wall-window-matcher 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +70 -0
- package/dist/cli.js.map +1 -0
- package/dist/findWindowWall.d.ts +154 -0
- package/dist/findWindowWall.d.ts.map +1 -0
- package/dist/findWindowWall.js +693 -0
- package/dist/findWindowWall.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/package.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# wall-window-matcher
|
|
2
|
+
|
|
3
|
+
> 建筑点云数据 —— 墙线段合并 + 窗户匹配 + drawWindow 属性注入工具
|
|
4
|
+
|
|
5
|
+
**纯算法、无 Node 文件系统依赖,可在浏览器 / Vite / Node 中直接使用。**
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
1. **墙线段共线合并**:将方向相近、距离很近的多条墙段合并成一条更长的线段
|
|
10
|
+
2. **窗户-墙体匹配**:基于坐标投影与距离判定,将 `category === 'window'` 的物体匹配到最近的墙上
|
|
11
|
+
3. **drawWindow 属性注入**:在匹配成功的墙线段上新增 `drawWindow[]` 数组,记录窗户信息(位置、宽高、离地高度)
|
|
12
|
+
4. **保留原始字段**:合并时保留原始线段的 `points`、`boxData`、`doorAndBeamData` 等所有字段
|
|
13
|
+
|
|
14
|
+
## 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install wall-window-matcher
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
或者直接从本地包引入(通过 vite alias 指向 `packages/wall-window-matcher/src/index.ts`)。
|
|
21
|
+
|
|
22
|
+
## 快速开始
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { processData, findWindowWalls, mergeCollinearSegments } from 'wall-window-matcher'
|
|
26
|
+
|
|
27
|
+
// 墙线段数组(从点云分割/墙体检测工具导出)
|
|
28
|
+
const wallSegments = [
|
|
29
|
+
{ start: { x: 0, y: 0, z: -1.3 }, end: { x: 5, y: 0, z: -1.3 }, length: 5, rooftopPz: 1.2, ... },
|
|
30
|
+
// ...
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
// 物体数组(其中 category === 'window' 的会被处理)
|
|
34
|
+
const objects = [
|
|
35
|
+
{ category: 'window', center: { x: 2.5, y: 0.1, z: 0.2 }, width: 1.5, height: 1.2, ... },
|
|
36
|
+
// ...
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
// 主入口:合并线段 + 匹配窗户 + 注入 drawWindow
|
|
40
|
+
const result = processData(wallSegments, objects)
|
|
41
|
+
console.log('合并后墙线段数:', result.segments.length)
|
|
42
|
+
console.log('匹配成功数:', result.matches.length)
|
|
43
|
+
console.log('sourceMap 对应关系:', result.sourceMap)
|
|
44
|
+
|
|
45
|
+
// segments 中的每条线段如果有匹配,会包含 drawWindow 数组
|
|
46
|
+
for (const seg of result.segments) {
|
|
47
|
+
if (seg.drawWindow && seg.drawWindow.length > 0) {
|
|
48
|
+
console.log('该墙有', seg.drawWindow.length, '个窗户')
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### `processData(wallSegments, windowObjects, options?)`
|
|
56
|
+
|
|
57
|
+
主函数,一次性完成合并 + 匹配 + 属性注入。
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
function processData(
|
|
61
|
+
wallSegments: WallSegment[],
|
|
62
|
+
windowObjects: WindowObject[],
|
|
63
|
+
options?: FindWallOptions & { printOnly?: boolean },
|
|
64
|
+
): {
|
|
65
|
+
segments: WallSegment[]; // 合并后的墙线段(含 drawWindow 注入)
|
|
66
|
+
matches: WallWindowMatch[]; // 匹配详情列表
|
|
67
|
+
sourceMap: number[][]; // 每条输出线段对应的原始线段索引
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `findWindowWalls(windowObjects, wallSegments, options?)`
|
|
72
|
+
|
|
73
|
+
只做窗户-墙体匹配,不合并。
|
|
74
|
+
|
|
75
|
+
### `mergeCollinearSegments(segments)`
|
|
76
|
+
|
|
77
|
+
只做墙线段共线合并,返回 `{ segments, sourceMap, debugRPZGroups }`。
|
|
78
|
+
|
|
79
|
+
### `computeLocalFloorZ(points)`
|
|
80
|
+
|
|
81
|
+
从一组点云计算局部地板 Z 值,用于判断窗户离地高度。
|
|
82
|
+
|
|
83
|
+
## 类型定义
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
interface WallSegment {
|
|
87
|
+
start: Point3D; // { x, y, z }
|
|
88
|
+
end: Point3D; // { x, y, z }
|
|
89
|
+
length: number;
|
|
90
|
+
direction: { x: number; y: number; z: number };
|
|
91
|
+
rooftopPz?: number; // 屋顶 Z
|
|
92
|
+
buildRosource?: string; // 来源标识
|
|
93
|
+
isRebuild?: boolean;
|
|
94
|
+
points?: Point3D[]; // 原始点云(可能非常大)
|
|
95
|
+
boxData?: any;
|
|
96
|
+
doorAndBeamData?: any[];
|
|
97
|
+
insetionArr?: any[];
|
|
98
|
+
drawWindow?: DrawWindow[]; // 新增字段:匹配到的窗户
|
|
99
|
+
[key: string]: any;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
interface WindowObject {
|
|
103
|
+
category: string; // 'window'
|
|
104
|
+
center?: Point3D;
|
|
105
|
+
width?: number;
|
|
106
|
+
height?: number;
|
|
107
|
+
[key: string]: any;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface DrawWindow {
|
|
111
|
+
p: Point3D;
|
|
112
|
+
width: number;
|
|
113
|
+
height: number;
|
|
114
|
+
groundClearance: number;
|
|
115
|
+
full: boolean;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Node 服务调用示例
|
|
120
|
+
|
|
121
|
+
在 Node 服务中读取本地 JSON,调用 npm 包处理后直接返回大 JSON 响应:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { processData } from 'wall-window-matcher'
|
|
125
|
+
import { readFileSync } from 'fs'
|
|
126
|
+
|
|
127
|
+
const walls = JSON.parse(readFileSync('PJ1781665824Wxs___finalLines.json', 'utf-8'))
|
|
128
|
+
const objects = JSON.parse(readFileSync('PJ1781665824Wxs_pcdPointsArr.json', 'utf-8'))
|
|
129
|
+
const windowObjects = objects.filter((o: any) => o.category === 'window')
|
|
130
|
+
|
|
131
|
+
const result = processData(walls, windowObjects)
|
|
132
|
+
console.log('合并后:', result.segments.length, '条')
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
或者通过 HTTP 接口:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
# 默认返回完整处理后的大 JSON(59 条线段,含 points 等原始字段)
|
|
139
|
+
curl -X POST http://localhost:3030/api/pcs/process \
|
|
140
|
+
-H "Content-Type: application/json" \
|
|
141
|
+
-d '{"pjName":"PJ1781665824Wxs"}'
|
|
142
|
+
|
|
143
|
+
# 只返回被修改过的线段(合并过的 / 新增了 drawWindow 的)
|
|
144
|
+
curl -X POST http://localhost:3030/api/pcs/process \
|
|
145
|
+
-H "Content-Type: application/json" \
|
|
146
|
+
-d '{"pjName":"PJ1781665824Wxs","outputChanged":true}'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## CLI(仅 Node 环境)
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# 直接运行(需要 tsx)
|
|
153
|
+
npx tsx packages/wall-window-matcher/src/cli.ts \
|
|
154
|
+
path/to/walls.json path/to/objects.json
|
|
155
|
+
|
|
156
|
+
# 或在 npm pack 后的 dist 中
|
|
157
|
+
npm run build # 编译 TS → dist/
|
|
158
|
+
node dist/cli.js walls.json objects.json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## 项目结构
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
packages/wall-window-matcher/
|
|
165
|
+
├── src/
|
|
166
|
+
│ ├── index.ts # 主入口(浏览器 / Node 通用,无 fs 依赖)
|
|
167
|
+
│ ├── findWindowWall.ts # 核心算法:合并 + 匹配 + 类型定义
|
|
168
|
+
│ └── cli.ts # Node CLI 工具(含 fs 依赖)
|
|
169
|
+
├── package.json
|
|
170
|
+
├── tsconfig.json
|
|
171
|
+
└── README.md
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## License
|
|
175
|
+
|
|
176
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { WallSegment, FindWallOptions } from './index';
|
|
3
|
+
export declare function processFiles(segmentsPath: string, objectsPath: string, outputPath?: string, options?: FindWallOptions & {
|
|
4
|
+
printOnly?: boolean;
|
|
5
|
+
}): WallSegment[];
|
|
6
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAMA,OAAO,EAAe,WAAW,EAAgB,eAAe,EAAE,MAAM,SAAS,CAAA;AAOjF,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAClD,WAAW,EAAE,CAgBf"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
// wall-window-matcher CLI —— 仅用于 Node 环境
|
|
4
|
+
// 用法:npx tsx src/cli.ts <walls.json> <objects.json> [output.json] [--print-only]
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.processFiles = processFiles;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const index_1 = require("./index");
|
|
43
|
+
function readJSON(filePath) {
|
|
44
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
45
|
+
return JSON.parse(raw);
|
|
46
|
+
}
|
|
47
|
+
function processFiles(segmentsPath, objectsPath, outputPath, options) {
|
|
48
|
+
console.log(`[wall-window-matcher] 读取墙线段: ${segmentsPath}`);
|
|
49
|
+
const wallSegments = readJSON(segmentsPath);
|
|
50
|
+
console.log(`[wall-window-matcher] 读取物体数据: ${objectsPath}`);
|
|
51
|
+
const objects = readJSON(objectsPath);
|
|
52
|
+
const windowObjects = objects.filter((o) => o.category === 'window');
|
|
53
|
+
console.log(`[wall-window-matcher] 墙线段: ${wallSegments.length} 条,窗户: ${windowObjects.length} 个`);
|
|
54
|
+
const { segments } = (0, index_1.processData)(wallSegments, windowObjects, options);
|
|
55
|
+
const outPath = outputPath || segmentsPath.replace(/\.json$/, '_enhanced.json');
|
|
56
|
+
fs.writeFileSync(outPath, JSON.stringify(segments, null, 2), 'utf-8');
|
|
57
|
+
console.log(`[wall-window-matcher] 输出: ${outPath}`);
|
|
58
|
+
return segments;
|
|
59
|
+
}
|
|
60
|
+
// ---- CLI 入口 ----
|
|
61
|
+
const args = process.argv.slice(2);
|
|
62
|
+
if (args.length >= 2) {
|
|
63
|
+
const segmentsFile = path.resolve(args[0]);
|
|
64
|
+
const objectsFile = path.resolve(args[1]);
|
|
65
|
+
const outputFile = args[2] && !args[2].startsWith('--') ? path.resolve(args[2]) : undefined;
|
|
66
|
+
const printOnly = args.includes('--print-only');
|
|
67
|
+
console.log('=== wall-window-matcher CLI ===');
|
|
68
|
+
processFiles(segmentsFile, objectsFile, outputFile, { printOnly });
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;AACA,yCAAyC;AACzC,iFAAiF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWjF,oCAqBC;AA9BD,uCAAwB;AACxB,2CAA4B;AAC5B,mCAAiF;AAEjF,SAAS,QAAQ,CAAI,QAAgB;IACnC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC9C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAA;AAC7B,CAAC;AAED,SAAgB,YAAY,CAC1B,YAAoB,EACpB,WAAmB,EACnB,UAAmB,EACnB,OAAmD;IAEnD,OAAO,CAAC,GAAG,CAAC,gCAAgC,YAAY,EAAE,CAAC,CAAA;IAC3D,MAAM,YAAY,GAAG,QAAQ,CAAgB,YAAY,CAAC,CAAA;IAC1D,OAAO,CAAC,GAAG,CAAC,iCAAiC,WAAW,EAAE,CAAC,CAAA;IAC3D,MAAM,OAAO,GAAG,QAAQ,CAAiB,WAAW,CAAC,CAAA;IAErD,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAA;IACzE,OAAO,CAAC,GAAG,CAAC,8BAA8B,YAAY,CAAC,MAAM,UAAU,aAAa,CAAC,MAAM,IAAI,CAAC,CAAA;IAEhG,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAA,mBAAW,EAAC,YAAY,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IAEtE,MAAM,OAAO,GAAG,UAAU,IAAI,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAA;IAC/E,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAA;IACrE,OAAO,CAAC,GAAG,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAA;IAEnD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,mBAAmB;AACnB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAClC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;IACrB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;IAE/C,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;IAC9C,YAAY,CAAC,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;AACpE,CAAC"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 找到每个窗户物体所对应的墙体线段
|
|
3
|
+
*
|
|
4
|
+
* 核心思路:
|
|
5
|
+
* 1. 解析窗户四边形的4个角点,计算窗户中心、长边长度、长边方向
|
|
6
|
+
* 2. 对每条墙线段做粗筛(长度 >= 窗户长边 × 1.0,即墙至少与窗等长)
|
|
7
|
+
* 3. 精筛:计算窗户中心到墙线的垂直距离,垂足必须在线段范围内
|
|
8
|
+
* 4. 方向约束:墙线方向应与窗户长边方向平行(夹角 < 45°)
|
|
9
|
+
* 5. 按距离升序取最优匹配
|
|
10
|
+
*/
|
|
11
|
+
export interface Point3D {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
z: number;
|
|
15
|
+
}
|
|
16
|
+
/** 窗户在线段上的标记(用于 drawWindow 新字段)*/
|
|
17
|
+
export interface DrawWindow {
|
|
18
|
+
p: Point3D;
|
|
19
|
+
width: number;
|
|
20
|
+
full: boolean;
|
|
21
|
+
height: number;
|
|
22
|
+
groundClearance: number;
|
|
23
|
+
}
|
|
24
|
+
/** 某个不一致 rooftopPz 组中的单条线段调试信息 */
|
|
25
|
+
export interface RPZDebugSegment {
|
|
26
|
+
idx: number;
|
|
27
|
+
start: Point3D;
|
|
28
|
+
end: Point3D;
|
|
29
|
+
length: number;
|
|
30
|
+
rooftopPz: number;
|
|
31
|
+
}
|
|
32
|
+
/** 共线但 rooftopPz 不一致的线段组 */
|
|
33
|
+
export interface RPZDebugGroup {
|
|
34
|
+
values: string[];
|
|
35
|
+
segments: RPZDebugSegment[];
|
|
36
|
+
}
|
|
37
|
+
export interface WallSegment {
|
|
38
|
+
start: Point3D;
|
|
39
|
+
end: Point3D;
|
|
40
|
+
length: number;
|
|
41
|
+
direction: Point3D;
|
|
42
|
+
points: Point3D[];
|
|
43
|
+
originalPoints?: Point3D[];
|
|
44
|
+
isRebuild?: boolean;
|
|
45
|
+
rooftopPz?: number;
|
|
46
|
+
buildRosource?: string;
|
|
47
|
+
doorAndBeamData?: unknown[];
|
|
48
|
+
insetionArr?: unknown[];
|
|
49
|
+
boxData?: {
|
|
50
|
+
isBox3: boolean;
|
|
51
|
+
min: Point3D;
|
|
52
|
+
max: Point3D;
|
|
53
|
+
};
|
|
54
|
+
drawWindow?: DrawWindow[];
|
|
55
|
+
}
|
|
56
|
+
export interface WindowObject {
|
|
57
|
+
name: string;
|
|
58
|
+
category: string;
|
|
59
|
+
center: Point3D;
|
|
60
|
+
box: {
|
|
61
|
+
min: Point3D;
|
|
62
|
+
max: Point3D;
|
|
63
|
+
};
|
|
64
|
+
coordinatesByArea: {
|
|
65
|
+
coordinates: Point3D[];
|
|
66
|
+
heightData?: {
|
|
67
|
+
minZ: number;
|
|
68
|
+
maxZ: number;
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
export interface WindowWallMatch {
|
|
74
|
+
/** 窗户名称 */
|
|
75
|
+
windowName: string;
|
|
76
|
+
/** 窗户分类 */
|
|
77
|
+
windowCategory: string;
|
|
78
|
+
/** 窗户中心 (世界坐标) */
|
|
79
|
+
windowCenter: Point3D;
|
|
80
|
+
/** 匹配到的墙线段 */
|
|
81
|
+
wallSegment: WallSegment;
|
|
82
|
+
/** 窗户中心到墙线的垂直距离 (m) */
|
|
83
|
+
distance: number;
|
|
84
|
+
/** 墙线长度 / 窗户长边 */
|
|
85
|
+
wallLengthRatio: number;
|
|
86
|
+
/** drawWindow 数据(窗户在墙上的位置/尺寸)*/
|
|
87
|
+
drawWindow?: DrawWindow;
|
|
88
|
+
}
|
|
89
|
+
export interface FindWallOptions {
|
|
90
|
+
/**
|
|
91
|
+
* 墙线长度至少为窗户长边的倍数,默认 1.0
|
|
92
|
+
* 用于排除过短的杂线,设为 1.0 表示墙至少与窗等长
|
|
93
|
+
*/
|
|
94
|
+
minLengthRatio?: number;
|
|
95
|
+
/**
|
|
96
|
+
* 窗户中心到墙线的最大垂直距离 (m),默认 0.5
|
|
97
|
+
* 超出此距离认为不在此墙上
|
|
98
|
+
*/
|
|
99
|
+
maxDistance?: number;
|
|
100
|
+
/**
|
|
101
|
+
* 墙线与窗户长边方向的最大夹角 (°),默认 45
|
|
102
|
+
* 墙应大致平行于窗户的水平方向
|
|
103
|
+
*/
|
|
104
|
+
angleThreshold?: number;
|
|
105
|
+
/**
|
|
106
|
+
* 垂足在线段上的容许范围,默认 [-0.1, 1.1]
|
|
107
|
+
* 略放宽边界以包容线段提取误差
|
|
108
|
+
*/
|
|
109
|
+
projectionMargin?: number;
|
|
110
|
+
/**
|
|
111
|
+
* 是否仅打印核对信息而不写入 drawWindow 字段,默认 true(仅打印)。
|
|
112
|
+
* 核对无误后设为 false,会将 drawWindow 写入墙线段对象。
|
|
113
|
+
*/
|
|
114
|
+
printOnly?: boolean;
|
|
115
|
+
}
|
|
116
|
+
/** 两点在 XY 平面上的距离 */
|
|
117
|
+
export declare function dist2D(a: Point3D, b: Point3D): number;
|
|
118
|
+
/** 计算四边形最长边及其方向 (XY 平面) */
|
|
119
|
+
export declare function analyzeQuad(corners: Point3D[]): {
|
|
120
|
+
longSide: number;
|
|
121
|
+
dirX: number;
|
|
122
|
+
dirY: number;
|
|
123
|
+
};
|
|
124
|
+
/** 从墙线段集合中估算地面高度 (Z 轴中位数) */
|
|
125
|
+
/** 基于窗户附近墙线段计算局部地面 Z(半径 3m) */
|
|
126
|
+
export declare function computeLocalFloorZ(walls: WallSegment[], cx: number, cy: number): number;
|
|
127
|
+
/**
|
|
128
|
+
* 计算点 C 到线段 AB 的垂直距离与投影参数 t
|
|
129
|
+
* 返回 { dist, t },t ∈ [0,1] 表示垂足在线段上
|
|
130
|
+
*/
|
|
131
|
+
export declare function pointToSegmentDist(cx: number, cy: number, ax: number, ay: number, bx: number, by: number): {
|
|
132
|
+
dist: number;
|
|
133
|
+
t: number;
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* 合并共线且相邻的墙线段
|
|
137
|
+
*
|
|
138
|
+
* 思路:
|
|
139
|
+
* 1. 将每条线段的方向无向化到 [0°, 180°),按角度分桶(±5° 容差)
|
|
140
|
+
* 2. 每个桶内计算线段到参考线的垂直距离,进一步按共线关系分组
|
|
141
|
+
* 3. 每组内投影到方向轴上,合并重叠/相邻的区间
|
|
142
|
+
*
|
|
143
|
+
* @param segments 原始墙线段列表
|
|
144
|
+
* @param angleTol 角度容差 (°),默认 5
|
|
145
|
+
* @param gapTol 间隙容差 (m),默认 0.05,小于此值的间隙视为相连
|
|
146
|
+
* @returns 合并后的墙线段列表
|
|
147
|
+
*/
|
|
148
|
+
export declare function mergeCollinearSegments(segments: WallSegment[], angleTol?: number, gapTol?: number): {
|
|
149
|
+
segments: WallSegment[];
|
|
150
|
+
sourceMap: number[][];
|
|
151
|
+
debugRPZGroups?: RPZDebugGroup[];
|
|
152
|
+
};
|
|
153
|
+
export declare function findWindowWalls(windowObjs: WindowObject[], wallSegments: WallSegment[], options?: FindWallOptions): WindowWallMatch[];
|
|
154
|
+
//# sourceMappingURL=findWindowWall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findWindowWall.d.ts","sourceRoot":"","sources":["../src/findWindowWall.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,CAAC,EAAE,OAAO,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,4BAA4B;AAC5B,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,EAAE,OAAO,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,OAAO,CAAA;IAClB,MAAM,EAAE,OAAO,EAAE,CAAA;IACjB,cAAc,CAAC,EAAE,OAAO,EAAE,CAAA;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,OAAO,EAAE,CAAA;IAC3B,WAAW,CAAC,EAAE,OAAO,EAAE,CAAA;IACvB,OAAO,CAAC,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAA;IACzD,UAAU,CAAC,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE;QAAE,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAA;IACnC,iBAAiB,EAAE;QACjB,WAAW,EAAE,OAAO,EAAE,CAAA;QACtB,UAAU,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAC5C,CAAA;IACD,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW;IACX,cAAc,EAAE,MAAM,CAAA;IACtB,kBAAkB;IAClB,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc;IACd,WAAW,EAAE,WAAW,CAAA;IACxB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,kBAAkB;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,gCAAgC;IAChC,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAID,oBAAoB;AACpB,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,MAAM,CAIrD;AAED,2BAA2B;AAC3B,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAmBhG;AAED,6BAA6B;AAC7B,+BAA+B;AAC/B,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAqBvF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EACtB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAe7B;AA2HD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,WAAW,EAAE,EACvB,QAAQ,SAAI,EAAE,MAAM,SAAO,GAAI;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,aAAa,EAAE,CAAA;CAAE,CAwHvC;AAE9E,wBAAgB,eAAe,CAC7B,UAAU,EAAE,YAAY,EAAE,EAC1B,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,CAAC,EAAE,eAAe,GACxB,eAAe,EAAE,CAsUnB"}
|
|
@@ -0,0 +1,693 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 找到每个窗户物体所对应的墙体线段
|
|
4
|
+
*
|
|
5
|
+
* 核心思路:
|
|
6
|
+
* 1. 解析窗户四边形的4个角点,计算窗户中心、长边长度、长边方向
|
|
7
|
+
* 2. 对每条墙线段做粗筛(长度 >= 窗户长边 × 1.0,即墙至少与窗等长)
|
|
8
|
+
* 3. 精筛:计算窗户中心到墙线的垂直距离,垂足必须在线段范围内
|
|
9
|
+
* 4. 方向约束:墙线方向应与窗户长边方向平行(夹角 < 45°)
|
|
10
|
+
* 5. 按距离升序取最优匹配
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.dist2D = dist2D;
|
|
14
|
+
exports.analyzeQuad = analyzeQuad;
|
|
15
|
+
exports.computeLocalFloorZ = computeLocalFloorZ;
|
|
16
|
+
exports.pointToSegmentDist = pointToSegmentDist;
|
|
17
|
+
exports.mergeCollinearSegments = mergeCollinearSegments;
|
|
18
|
+
exports.findWindowWalls = findWindowWalls;
|
|
19
|
+
// ---- 工具函数 ----
|
|
20
|
+
/** 两点在 XY 平面上的距离 */
|
|
21
|
+
function dist2D(a, b) {
|
|
22
|
+
const dx = a.x - b.x;
|
|
23
|
+
const dy = a.y - b.y;
|
|
24
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
25
|
+
}
|
|
26
|
+
/** 计算四边形最长边及其方向 (XY 平面) */
|
|
27
|
+
function analyzeQuad(corners) {
|
|
28
|
+
let maxLen = 0;
|
|
29
|
+
let dirX = 0;
|
|
30
|
+
let dirY = 0;
|
|
31
|
+
for (let i = 0; i < 4; i++) {
|
|
32
|
+
const a = corners[i];
|
|
33
|
+
const b = corners[(i + 1) % 4];
|
|
34
|
+
const dx = b.x - a.x;
|
|
35
|
+
const dy = b.y - a.y;
|
|
36
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
37
|
+
if (len > maxLen) {
|
|
38
|
+
maxLen = len;
|
|
39
|
+
dirX = dx / len;
|
|
40
|
+
dirY = dy / len;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { longSide: maxLen, dirX, dirY };
|
|
44
|
+
}
|
|
45
|
+
/** 从墙线段集合中估算地面高度 (Z 轴中位数) */
|
|
46
|
+
/** 基于窗户附近墙线段计算局部地面 Z(半径 3m) */
|
|
47
|
+
function computeLocalFloorZ(walls, cx, cy) {
|
|
48
|
+
const radius = 3;
|
|
49
|
+
const zs = [];
|
|
50
|
+
for (const w of walls) {
|
|
51
|
+
const mx = (w.start.x + w.end.x) / 2;
|
|
52
|
+
const my = (w.start.y + w.end.y) / 2;
|
|
53
|
+
const dx = mx - cx, dy = my - cy;
|
|
54
|
+
if (dx * dx + dy * dy <= radius * radius) {
|
|
55
|
+
zs.push(w.start.z, w.end.z);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (zs.length === 0) {
|
|
59
|
+
// 附近无墙 → 回退到全局中位数
|
|
60
|
+
const allZ = [];
|
|
61
|
+
for (const w of walls)
|
|
62
|
+
allZ.push(w.start.z, w.end.z);
|
|
63
|
+
if (!allZ.length)
|
|
64
|
+
return -Infinity;
|
|
65
|
+
allZ.sort((a, b) => a - b);
|
|
66
|
+
return allZ[Math.floor(allZ.length / 2)];
|
|
67
|
+
}
|
|
68
|
+
zs.sort((a, b) => a - b);
|
|
69
|
+
return zs[Math.floor(zs.length / 2)];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 计算点 C 到线段 AB 的垂直距离与投影参数 t
|
|
73
|
+
* 返回 { dist, t },t ∈ [0,1] 表示垂足在线段上
|
|
74
|
+
*/
|
|
75
|
+
function pointToSegmentDist(cx, cy, ax, ay, bx, by) {
|
|
76
|
+
const vx = bx - ax;
|
|
77
|
+
const vy = by - ay;
|
|
78
|
+
const len2 = vx * vx + vy * vy;
|
|
79
|
+
if (len2 < 1e-12) {
|
|
80
|
+
// 退化为点
|
|
81
|
+
return { dist: Math.sqrt((cx - ax) ** 2 + (cy - ay) ** 2), t: 0 };
|
|
82
|
+
}
|
|
83
|
+
const wx = cx - ax;
|
|
84
|
+
const wy = cy - ay;
|
|
85
|
+
const t = (wx * vx + wy * vy) / len2;
|
|
86
|
+
const projX = ax + t * vx;
|
|
87
|
+
const projY = ay + t * vy;
|
|
88
|
+
const dist = Math.sqrt((cx - projX) ** 2 + (cy - projY) ** 2);
|
|
89
|
+
return { dist, t };
|
|
90
|
+
}
|
|
91
|
+
/** 信号1:计算墙线段两端附近连接的其他墙数量 */
|
|
92
|
+
function scoreEndpointConnectivity(wall, allWalls, radius = 0.15) {
|
|
93
|
+
let left = 0;
|
|
94
|
+
let right = 0;
|
|
95
|
+
for (const other of allWalls) {
|
|
96
|
+
if (other === wall)
|
|
97
|
+
continue;
|
|
98
|
+
if (dist2D(wall.start, other.start) <= radius || dist2D(wall.start, other.end) <= radius)
|
|
99
|
+
left++;
|
|
100
|
+
if (dist2D(wall.end, other.start) <= radius || dist2D(wall.end, other.end) <= radius)
|
|
101
|
+
right++;
|
|
102
|
+
}
|
|
103
|
+
// 两端都有连接 = 5 分,一端有连接 = 2 分,两端自由 = 0 分
|
|
104
|
+
let score = 0;
|
|
105
|
+
if (left >= 1 && right >= 1)
|
|
106
|
+
score = 5;
|
|
107
|
+
else if (left >= 1 || right >= 1)
|
|
108
|
+
score = 2;
|
|
109
|
+
return { left, right, score };
|
|
110
|
+
}
|
|
111
|
+
/** 信号2:计算窗口5个检查点到墙线距离的方差(离散度越低越好) */
|
|
112
|
+
function scoreDistanceVariance(wall, checkPoints) {
|
|
113
|
+
const ds = [];
|
|
114
|
+
const { start, end } = wall;
|
|
115
|
+
for (const pt of checkPoints) {
|
|
116
|
+
const { dist } = pointToSegmentDist(pt.x, pt.y, start.x, start.y, end.x, end.y);
|
|
117
|
+
ds.push(dist);
|
|
118
|
+
}
|
|
119
|
+
const mean = ds.reduce((s, v) => s + v, 0) / ds.length;
|
|
120
|
+
const variance = ds.reduce((s, v) => s + (v - mean) ** 2, 0) / ds.length;
|
|
121
|
+
if (variance < 0.01)
|
|
122
|
+
return 3;
|
|
123
|
+
if (variance < 0.05)
|
|
124
|
+
return 2;
|
|
125
|
+
if (variance < 0.10)
|
|
126
|
+
return 1;
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
/** 信号3:检查墙两端连接的垂直墙是否都向同一侧延伸 */
|
|
130
|
+
function scoreSameSidePerpendicular(wall, allWalls, connectRadius = 0.15) {
|
|
131
|
+
const dx = wall.end.x - wall.start.x;
|
|
132
|
+
const dy = wall.end.y - wall.start.y;
|
|
133
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
134
|
+
if (len < 1e-12)
|
|
135
|
+
return 0;
|
|
136
|
+
// 法线方向
|
|
137
|
+
const nx = -dy / len;
|
|
138
|
+
const ny = dx / len;
|
|
139
|
+
// 分别收集两端连接的垂直墙的"延伸侧"
|
|
140
|
+
const sidesByEnd = [[], []];
|
|
141
|
+
for (let ei = 0; ei < 2; ei++) {
|
|
142
|
+
const ep = ei === 0 ? wall.start : wall.end;
|
|
143
|
+
for (const other of allWalls) {
|
|
144
|
+
if (other === wall)
|
|
145
|
+
continue;
|
|
146
|
+
// 是否连接在此端点附近
|
|
147
|
+
const dStart = dist2D(ep, other.start);
|
|
148
|
+
const dEnd = dist2D(ep, other.end);
|
|
149
|
+
let farEnd = null;
|
|
150
|
+
if (dStart <= connectRadius)
|
|
151
|
+
farEnd = other.end;
|
|
152
|
+
else if (dEnd <= connectRadius)
|
|
153
|
+
farEnd = other.start;
|
|
154
|
+
if (!farEnd)
|
|
155
|
+
continue;
|
|
156
|
+
// 是否大致垂直于本墙(70°~110°)
|
|
157
|
+
const odx = other.end.x - other.start.x;
|
|
158
|
+
const ody = other.end.y - other.start.y;
|
|
159
|
+
const olen = Math.sqrt(odx * odx + ody * ody);
|
|
160
|
+
if (olen < 1e-12)
|
|
161
|
+
continue;
|
|
162
|
+
const dot = Math.abs(dx * odx + dy * ody) / (len * olen);
|
|
163
|
+
// 垂直墙的 dot 接近 0(余弦值 < cos70° ≈ 0.342)
|
|
164
|
+
if (dot >= 0.342)
|
|
165
|
+
continue;
|
|
166
|
+
// farEnd 在法线方向的哪一侧
|
|
167
|
+
const side = (farEnd.x - ep.x) * nx + (farEnd.y - ep.y) * ny;
|
|
168
|
+
sidesByEnd[ei].push(side > 0 ? 1 : -1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// 两端都必须有垂直墙连接,且所有垂直墙的延伸方向一致
|
|
172
|
+
if (sidesByEnd[0].length === 0 || sidesByEnd[1].length === 0)
|
|
173
|
+
return 0;
|
|
174
|
+
const allSides = [...sidesByEnd[0], ...sidesByEnd[1]];
|
|
175
|
+
const allSame = allSides.every(s => s === allSides[0]);
|
|
176
|
+
return allSame ? 2 : 1;
|
|
177
|
+
}
|
|
178
|
+
/** 综合评分 */
|
|
179
|
+
function computeWallScore(wall, checkPoints, allWalls) {
|
|
180
|
+
const conn = scoreEndpointConnectivity(wall, allWalls);
|
|
181
|
+
const variance = scoreDistanceVariance(wall, checkPoints);
|
|
182
|
+
const sameSide = scoreSameSidePerpendicular(wall, allWalls);
|
|
183
|
+
const score = conn.score * 3 + variance * 2 + sameSide * 2;
|
|
184
|
+
return { score, details: { conn: conn.score, variance, sameSide } };
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 合并共线且相邻的墙线段
|
|
188
|
+
*
|
|
189
|
+
* 思路:
|
|
190
|
+
* 1. 将每条线段的方向无向化到 [0°, 180°),按角度分桶(±5° 容差)
|
|
191
|
+
* 2. 每个桶内计算线段到参考线的垂直距离,进一步按共线关系分组
|
|
192
|
+
* 3. 每组内投影到方向轴上,合并重叠/相邻的区间
|
|
193
|
+
*
|
|
194
|
+
* @param segments 原始墙线段列表
|
|
195
|
+
* @param angleTol 角度容差 (°),默认 5
|
|
196
|
+
* @param gapTol 间隙容差 (m),默认 0.05,小于此值的间隙视为相连
|
|
197
|
+
* @returns 合并后的墙线段列表
|
|
198
|
+
*/
|
|
199
|
+
function mergeCollinearSegments(segments, angleTol = 5, gapTol = 0.05) {
|
|
200
|
+
if (segments.length <= 1)
|
|
201
|
+
return { segments, sourceMap: segments.map((_, i) => [i]) };
|
|
202
|
+
const items = segments.map((seg, idx) => {
|
|
203
|
+
const dx = seg.end.x - seg.start.x, dy = seg.end.y - seg.start.y;
|
|
204
|
+
let angle = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
205
|
+
if (angle < 0)
|
|
206
|
+
angle += 180;
|
|
207
|
+
return { seg, angle, idx };
|
|
208
|
+
});
|
|
209
|
+
items.sort((a, b) => a.angle - b.angle);
|
|
210
|
+
const buckets = [];
|
|
211
|
+
for (const item of items) {
|
|
212
|
+
let placed = false;
|
|
213
|
+
for (const bucket of buckets) {
|
|
214
|
+
const d = Math.abs(item.angle - bucket[0].angle);
|
|
215
|
+
if (Math.min(d, 180 - d) <= angleTol) {
|
|
216
|
+
bucket.push(item);
|
|
217
|
+
placed = true;
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (!placed)
|
|
222
|
+
buckets.push([item]);
|
|
223
|
+
}
|
|
224
|
+
const mergedSegs = [];
|
|
225
|
+
const mergedSources = [];
|
|
226
|
+
const debugRPZGroups = [];
|
|
227
|
+
for (const bucket of buckets) {
|
|
228
|
+
let ref = bucket[0].seg, refMaxLen = 0;
|
|
229
|
+
for (const item of bucket)
|
|
230
|
+
if (item.seg.length > refMaxLen) {
|
|
231
|
+
refMaxLen = item.seg.length;
|
|
232
|
+
ref = item.seg;
|
|
233
|
+
}
|
|
234
|
+
const rDx = ref.end.x - ref.start.x, rDy = ref.end.y - ref.start.y;
|
|
235
|
+
const rLen = Math.sqrt(rDx * rDx + rDy * rDy);
|
|
236
|
+
if (rLen < 1e-12)
|
|
237
|
+
continue;
|
|
238
|
+
const nx = -rDy / rLen, ny = rDx / rLen;
|
|
239
|
+
const withOffset = bucket.map((item) => {
|
|
240
|
+
const dx = item.seg.start.x - ref.start.x, dy = item.seg.start.y - ref.start.y;
|
|
241
|
+
return { seg: item.seg, offset: Math.abs(dx * nx + dy * ny), idx: item.idx };
|
|
242
|
+
});
|
|
243
|
+
withOffset.sort((a, b) => a.offset - b.offset);
|
|
244
|
+
const collinearGroups = [];
|
|
245
|
+
for (const item of withOffset) {
|
|
246
|
+
let placed = false;
|
|
247
|
+
for (const g of collinearGroups) {
|
|
248
|
+
if (Math.abs(item.offset - g[0].offset) <= 0.05) {
|
|
249
|
+
g.push(item);
|
|
250
|
+
placed = true;
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (!placed)
|
|
255
|
+
collinearGroups.push([item]);
|
|
256
|
+
}
|
|
257
|
+
for (const group of collinearGroups) {
|
|
258
|
+
let gref = group[0].seg, grefLen = 0;
|
|
259
|
+
for (const gi of group)
|
|
260
|
+
if (gi.seg.length > grefLen) {
|
|
261
|
+
grefLen = gi.seg.length;
|
|
262
|
+
gref = gi.seg;
|
|
263
|
+
}
|
|
264
|
+
const gDx = gref.end.x - gref.start.x, gDy = gref.end.y - gref.start.y;
|
|
265
|
+
const gLen = Math.sqrt(gDx * gDx + gDy * gDy);
|
|
266
|
+
if (gLen < 1e-12)
|
|
267
|
+
continue;
|
|
268
|
+
const dirX = gDx / gLen, dirY = gDy / gLen;
|
|
269
|
+
// --- rooftopPz: 取组内最大值合并 ---
|
|
270
|
+
const rpzVals = group.map(gi => gi.seg.rooftopPz ?? 0);
|
|
271
|
+
const maxRpz = Math.max(...rpzVals);
|
|
272
|
+
const rpzSet = [...new Set(rpzVals.map(v => v.toFixed(3)))];
|
|
273
|
+
if (rpzSet.length > 1) {
|
|
274
|
+
console.warn("[merge] inconsistent rooftopPz:", rpzSet.join("/"), "max=", maxRpz.toFixed(3), "count=", group.length);
|
|
275
|
+
const rpzSegs = group.map(gi => ({ idx: gi.idx, start: { x: gi.seg.start.x, y: gi.seg.start.y, z: gi.seg.start.z }, end: { x: gi.seg.end.x, y: gi.seg.end.y, z: gi.seg.end.z }, length: gi.seg.length, rooftopPz: gi.seg.rooftopPz ?? 0 }));
|
|
276
|
+
debugRPZGroups.push({ values: [...rpzSet], segments: rpzSegs });
|
|
277
|
+
console.log("[debugRPZ] " + JSON.stringify(rpzSegs));
|
|
278
|
+
}
|
|
279
|
+
const rooftopPz = maxRpz;
|
|
280
|
+
// --- buildRosource source check ---
|
|
281
|
+
const srcSet = [...new Set(group.map(gi => String(gi.seg.buildRosource)))];
|
|
282
|
+
if (srcSet.length > 1 && group.length > 1)
|
|
283
|
+
console.warn("[merge] buildRosource src:", srcSet.join("/"));
|
|
284
|
+
const buildRosource = gref.buildRosource;
|
|
285
|
+
// --- collect intervals (geometry only) ---
|
|
286
|
+
const intervals = [];
|
|
287
|
+
const srcIdxs = [];
|
|
288
|
+
for (const gi of group) {
|
|
289
|
+
const s = gi.seg;
|
|
290
|
+
const t1 = (s.start.x - gref.start.x) * dirX + (s.start.y - gref.start.y) * dirY;
|
|
291
|
+
const t2 = (s.end.x - gref.start.x) * dirX + (s.end.y - gref.start.y) * dirY;
|
|
292
|
+
intervals.push([Math.min(t1, t2), Math.max(t1, t2)]);
|
|
293
|
+
srcIdxs.push(gi.idx);
|
|
294
|
+
}
|
|
295
|
+
intervals.sort((a, b) => a[0] - b[0]);
|
|
296
|
+
const mergedIntervals = [];
|
|
297
|
+
for (const [l, r] of intervals) {
|
|
298
|
+
if (mergedIntervals.length === 0) {
|
|
299
|
+
mergedIntervals.push([l, r]);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const last = mergedIntervals[mergedIntervals.length - 1];
|
|
303
|
+
if (l <= last[1] + gapTol)
|
|
304
|
+
last[1] = Math.max(last[1], r);
|
|
305
|
+
else
|
|
306
|
+
mergedIntervals.push([l, r]);
|
|
307
|
+
}
|
|
308
|
+
for (const [l, r] of mergedIntervals) {
|
|
309
|
+
const len = r - l;
|
|
310
|
+
if (len < 0.01)
|
|
311
|
+
continue;
|
|
312
|
+
// 从 gref 复制所有现有字段,然后只覆盖会变化的字段(几何、来源、状态等)
|
|
313
|
+
const newStart = { x: gref.start.x + l * dirX, y: gref.start.y + l * dirY, z: gref.start.z };
|
|
314
|
+
const newEnd = { x: gref.start.x + r * dirX, y: gref.start.y + r * dirY, z: gref.start.z };
|
|
315
|
+
// 把 gref 的所有字段复制过来,再覆盖会变化的字段
|
|
316
|
+
const base = { ...gref };
|
|
317
|
+
base.start = newStart;
|
|
318
|
+
base.end = newEnd;
|
|
319
|
+
base.length = len;
|
|
320
|
+
base.direction = { x: dirX, y: dirY, z: 0 };
|
|
321
|
+
base.rooftopPz = rooftopPz;
|
|
322
|
+
base.buildRosource = buildRosource;
|
|
323
|
+
base.isRebuild = false;
|
|
324
|
+
// points / boxData / originalPoints / doorAndBeamData / insetionArr 保留 gref 的原值
|
|
325
|
+
// 如果 doorAndBeamData 或 insetionArr 在 gref 中不存在,则设为 []
|
|
326
|
+
if (!base.doorAndBeamData)
|
|
327
|
+
base.doorAndBeamData = [];
|
|
328
|
+
if (!base.insetionArr)
|
|
329
|
+
base.insetionArr = [];
|
|
330
|
+
mergedSegs.push(base);
|
|
331
|
+
mergedSources.push(srcIdxs);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// --- Step 5: endpoint join ---
|
|
336
|
+
let changed = true;
|
|
337
|
+
while (changed) {
|
|
338
|
+
changed = false;
|
|
339
|
+
for (let i = 0; i < mergedSegs.length; i++) {
|
|
340
|
+
for (let j = i + 1; j < mergedSegs.length; j++) {
|
|
341
|
+
const a = mergedSegs[i], b = mergedSegs[j];
|
|
342
|
+
if (a.rooftopPz !== undefined && b.rooftopPz !== undefined)
|
|
343
|
+
if (Math.abs(a.rooftopPz - b.rooftopPz) > 0.05)
|
|
344
|
+
continue;
|
|
345
|
+
const s1 = Math.abs(a.end.x - b.start.x) < 0.001 && Math.abs(a.end.y - b.start.y) < 0.001;
|
|
346
|
+
const s2 = Math.abs(a.start.x - b.end.x) < 0.001 && Math.abs(a.start.y - b.end.y) < 0.001;
|
|
347
|
+
const s3 = Math.abs(a.end.x - b.end.x) < 0.001 && Math.abs(a.end.y - b.end.y) < 0.001;
|
|
348
|
+
const s4 = Math.abs(a.start.x - b.start.x) < 0.001 && Math.abs(a.start.y - b.start.y) < 0.001;
|
|
349
|
+
if (!(s1 || s2 || s3 || s4))
|
|
350
|
+
continue;
|
|
351
|
+
const dot = a.direction.x * b.direction.x + a.direction.y * b.direction.y;
|
|
352
|
+
if (dot < 0.98)
|
|
353
|
+
continue;
|
|
354
|
+
let ns = a.start, ne = a.end;
|
|
355
|
+
if (s1)
|
|
356
|
+
ne = b.end;
|
|
357
|
+
else if (s2)
|
|
358
|
+
ns = b.start;
|
|
359
|
+
else if (s3)
|
|
360
|
+
ne = b.start;
|
|
361
|
+
else if (s4)
|
|
362
|
+
ns = b.end;
|
|
363
|
+
const nl = Math.hypot(ne.x - ns.x, ne.y - ns.y);
|
|
364
|
+
// 从 a 复制所有字段,只覆盖会变化的字段
|
|
365
|
+
const mergedBase = { ...a };
|
|
366
|
+
mergedBase.start = ns;
|
|
367
|
+
mergedBase.end = ne;
|
|
368
|
+
mergedBase.length = nl;
|
|
369
|
+
mergedBase.direction = { x: (ne.x - ns.x) / nl, y: (ne.y - ns.y) / nl, z: 0 };
|
|
370
|
+
mergedBase.rooftopPz = a.rooftopPz !== undefined ? a.rooftopPz : b.rooftopPz;
|
|
371
|
+
mergedBase.buildRosource = a.buildRosource || b.buildRosource;
|
|
372
|
+
mergedBase.isRebuild = false;
|
|
373
|
+
// 保留 a 的 points / boxData / originalPoints / doorAndBeamData / insetionArr
|
|
374
|
+
if (!mergedBase.doorAndBeamData)
|
|
375
|
+
mergedBase.doorAndBeamData = [];
|
|
376
|
+
if (!mergedBase.insetionArr)
|
|
377
|
+
mergedBase.insetionArr = [];
|
|
378
|
+
mergedSegs[i] = mergedBase;
|
|
379
|
+
mergedSources[i] = [...new Set([...mergedSources[i], ...mergedSources[j]])];
|
|
380
|
+
mergedSegs.splice(j, 1);
|
|
381
|
+
mergedSources.splice(j, 1);
|
|
382
|
+
j--;
|
|
383
|
+
changed = true;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return { segments: mergedSegs, sourceMap: mergedSources, debugRPZGroups };
|
|
388
|
+
}
|
|
389
|
+
function findWindowWalls(windowObjs, wallSegments, options) {
|
|
390
|
+
const opts = {
|
|
391
|
+
minLengthRatio: 0.95,
|
|
392
|
+
maxDistance: 0.5,
|
|
393
|
+
angleThreshold: 45,
|
|
394
|
+
projectionMargin: 0.1,
|
|
395
|
+
printOnly: true,
|
|
396
|
+
...options,
|
|
397
|
+
};
|
|
398
|
+
const results = [];
|
|
399
|
+
// ---- Step 0: 共线合并墙线段 ----
|
|
400
|
+
const { segments: mergedSegments, sourceMap: mergeSourceMap } = mergeCollinearSegments(wallSegments);
|
|
401
|
+
console.log(`[findWindowWall] 墙线段共线合并: ${wallSegments.length} → ${mergedSegments.length} 条`);
|
|
402
|
+
// 合并线段 + 原始线段共同作为候选
|
|
403
|
+
// - 合并线段:覆盖多段小线段拼成的长墙场景
|
|
404
|
+
// - 原始线段:当合并引入微小偏差时,原始线段保底
|
|
405
|
+
const candidateSegments = [...mergedSegments, ...wallSegments];
|
|
406
|
+
for (const win of windowObjs) {
|
|
407
|
+
// ---- Step 0: 解析窗户四边形 ----
|
|
408
|
+
const coords = win.coordinatesByArea?.coordinates;
|
|
409
|
+
if (!coords || coords.length < 4) {
|
|
410
|
+
console.warn(`[findWindowWall] ${win.name} 缺少 coordinatesByArea.coordinates,跳过`);
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
const corners = coords.slice(0, 4);
|
|
414
|
+
const centerX = corners.reduce((s, p) => s + p.x, 0) / 4;
|
|
415
|
+
const centerY = corners.reduce((s, p) => s + p.y, 0) / 4;
|
|
416
|
+
const { longSide: winLong, dirX: winDirX, dirY: winDirY } = analyzeQuad(corners);
|
|
417
|
+
if (winLong < 0.01) {
|
|
418
|
+
console.warn(`[findWindowWall] ${win.name} 四边形边长过短 (${winLong.toFixed(3)}),跳过`);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
// ---- 高度校验:基于附近墙段的局部地面 Z ----
|
|
422
|
+
const quadZ = corners.reduce((s, p) => s + p.z, 0) / 4;
|
|
423
|
+
const floorZ = computeLocalFloorZ(wallSegments, centerX, centerY);
|
|
424
|
+
if (quadZ < floorZ - 0.3) {
|
|
425
|
+
console.warn(`[findWindowWall] ${win.name} 高度异常(z=${quadZ.toFixed(3)},附近地面=${floorZ.toFixed(3)}),跳过`);
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
// ---- Step 1-2: 收集候选墙线段 → 多信号评分择优 ----
|
|
429
|
+
let bestSeg = null;
|
|
430
|
+
// 收集窗户的 5 个检查点(中心 + 4 角点)
|
|
431
|
+
// 解决窗户偏在墙的一端时中心投影越界的问题
|
|
432
|
+
const checkPoints = [
|
|
433
|
+
{ x: centerX, y: centerY, z: 0 }, // 中心点
|
|
434
|
+
{ x: corners[0].x, y: corners[0].y, z: 0 }, // 4 个角点
|
|
435
|
+
{ x: corners[1].x, y: corners[1].y, z: 0 },
|
|
436
|
+
{ x: corners[2].x, y: corners[2].y, z: 0 },
|
|
437
|
+
{ x: corners[3].x, y: corners[3].y, z: 0 },
|
|
438
|
+
];
|
|
439
|
+
// 扫查日志:打印候选墙线段详情,用于排查未匹配或匹配偏差的问题
|
|
440
|
+
if (win.name.includes('_008') || win.name.includes('_002') ||
|
|
441
|
+
win.name.includes('_014') || win.name.includes('_015') || win.name.includes('_020')) {
|
|
442
|
+
const allScored = candidateSegments.map((seg) => {
|
|
443
|
+
const { start, end } = seg;
|
|
444
|
+
// 中心点到无限直线的距离
|
|
445
|
+
const lineDist = pointToSegmentDist(centerX, centerY, start.x, start.y, end.x, end.y);
|
|
446
|
+
// 5 个点的投影数据
|
|
447
|
+
const pts = checkPoints.map((pt) => {
|
|
448
|
+
const r = pointToSegmentDist(pt.x, pt.y, start.x, start.y, end.x, end.y);
|
|
449
|
+
return `t=${r.t.toFixed(3)},d=${r.dist.toFixed(3)}`;
|
|
450
|
+
});
|
|
451
|
+
// 方向角
|
|
452
|
+
const dx = end.x - start.x, dy = end.y - start.y;
|
|
453
|
+
const sl = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
454
|
+
const sdx = dx / sl, sdy = dy / sl;
|
|
455
|
+
const dot = Math.abs(winDirX * sdx + winDirY * sdy);
|
|
456
|
+
const ang = Math.acos(Math.min(dot, 1)) * (180 / Math.PI);
|
|
457
|
+
return { seg, lineDist: lineDist.dist, t: lineDist.t, pts, angle: ang, length: seg.length };
|
|
458
|
+
});
|
|
459
|
+
allScored.sort((a, b) => a.lineDist - b.lineDist);
|
|
460
|
+
// 打印该窗户的全称
|
|
461
|
+
console.warn(`[${win.name}扫查] 按无限直线距离排序的前 15 条候选: (需长≥${(winLong * opts.minLengthRatio).toFixed(2)})`);
|
|
462
|
+
for (let i = 0; i < Math.min(15, allScored.length); i++) {
|
|
463
|
+
const s = allScored[i];
|
|
464
|
+
const lenOk = s.length >= winLong * opts.minLengthRatio ? '✓' : `✗(需${(winLong * opts.minLengthRatio).toFixed(2)})`;
|
|
465
|
+
const tOk = Math.abs(s.t) <= 1 + 0.4 ? '✓' : '✗'; // 宽松 t check
|
|
466
|
+
const dOk = s.lineDist <= 0.65 ? '✓' : '✗'; // 宽松 d check
|
|
467
|
+
const aOk = s.angle <= 45 ? '✓' : '✗';
|
|
468
|
+
console.warn(` #${i} 距=${s.lineDist.toFixed(3)}m t=${s.t.toFixed(3)} 角=${s.angle.toFixed(1)}° 长=${s.length.toFixed(3)}m` +
|
|
469
|
+
` [长度${lenOk} 投影${tOk} 距离${dOk} 角度${aOk}]` +
|
|
470
|
+
` 起点(${s.seg.start.x.toFixed(3)},${s.seg.start.y.toFixed(3)})→(${s.seg.end.x.toFixed(3)},${s.seg.end.y.toFixed(3)})` +
|
|
471
|
+
` | 5点: ${s.pts.join(' | ')}`);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
// ---- 多信号评分匹配:收集候选 → 评分 → 择优 ----
|
|
475
|
+
// 解决当窗户位于内外两墙之间时,优先选择外墙的问题
|
|
476
|
+
const matchAttempts = [
|
|
477
|
+
{ margin: opts.projectionMargin, maxDist: opts.maxDistance, label: '严格' },
|
|
478
|
+
{ margin: 0.4, maxDist: 0.65, label: '宽松' },
|
|
479
|
+
];
|
|
480
|
+
let passingCandidates = [];
|
|
481
|
+
for (const attempt of matchAttempts) {
|
|
482
|
+
// 如果上一轮已有候选,不再尝试宽松参数
|
|
483
|
+
if (passingCandidates.length > 0)
|
|
484
|
+
break;
|
|
485
|
+
for (const seg of candidateSegments) {
|
|
486
|
+
// 粗筛:长度
|
|
487
|
+
if (seg.length < winLong * opts.minLengthRatio)
|
|
488
|
+
continue;
|
|
489
|
+
const { start, end } = seg;
|
|
490
|
+
// 检查 5 个点中是否有任意一个通过投影 + 距离检查
|
|
491
|
+
let validPoint = false;
|
|
492
|
+
let minDist = Infinity;
|
|
493
|
+
for (const pt of checkPoints) {
|
|
494
|
+
const { dist, t } = pointToSegmentDist(pt.x, pt.y, start.x, start.y, end.x, end.y);
|
|
495
|
+
if (t >= -attempt.margin && t <= 1 + attempt.margin && dist <= attempt.maxDist) {
|
|
496
|
+
validPoint = true;
|
|
497
|
+
minDist = Math.min(minDist, dist);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (!validPoint)
|
|
501
|
+
continue;
|
|
502
|
+
// 方向约束:墙线方向与窗户长边方向的夹角
|
|
503
|
+
const segLen = Math.sqrt((end.x - start.x) ** 2 + (end.y - start.y) ** 2);
|
|
504
|
+
if (segLen < 1e-12)
|
|
505
|
+
continue;
|
|
506
|
+
const segDirX = (end.x - start.x) / segLen;
|
|
507
|
+
const segDirY = (end.y - start.y) / segLen;
|
|
508
|
+
const dot = Math.abs(winDirX * segDirX + winDirY * segDirY);
|
|
509
|
+
const angle = Math.acos(Math.min(dot, 1)) * (180 / Math.PI);
|
|
510
|
+
if (angle > opts.angleThreshold)
|
|
511
|
+
continue;
|
|
512
|
+
// 通过所有基础检查,加入候选列表
|
|
513
|
+
passingCandidates.push({
|
|
514
|
+
seg,
|
|
515
|
+
minDist,
|
|
516
|
+
ratio: seg.length / winLong,
|
|
517
|
+
score: 0,
|
|
518
|
+
details: { conn: 0, variance: 0, sameSide: 0 },
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
if (passingCandidates.length > 0) {
|
|
522
|
+
console.log(`[findWindowWall] ${win.name} ${attempt.label}模式: 有 ${passingCandidates.length} 条候选`);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// 多信号评分
|
|
526
|
+
if (passingCandidates.length > 1) {
|
|
527
|
+
for (const pc of passingCandidates) {
|
|
528
|
+
const { score, details } = computeWallScore(pc.seg, checkPoints, wallSegments);
|
|
529
|
+
pc.score = score;
|
|
530
|
+
pc.details = details;
|
|
531
|
+
}
|
|
532
|
+
// 按评分降序,同分按距离升序
|
|
533
|
+
passingCandidates.sort((a, b) => b.score - a.score || a.minDist - b.minDist);
|
|
534
|
+
const best = passingCandidates[0];
|
|
535
|
+
const logDetail = passingCandidates.map(p => `评分=${p.score}(conn=${p.details.conn}/var=${p.details.variance}/side=${p.details.sameSide}) dist=${p.minDist.toFixed(3)}`).join(' | ');
|
|
536
|
+
console.log(`[findWindowWall] ${win.name} 评分排序: ${logDetail}`);
|
|
537
|
+
console.log(`[findWindowWall] ${win.name} → 选中评分=${best.score}(conn=${best.details.conn}/var=${best.details.variance}/side=${best.details.sameSide}) dist=${best.minDist.toFixed(3)}m`);
|
|
538
|
+
}
|
|
539
|
+
else if (passingCandidates.length === 1) {
|
|
540
|
+
passingCandidates[0].score = -1; // 仅一条候选,不评分
|
|
541
|
+
}
|
|
542
|
+
let bestDist = Infinity;
|
|
543
|
+
let bestRatio = 0;
|
|
544
|
+
if (passingCandidates.length > 0) {
|
|
545
|
+
const winner = passingCandidates[0];
|
|
546
|
+
bestSeg = winner.seg;
|
|
547
|
+
bestDist = winner.minDist;
|
|
548
|
+
bestRatio = winner.ratio;
|
|
549
|
+
}
|
|
550
|
+
// 临时:输出 008 的匹配结果供验证
|
|
551
|
+
if (win.name.includes('_008') && bestSeg) {
|
|
552
|
+
console.log(`[findWindowWall] ${win.name} 匹配墙线: (${bestSeg.start.x.toFixed(3)},${bestSeg.start.y.toFixed(3)})→(${bestSeg.end.x.toFixed(3)},${bestSeg.end.y.toFixed(3)}) len=${bestSeg.length.toFixed(3)}m dist=${bestDist.toFixed(3)}m`);
|
|
553
|
+
}
|
|
554
|
+
// ---- drawWindow 计算(仅打印模式,默认不写入)----
|
|
555
|
+
// printOnly=true 时只打印匹配的 "窗户-墙段" 组,以及最终合成后的 drawWindow 结构
|
|
556
|
+
// printOnly=false 时才真正写入 wallSegment.drawWindow
|
|
557
|
+
let dw_info = undefined;
|
|
558
|
+
if (bestSeg) {
|
|
559
|
+
const dw_dx = bestSeg.end.x - bestSeg.start.x;
|
|
560
|
+
const dw_dy = bestSeg.end.y - bestSeg.start.y;
|
|
561
|
+
const dw_segLen = Math.sqrt(dw_dx * dw_dx + dw_dy * dw_dy);
|
|
562
|
+
const dw_dirX = dw_dx / dw_segLen;
|
|
563
|
+
const dw_dirY = dw_dy / dw_segLen;
|
|
564
|
+
// 将窗户 4 角点投影到墙段的参数轴上,得到 t∈[0,1] 的区间
|
|
565
|
+
const dw_tVals = [];
|
|
566
|
+
for (let ci = 0; ci < corners.length; ci++) {
|
|
567
|
+
const dw_px = corners[ci].x - bestSeg.start.x;
|
|
568
|
+
const dw_py = corners[ci].y - bestSeg.start.y;
|
|
569
|
+
const dw_t = (dw_px * dw_dirX + dw_py * dw_dirY) / dw_segLen;
|
|
570
|
+
dw_tVals.push(dw_t);
|
|
571
|
+
}
|
|
572
|
+
const dw_tMin = Math.min(...dw_tVals);
|
|
573
|
+
const dw_tMax = Math.max(...dw_tVals);
|
|
574
|
+
const dw_width = (dw_tMax - dw_tMin) * dw_segLen;
|
|
575
|
+
const dw_midT = (dw_tMin + dw_tMax) / 2;
|
|
576
|
+
const dw_pMidX = bestSeg.start.x + dw_midT * dw_dx;
|
|
577
|
+
const dw_pMidY = bestSeg.start.y + dw_midT * dw_dy;
|
|
578
|
+
const dw_boxMinZ = win.box.min.z;
|
|
579
|
+
const dw_boxMaxZ = win.box.max.z;
|
|
580
|
+
const dw_height = Math.abs(dw_boxMaxZ - dw_boxMinZ);
|
|
581
|
+
const dw_floorZ = computeLocalFloorZ(mergedSegments, bestSeg.start.x, bestSeg.start.y);
|
|
582
|
+
const dw_gClr = Math.max(0, dw_boxMinZ - dw_floorZ);
|
|
583
|
+
const dw_full = dw_tMin <= 0 && dw_tMax >= 1;
|
|
584
|
+
dw_info = {
|
|
585
|
+
p: { x: dw_pMidX, y: dw_pMidY, z: dw_boxMinZ + dw_height / 2 },
|
|
586
|
+
width: dw_width,
|
|
587
|
+
full: dw_full,
|
|
588
|
+
height: dw_height,
|
|
589
|
+
groundClearance: dw_gClr,
|
|
590
|
+
};
|
|
591
|
+
// ===== 打印 drawWindow 数据 =====
|
|
592
|
+
console.log('[drawWindow]', win.name, JSON.stringify(dw_info));
|
|
593
|
+
if (!opts.printOnly) {
|
|
594
|
+
const bs = bestSeg;
|
|
595
|
+
if (!bs.drawWindow)
|
|
596
|
+
bs.drawWindow = [];
|
|
597
|
+
bs.drawWindow.push(dw_info);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
// ---- Step 3: 输出 ----
|
|
601
|
+
if (bestSeg) {
|
|
602
|
+
results.push({
|
|
603
|
+
windowName: win.name,
|
|
604
|
+
windowCategory: win.category,
|
|
605
|
+
windowCenter: win.center,
|
|
606
|
+
wallSegment: bestSeg,
|
|
607
|
+
distance: bestDist,
|
|
608
|
+
wallLengthRatio: bestRatio,
|
|
609
|
+
drawWindow: dw_info,
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
console.warn(`[findWindowWall] ${win.name} 未找到匹配的墙线段`);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
// ---- Step 4: 数据合并(只对匹配上的墙段做)----
|
|
617
|
+
// 遍历匹配结果,如果墙段来自合并线段,则从原始线段中收集数据字段
|
|
618
|
+
for (const r of results) {
|
|
619
|
+
const ws = r.wallSegment;
|
|
620
|
+
// 找到 ws 在 mergedSegments 中的索引
|
|
621
|
+
const mi = mergedSegments.indexOf(ws);
|
|
622
|
+
if (mi === -1)
|
|
623
|
+
continue; // 不是合并线段(是原始线段),跳过
|
|
624
|
+
const srcIdxs = mergeSourceMap[mi];
|
|
625
|
+
if (!srcIdxs || srcIdxs.length <= 1)
|
|
626
|
+
continue; // 没有可合并的源数据
|
|
627
|
+
const srcSegs = srcIdxs.map((idx) => wallSegments[idx]);
|
|
628
|
+
// 合并数据字段
|
|
629
|
+
const allPoints = [];
|
|
630
|
+
const allOrig = [];
|
|
631
|
+
const allDoor = [];
|
|
632
|
+
const allInsetion = [];
|
|
633
|
+
const allDrawWin = [];
|
|
634
|
+
let boxData = undefined;
|
|
635
|
+
for (const s of srcSegs) {
|
|
636
|
+
if (s.points?.length)
|
|
637
|
+
for (const p of s.points)
|
|
638
|
+
allPoints.push(p);
|
|
639
|
+
if (s.originalPoints?.length)
|
|
640
|
+
for (const p of s.originalPoints)
|
|
641
|
+
allOrig.push(p);
|
|
642
|
+
if (s.doorAndBeamData?.length)
|
|
643
|
+
for (const p of s.doorAndBeamData)
|
|
644
|
+
allDoor.push(p);
|
|
645
|
+
if (s.insetionArr?.length)
|
|
646
|
+
for (const p of s.insetionArr)
|
|
647
|
+
allInsetion.push(p);
|
|
648
|
+
if (s.drawWindow?.length)
|
|
649
|
+
for (const p of s.drawWindow)
|
|
650
|
+
allDrawWin.push(p);
|
|
651
|
+
if (s.boxData && !boxData)
|
|
652
|
+
boxData = s.boxData;
|
|
653
|
+
}
|
|
654
|
+
if (allPoints.length)
|
|
655
|
+
ws.points = allPoints;
|
|
656
|
+
if (allOrig.length)
|
|
657
|
+
ws.originalPoints = allOrig;
|
|
658
|
+
if (allDoor.length)
|
|
659
|
+
ws.doorAndBeamData = allDoor;
|
|
660
|
+
if (allInsetion.length)
|
|
661
|
+
ws.insetionArr = allInsetion;
|
|
662
|
+
if (allDrawWin.length)
|
|
663
|
+
ws.drawWindow = allDrawWin;
|
|
664
|
+
if (boxData)
|
|
665
|
+
ws.boxData = boxData;
|
|
666
|
+
if (allDrawWin.length > 0) {
|
|
667
|
+
console.log('[dataMerge] wall (' + ws.start.x.toFixed(3) + ',' + ws.start.y.toFixed(3) + ')->(' +
|
|
668
|
+
ws.end.x.toFixed(3) + ',' + ws.end.y.toFixed(3) + ')' +
|
|
669
|
+
' merged from ' + srcIdxs.length + ' segments' +
|
|
670
|
+
' drawWindow=' + allDrawWin.length + ' items');
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
// ---- Step 5: 打印合并后的 drawWindow(核对用,不影响业务输出)----
|
|
674
|
+
// 只打印合并后仍携带 drawWindow 的那段墙,便于人工核对窗-墙对应关系
|
|
675
|
+
const hasDw = mergedSegments.filter((s) => s.drawWindow && s.drawWindow.length > 0);
|
|
676
|
+
if (hasDw.length > 0) {
|
|
677
|
+
console.log('[findWindowWall] 合并后携带 drawWindow 的墙段数量=' + hasDw.length);
|
|
678
|
+
for (const s of hasDw) {
|
|
679
|
+
console.log('[findWindowWall] 墙段: (' + s.start.x.toFixed(3) + ',' + s.start.y.toFixed(3) + ')->(' +
|
|
680
|
+
s.end.x.toFixed(3) + ',' + s.end.y.toFixed(3) + ') len=' + s.length.toFixed(3) + 'm' +
|
|
681
|
+
' rooftopPz=' + (s.rooftopPz !== undefined ? s.rooftopPz.toFixed(3) : 'N/A'));
|
|
682
|
+
const dw = s.drawWindow;
|
|
683
|
+
for (let i = 0; i < dw.length; i++) {
|
|
684
|
+
const dwItem = dw[i];
|
|
685
|
+
console.log(' [drawWindow #' + i + '] p=(' + dwItem.p.x.toFixed(3) + ',' + dwItem.p.y.toFixed(3) +
|
|
686
|
+
') width=' + dwItem.width.toFixed(3) + 'm height=' + dwItem.height.toFixed(3) +
|
|
687
|
+
'm groundClearance=' + dwItem.groundClearance.toFixed(3) + 'm full=' + dwItem.full);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return results;
|
|
692
|
+
}
|
|
693
|
+
//# sourceMappingURL=findWindowWall.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findWindowWall.js","sourceRoot":"","sources":["../src/findWindowWall.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { WallSegment, WindowObject, FindWallOptions } from './findWindowWall';
|
|
2
|
+
export { findWindowWalls, mergeCollinearSegments, computeLocalFloorZ, } from './findWindowWall';
|
|
3
|
+
export type { Point3D, DrawWindow, WallSegment, WindowObject, FindWallOptions, } from './findWindowWall';
|
|
4
|
+
import type { Point3D, DrawWindow } from './findWindowWall';
|
|
5
|
+
export interface WallWindowMatch {
|
|
6
|
+
windowName: string;
|
|
7
|
+
windowCategory: string;
|
|
8
|
+
windowCenter: Point3D;
|
|
9
|
+
wallSegment: WallSegment;
|
|
10
|
+
distance: number;
|
|
11
|
+
wallLengthRatio: number;
|
|
12
|
+
drawWindow?: DrawWindow;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* 处理主函数:墙线段数组 + 物体数组 → 匹配窗户 → 输出带 drawWindow 的墙线段
|
|
16
|
+
* 纯算法,不依赖 Node API,可在浏览器中调用
|
|
17
|
+
*/
|
|
18
|
+
export declare function processData(wallSegments: WallSegment[], windowObjects: WindowObject[], options?: FindWallOptions & {
|
|
19
|
+
printOnly?: boolean;
|
|
20
|
+
}): {
|
|
21
|
+
segments: WallSegment[];
|
|
22
|
+
matches: WallWindowMatch[];
|
|
23
|
+
sourceMap: number[][];
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,WAAW,EACX,YAAY,EACZ,eAAe,EAEhB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,kBAAkB,CAAA;AAEzB,YAAY,EACV,OAAO,EACP,UAAU,EACV,WAAW,EACX,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG3D,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,EAAE,OAAO,CAAA;IACrB,WAAW,EAAE,WAAW,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,YAAY,EAAE,WAAW,EAAE,EAC3B,aAAa,EAAE,YAAY,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAClD;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;IAAC,OAAO,EAAE,eAAe,EAAE,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,EAAE,CAAA;CAAE,CA4BhF"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// wall-window-matcher 主入口
|
|
3
|
+
// 说明:此文件只包含纯算法函数(无 Node fs/path 依赖),可被浏览器/Vite 直接 import
|
|
4
|
+
// 若需要命令行工具,使用 cli.ts:npx tsx src/cli.ts <walls.json> <objects.json> [output.json]
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.computeLocalFloorZ = exports.mergeCollinearSegments = exports.findWindowWalls = void 0;
|
|
7
|
+
exports.processData = processData;
|
|
8
|
+
const findWindowWall_1 = require("./findWindowWall");
|
|
9
|
+
// 重新导出所有前端需要的函数和类型
|
|
10
|
+
var findWindowWall_2 = require("./findWindowWall");
|
|
11
|
+
Object.defineProperty(exports, "findWindowWalls", { enumerable: true, get: function () { return findWindowWall_2.findWindowWalls; } });
|
|
12
|
+
Object.defineProperty(exports, "mergeCollinearSegments", { enumerable: true, get: function () { return findWindowWall_2.mergeCollinearSegments; } });
|
|
13
|
+
Object.defineProperty(exports, "computeLocalFloorZ", { enumerable: true, get: function () { return findWindowWall_2.computeLocalFloorZ; } });
|
|
14
|
+
/**
|
|
15
|
+
* 处理主函数:墙线段数组 + 物体数组 → 匹配窗户 → 输出带 drawWindow 的墙线段
|
|
16
|
+
* 纯算法,不依赖 Node API,可在浏览器中调用
|
|
17
|
+
*/
|
|
18
|
+
function processData(wallSegments, windowObjects, options) {
|
|
19
|
+
const opts = {
|
|
20
|
+
printOnly: false,
|
|
21
|
+
...options,
|
|
22
|
+
};
|
|
23
|
+
const matches = (0, findWindowWall_1.findWindowWalls)(windowObjects, wallSegments, opts);
|
|
24
|
+
// 合并后的墙线段(用于输出)
|
|
25
|
+
const { segments: mergedSegments, sourceMap } = (0, findWindowWall_1.mergeCollinearSegments)(wallSegments);
|
|
26
|
+
// 将 drawWindow 数据合并到对应的墙线段中
|
|
27
|
+
for (const match of matches) {
|
|
28
|
+
if (match.drawWindow) {
|
|
29
|
+
const seg = mergedSegments.find((s) => Math.abs(s.start.x - match.wallSegment.start.x) < 0.01 &&
|
|
30
|
+
Math.abs(s.start.y - match.wallSegment.start.y) < 0.01 &&
|
|
31
|
+
Math.abs(s.end.x - match.wallSegment.end.x) < 0.01 &&
|
|
32
|
+
Math.abs(s.end.y - match.wallSegment.end.y) < 0.01);
|
|
33
|
+
if (seg) {
|
|
34
|
+
if (!seg.drawWindow)
|
|
35
|
+
seg.drawWindow = [];
|
|
36
|
+
seg.drawWindow.push(match.drawWindow);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return { segments: mergedSegments, matches, sourceMap };
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0BAA0B;AAC1B,yDAAyD;AACzD,kFAAkF;;;AA4ClF,kCAgCC;AA1ED,qDAOyB;AAEzB,mBAAmB;AACnB,mDAIyB;AAHvB,iHAAA,eAAe,OAAA;AACf,wHAAA,sBAAsB,OAAA;AACtB,oHAAA,kBAAkB,OAAA;AAyBpB;;;GAGG;AACH,SAAgB,WAAW,CACzB,YAA2B,EAC3B,aAA6B,EAC7B,OAAmD;IAEnD,MAAM,IAAI,GAA6C;QACrD,SAAS,EAAE,KAAK;QAChB,GAAG,OAAO;KACX,CAAA;IAED,MAAM,OAAO,GAAG,IAAA,gCAAe,EAAC,aAAa,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;IAElE,gBAAgB;IAChB,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,GAAG,IAAA,uCAAsB,EAAC,YAAY,CAAC,CAAA;IAEpF,4BAA4B;IAC5B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;YACrB,MAAM,GAAG,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,CAAc,EAAE,EAAE,CACjD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;gBACtD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;gBACtD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI;gBAClD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CACnD,CAAA;YACD,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,CAAC,GAAG,CAAC,UAAU;oBAAE,GAAG,CAAC,UAAU,GAAG,EAAE,CAAA;gBACxC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAA;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;AACzD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wall-window-matcher",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "建筑点云 —— 墙线段共线合并 + 窗户匹配 + drawWindow 属性注入(浏览器/Node 通用)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"wall-window-matcher": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": ["dist"],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["building", "point-cloud", "window", "wall", "matching"],
|
|
16
|
+
"license": "MIT"
|
|
17
|
+
}
|