dimine-python-sdk 0.2.1__py3-none-any.whl → 0.2.2__py3-none-any.whl
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.
- dimine_python_sdk/__init__.py +1 -1
- dimine_python_sdk/cli/commands/file.py +2 -2
- dimine_python_sdk/docs/guides/lib/exploitation/contour_modeling.md +112 -5
- dimine_python_sdk/lib/exploitation/__init__.py +6 -0
- dimine_python_sdk/lib/exploitation/contour_modeling.py +190 -0
- dimine_python_sdk/lib/exploitation/models.py +16 -0
- dimine_python_sdk/lib/io/dmf_file.py +13 -11
- dimine_python_sdk/lib/io/models.py +2 -2
- dimine_python_sdk/lib/native/__init__.py +2 -0
- dimine_python_sdk/lib/native/exploitation.py +62 -0
- dimine_python_sdk/lib/native/geometry.py +18 -8
- dimine_python_sdk/lib/native/models.py +1 -0
- dimine_python_sdk/site/guides/lib/exploitation/contour_modeling.html +281 -17
- dimine_python_sdk/site/objects.inv +0 -0
- dimine_python_sdk/site/reference/cli/commands/file.html +2 -2
- dimine_python_sdk/site/reference/lib/bridge.html +472 -228
- dimine_python_sdk/site/reference/lib/exploitation/api.html +727 -269
- dimine_python_sdk/site/reference/lib/exploitation/contour_modeling.html +820 -357
- dimine_python_sdk/site/reference/lib/exploitation/models.html +115 -0
- dimine_python_sdk/site/reference/lib/io/dmf_file.html +47 -43
- dimine_python_sdk/site/reference/lib/io/models.html +5 -5
- dimine_python_sdk/site/reference/lib/native/exploitation.html +210 -24
- dimine_python_sdk/site/reference/lib/native/geometry.html +222 -200
- dimine_python_sdk/site/reference/lib/native/models.html +49 -13
- dimine_python_sdk/site/search/search_index.json +1 -1
- dimine_python_sdk/site/sitemap.xml +82 -82
- dimine_python_sdk/site/sitemap.xml.gz +0 -0
- {dimine_python_sdk-0.2.1.dist-info → dimine_python_sdk-0.2.2.dist-info}/METADATA +2 -1
- {dimine_python_sdk-0.2.1.dist-info → dimine_python_sdk-0.2.2.dist-info}/RECORD +37 -33
- {dimine_python_sdk-0.2.1.dist-info → dimine_python_sdk-0.2.2.dist-info}/WHEEL +1 -1
- outline/contour_extract.py +450 -0
- outline/contour_match.py +1095 -0
- outline/contour_pipeline.py +586 -0
- outline/contour_validate.py +645 -0
- outline/read_dwg.py +1 -1
- {dimine_python_sdk-0.2.1.dist-info → dimine_python_sdk-0.2.2.dist-info}/entry_points.txt +0 -0
- {dimine_python_sdk-0.2.1.dist-info → dimine_python_sdk-0.2.2.dist-info}/top_level.txt +0 -0
dimine_python_sdk/__init__.py
CHANGED
|
@@ -195,13 +195,13 @@ def register_commands(subparsers, format_parent) -> None:
|
|
|
195
195
|
p.add_argument("--file-id", default=None, help="文件ID,多个文件打开时必填")
|
|
196
196
|
|
|
197
197
|
p = subparsers.add_parser("file-open", parents=[format_parent], help="打开文件到 Dimine 场景")
|
|
198
|
-
p.add_argument("--path", required=True, help="要打开的 .dmf/.dwg/.dxf 等文件路径")
|
|
198
|
+
p.add_argument("--path", "--file", required=True, help="要打开的 .dmf/.dwg/.dxf 等文件路径")
|
|
199
199
|
|
|
200
200
|
p = subparsers.add_parser("file-close", parents=[format_parent], help="关闭 Dimine 中的文件")
|
|
201
201
|
p.add_argument("--file-id", required=True, help="要关闭的文件ID")
|
|
202
202
|
|
|
203
203
|
p = subparsers.add_parser("file-create", parents=[format_parent], help="在 Dimine 中创建新的空文件")
|
|
204
|
-
p.add_argument("--path", required=True, help="新文件的路径")
|
|
204
|
+
p.add_argument("--path", "--file", required=True, help="新文件的路径")
|
|
205
205
|
|
|
206
206
|
p = subparsers.add_parser("file-visibility", parents=[format_parent], help="设置文件显示/隐藏状态")
|
|
207
207
|
p.add_argument("--file-id", required=True, help="文件ID")
|
|
@@ -331,7 +331,105 @@ for i, merged in enumerate(merged_results):
|
|
|
331
331
|
print(f" 实体[{i}]: 顶点={merged.points.shape[0]}, 面片={merged.faces.shape[0]}")
|
|
332
332
|
```
|
|
333
333
|
|
|
334
|
-
## 6.
|
|
334
|
+
## 6. 地表建模
|
|
335
|
+
|
|
336
|
+
从多条等高线生成三角网地表模型(DTM)。输入为一组等高线,输出为三角网地表。
|
|
337
|
+
|
|
338
|
+
### 基础用法
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
import numpy as np
|
|
342
|
+
from dimine_python_sdk.lib.exploitation import SurfaceModeling
|
|
343
|
+
|
|
344
|
+
# 多条等高线(不同高程的封闭轮廓线)
|
|
345
|
+
contour1 = [[0, 0, 100], [10, 0, 100], [10, 10, 100], [0, 10, 100], [0, 0, 100]]
|
|
346
|
+
contour2 = [[2, 2, 200], [8, 2, 200], [8, 8, 200], [2, 8, 200], [2, 2, 200]]
|
|
347
|
+
contour3 = [[4, 4, 300], [6, 4, 300], [6, 6, 300], [4, 6, 300], [4, 4, 300]]
|
|
348
|
+
|
|
349
|
+
# 地表建模
|
|
350
|
+
surfaces = SurfaceModeling.create([contour1, contour2, contour3], mode=0)
|
|
351
|
+
|
|
352
|
+
print(f"生成地表数量: {len(surfaces)}")
|
|
353
|
+
for i, tin in enumerate(surfaces):
|
|
354
|
+
print(f" 地表[{i}] 顶点数: {tin.points.shape[0]}, 三角面片数: {tin.faces.shape[0]}")
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### 支持的输入格式
|
|
358
|
+
|
|
359
|
+
`SurfaceModeling.create(contour_lines, mode=0)` 的每条等高线支持三种输入格式:
|
|
360
|
+
|
|
361
|
+
```python
|
|
362
|
+
import numpy as np
|
|
363
|
+
from dimine_python_sdk.models.types import Line
|
|
364
|
+
from dimine_python_sdk.lib.exploitation import SurfaceModeling
|
|
365
|
+
|
|
366
|
+
# 方式一:List[List[List[float]]] 纯列表
|
|
367
|
+
result = SurfaceModeling.create([
|
|
368
|
+
[[0, 0, 100], [10, 0, 100], [10, 10, 100], [0, 10, 100], [0, 0, 100]],
|
|
369
|
+
[[2, 2, 200], [8, 2, 200], [8, 8, 200], [2, 8, 200], [2, 2, 200]],
|
|
370
|
+
])
|
|
371
|
+
|
|
372
|
+
# 方式二:List[np.ndarray]
|
|
373
|
+
arr1 = np.array([[0, 0, 100], [10, 0, 100], [10, 10, 100], [0, 10, 100], [0, 0, 100]])
|
|
374
|
+
arr2 = np.array([[2, 2, 200], [8, 2, 200], [8, 8, 200], [2, 8, 200], [2, 2, 200]])
|
|
375
|
+
result = SurfaceModeling.create([arr1, arr2])
|
|
376
|
+
|
|
377
|
+
# 方式三:List[Line Pydantic 模型]
|
|
378
|
+
line1 = Line(geometry=[[0, 0, 100], [10, 0, 100], [10, 10, 100], [0, 10, 100], [0, 0, 100]])
|
|
379
|
+
line2 = Line(geometry=[[2, 2, 200], [8, 2, 200], [8, 8, 200], [2, 8, 200], [2, 2, 200]])
|
|
380
|
+
result = SurfaceModeling.create([line1, line2])
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 从 DMF 文件读取等高线进行地表建模
|
|
384
|
+
|
|
385
|
+
```python
|
|
386
|
+
from dimine_python_sdk.lib.io import DmfFile
|
|
387
|
+
from dimine_python_sdk.lib.exploitation import SurfaceModeling
|
|
388
|
+
|
|
389
|
+
# 从 DMF 文件加载等高线
|
|
390
|
+
dmf = DmfFile("path/to/contours.dmf")
|
|
391
|
+
|
|
392
|
+
# 提取所有多段线实体作为等高线
|
|
393
|
+
contour_lines = []
|
|
394
|
+
for layer in dmf.layers:
|
|
395
|
+
for entity in layer.entities:
|
|
396
|
+
if hasattr(entity, 'geometry'):
|
|
397
|
+
contour_lines.append(entity.geometry)
|
|
398
|
+
|
|
399
|
+
# 执行地表建模
|
|
400
|
+
surfaces = SurfaceModeling.create(contour_lines, mode=0)
|
|
401
|
+
|
|
402
|
+
print(f"从 {len(contour_lines)} 条等高线生成 {len(surfaces)} 个地表模型")
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### 参数说明
|
|
406
|
+
|
|
407
|
+
| 参数 | 类型 | 默认值 | 说明 |
|
|
408
|
+
|------|------|--------|------|
|
|
409
|
+
| `contour_lines` | `List[Line]` / `List[np.ndarray]` / `List[List[List[float]]]` | — | 等高线列表,每条为三维点序列 |
|
|
410
|
+
| `mode` | `int` | `0` | 建模模式,默认 0 |
|
|
411
|
+
| `vertical_angle_threshold` | `float` | `25.0` | 伪影判定阈值(度):三角面法向量与水平面夹角小于此值则判定为伪影 |
|
|
412
|
+
| `vertical_iterations` | `int` | `10` | 伪影剥离最大迭代次数,某轮无新伪影则提前退出 |
|
|
413
|
+
|
|
414
|
+
### 伪影移除原理
|
|
415
|
+
|
|
416
|
+
Delaunay 三角网在凸包边界处会生成近似垂直的伪影三角形。`SurfaceModeling.create`
|
|
417
|
+
自动通过迭代剥离移除这些伪影:
|
|
418
|
+
|
|
419
|
+
1. 找出严格边界三角形(包含仅被一个三角形引用的边)
|
|
420
|
+
2. 扩展为边界区域(边界三角形 + 与之共享边的邻接三角形)
|
|
421
|
+
3. 对边界区域内三角面做法向量检查:\|法向量Z\| < sin(threshold) → 移除
|
|
422
|
+
4. 移除后形成新边界,重复步骤 1-3,直到某轮无新伪影或达到最大迭代次数
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
# 默认参数(推荐)
|
|
426
|
+
surfaces = SurfaceModeling.create(contour_lines, mode=0)
|
|
427
|
+
|
|
428
|
+
# 调整阈值(更激进 / 更保守)
|
|
429
|
+
surfaces = SurfaceModeling.create(contour_lines, mode=0, vertical_angle_threshold=30.0)
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## 7. 算法类型
|
|
335
433
|
|
|
336
434
|
通过 `ContourAlgorithm` 枚举指定两轮廓线之间的连接算法:
|
|
337
435
|
|
|
@@ -354,19 +452,21 @@ models = ContourModeling.two_contour_modeling(
|
|
|
354
452
|
)
|
|
355
453
|
```
|
|
356
454
|
|
|
357
|
-
##
|
|
455
|
+
## 8. 异常处理
|
|
358
456
|
|
|
359
457
|
轮廓线建模定义了层次化异常,建议调用时捕获具体异常:
|
|
360
458
|
|
|
361
459
|
```python
|
|
362
460
|
from dimine_python_sdk.lib.exploitation import (
|
|
363
461
|
ContourModeling,
|
|
462
|
+
SurfaceModeling,
|
|
364
463
|
ContourAlgorithm,
|
|
365
464
|
ModelingError,
|
|
366
465
|
TwoContourModelingError,
|
|
367
466
|
SingleContourModelingError,
|
|
368
467
|
ContourExtrapolateModelingError,
|
|
369
468
|
ParallelContourModelingError,
|
|
469
|
+
SurfaceModelingError,
|
|
370
470
|
)
|
|
371
471
|
|
|
372
472
|
try:
|
|
@@ -377,6 +477,12 @@ except TwoContourModelingError as e:
|
|
|
377
477
|
print(f"两轮廓线建模失败: {e}")
|
|
378
478
|
except ModelingError as e:
|
|
379
479
|
print(f"轮廓线建模错误: {e}")
|
|
480
|
+
|
|
481
|
+
# 地表建模异常处理
|
|
482
|
+
try:
|
|
483
|
+
surfaces = SurfaceModeling.create(contour_lines, mode=0)
|
|
484
|
+
except SurfaceModelingError as e:
|
|
485
|
+
print(f"地表建模失败: {e}")
|
|
380
486
|
```
|
|
381
487
|
|
|
382
488
|
异常继承关系:
|
|
@@ -387,10 +493,11 @@ RuntimeError
|
|
|
387
493
|
├── TwoContourModelingError (两轮廓线建模失败)
|
|
388
494
|
├── SingleContourModelingError (单轮廓线封闭为面失败)
|
|
389
495
|
├── ContourExtrapolateModelingError (轮廓线外推建模失败)
|
|
390
|
-
|
|
496
|
+
├── ParallelContourModelingError (多平行轮廓线建模失败)
|
|
497
|
+
└── SurfaceModelingError (地表建模失败)
|
|
391
498
|
```
|
|
392
499
|
|
|
393
|
-
##
|
|
500
|
+
## 9. 提交到 Dimine 场景
|
|
394
501
|
|
|
395
502
|
生成的三角网模型可以通过 `conn` 模块提交到 Dimine 场景中显示:
|
|
396
503
|
|
|
@@ -435,7 +542,7 @@ if __name__ == "__main__":
|
|
|
435
542
|
asyncio.run(main())
|
|
436
543
|
```
|
|
437
544
|
|
|
438
|
-
##
|
|
545
|
+
## 10. 完整示例
|
|
439
546
|
|
|
440
547
|
```python
|
|
441
548
|
import numpy as np
|
|
@@ -8,6 +8,8 @@ from dimine_python_sdk.lib.exploitation.contour_modeling import (
|
|
|
8
8
|
ModelingError,
|
|
9
9
|
ParallelContourModelingError,
|
|
10
10
|
SingleContourModelingError,
|
|
11
|
+
SurfaceModeling,
|
|
12
|
+
SurfaceModelingError,
|
|
11
13
|
TwoContourModelingError,
|
|
12
14
|
)
|
|
13
15
|
from dimine_python_sdk.lib.exploitation.implicit_modeling import (
|
|
@@ -31,6 +33,7 @@ from dimine_python_sdk.lib.exploitation.models import (
|
|
|
31
33
|
ImplicitStratumModelingParam,
|
|
32
34
|
LanewayParam,
|
|
33
35
|
SectionParam,
|
|
36
|
+
SurfaceModelingParam,
|
|
34
37
|
)
|
|
35
38
|
|
|
36
39
|
__all__ = [
|
|
@@ -45,10 +48,12 @@ __all__ = [
|
|
|
45
48
|
"TwoContourModelingError",
|
|
46
49
|
"SingleContourModelingError",
|
|
47
50
|
"ContourExtrapolateModelingError",
|
|
51
|
+
"SurfaceModelingError",
|
|
48
52
|
"ParallelContourModelingError",
|
|
49
53
|
"ContourAlgorithm",
|
|
50
54
|
"ExtrapolateMode",
|
|
51
55
|
"ExtrapolateDirection",
|
|
56
|
+
"SurfaceModeling",
|
|
52
57
|
"ImplicitModeling",
|
|
53
58
|
"ImplicitModelingError",
|
|
54
59
|
"ImplicitStratumModelingError",
|
|
@@ -56,4 +61,5 @@ __all__ = [
|
|
|
56
61
|
"ImplicitGridParam",
|
|
57
62
|
"ImplicitEstimationParam",
|
|
58
63
|
"ImplicitStratumModelingParam",
|
|
64
|
+
"SurfaceModelingParam",
|
|
59
65
|
]
|
|
@@ -23,6 +23,7 @@ from dimine_python_sdk.lib.native.exploitation import (
|
|
|
23
23
|
contour_extrapolate_modeling as _native_contour_extrapolate_modeling,
|
|
24
24
|
multi_parallel_contour_modeling as _native_multi_parallel_contour_modeling,
|
|
25
25
|
single_contour_modeling as _native_single_contour_modeling,
|
|
26
|
+
surface_modeling as _native_surface_modeling,
|
|
26
27
|
two_contour_modeling as _native_two_contour_modeling,
|
|
27
28
|
unite_polydata as _native_unite_polydata,
|
|
28
29
|
)
|
|
@@ -35,12 +36,15 @@ __all__ = [
|
|
|
35
36
|
"SingleContourModelingError",
|
|
36
37
|
"ContourExtrapolateModelingError",
|
|
37
38
|
"ParallelContourModelingError",
|
|
39
|
+
"SurfaceModelingError",
|
|
38
40
|
"ContourModeling",
|
|
41
|
+
"SurfaceModeling",
|
|
39
42
|
"two_contour_modeling_impl",
|
|
40
43
|
"single_contour_modeling_impl",
|
|
41
44
|
"contour_extrapolate_modeling_impl",
|
|
42
45
|
"unite_polydata_impl",
|
|
43
46
|
"multi_parallel_contour_modeling_impl",
|
|
47
|
+
"surface_modeling_impl",
|
|
44
48
|
]
|
|
45
49
|
|
|
46
50
|
|
|
@@ -64,11 +68,124 @@ class ParallelContourModelingError(ModelingError):
|
|
|
64
68
|
"""多平行轮廓线建模失败"""
|
|
65
69
|
|
|
66
70
|
|
|
71
|
+
class SurfaceModelingError(ModelingError):
|
|
72
|
+
"""地表建模失败"""
|
|
73
|
+
|
|
74
|
+
|
|
67
75
|
def _native_tin_to_tingeometry(tin: NativeTin) -> TINGeometry:
|
|
68
76
|
"""将 NativeTin 转换为 TINGeometry"""
|
|
69
77
|
return TINGeometry(points=tin.points, faces=tin.faces)
|
|
70
78
|
|
|
71
79
|
|
|
80
|
+
def _remove_vertical_triangles(
|
|
81
|
+
tin: NativeTin,
|
|
82
|
+
angle_threshold: float = 25.0,
|
|
83
|
+
iterations: int = 10,
|
|
84
|
+
) -> NativeTin:
|
|
85
|
+
"""移除地表模型中凸包边界附近的伪影三角形。
|
|
86
|
+
|
|
87
|
+
这些三角形出现在 Delaunay 三角网凸包边界附近,由边界边连接远距离
|
|
88
|
+
顶点形成近似垂直的三角面,并非真实地形表面的一部分。
|
|
89
|
+
|
|
90
|
+
每次迭代:
|
|
91
|
+
1. 找出严格边界三角形(包含只被一个三角形引用的边)
|
|
92
|
+
2. 边界三角形 + 与之共享边的邻接三角形共同构成「边界区域」
|
|
93
|
+
3. 对边界区域内的三角形做法向量角度检查(默认 15°)
|
|
94
|
+
4. 移除不合规三角形,形成新的边界
|
|
95
|
+
5. 重复 1-4,逐步向内剥离伪影层
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
tin : NativeTin
|
|
100
|
+
待处理的三角网模型。
|
|
101
|
+
angle_threshold : float
|
|
102
|
+
法向量与水平面的夹角阈值(度),默认 15.0。
|
|
103
|
+
iterations : int
|
|
104
|
+
最大迭代次数,默认 3。若某轮未移除任何三角形则提前终止。
|
|
105
|
+
|
|
106
|
+
Returns
|
|
107
|
+
-------
|
|
108
|
+
NativeTin
|
|
109
|
+
剔除伪影后的三角网模型,顶点已重新编号。
|
|
110
|
+
"""
|
|
111
|
+
if len(tin.faces) == 0:
|
|
112
|
+
return tin
|
|
113
|
+
|
|
114
|
+
points = np.asarray(tin.points, dtype=float)
|
|
115
|
+
faces = np.asarray(tin.faces, dtype=int)
|
|
116
|
+
min_nz = np.sin(np.radians(angle_threshold))
|
|
117
|
+
|
|
118
|
+
for _ in range(iterations):
|
|
119
|
+
n_faces = len(faces)
|
|
120
|
+
if n_faces == 0:
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
# --- 构建边→三角形映射,找出边界边和严格边界三角形 ---
|
|
124
|
+
edge_to_tris: dict[tuple, list] = {}
|
|
125
|
+
for fi, f in enumerate(faces):
|
|
126
|
+
i0, i1, i2 = int(f[0]), int(f[1]), int(f[2])
|
|
127
|
+
for e in [(min(i0, i1), max(i0, i1)),
|
|
128
|
+
(min(i1, i2), max(i1, i2)),
|
|
129
|
+
(min(i2, i0), max(i2, i0))]:
|
|
130
|
+
edge_to_tris.setdefault(e, []).append(fi)
|
|
131
|
+
|
|
132
|
+
boundary_tri_set: set = set()
|
|
133
|
+
for tris in edge_to_tris.values():
|
|
134
|
+
if len(tris) == 1:
|
|
135
|
+
boundary_tri_set.update(tris)
|
|
136
|
+
|
|
137
|
+
if not boundary_tri_set:
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
# --- 扩展边界区域:纳入与边界三角形共享边的邻接三角形 ---
|
|
141
|
+
boundary_region: set = set(boundary_tri_set)
|
|
142
|
+
for tri_idx in list(boundary_tri_set):
|
|
143
|
+
f = faces[tri_idx]
|
|
144
|
+
i0, i1, i2 = int(f[0]), int(f[1]), int(f[2])
|
|
145
|
+
for e in [(min(i0, i1), max(i0, i1)),
|
|
146
|
+
(min(i1, i2), max(i1, i2)),
|
|
147
|
+
(min(i2, i0), max(i2, i0))]:
|
|
148
|
+
for neighbor in edge_to_tris.get(e, []):
|
|
149
|
+
boundary_region.add(neighbor)
|
|
150
|
+
|
|
151
|
+
region_indices = np.array(sorted(boundary_region), dtype=int)
|
|
152
|
+
|
|
153
|
+
# --- 对边界区域做法向量检查 ---
|
|
154
|
+
v0 = points[faces[region_indices, 0]]
|
|
155
|
+
v1 = points[faces[region_indices, 1]]
|
|
156
|
+
v2 = points[faces[region_indices, 2]]
|
|
157
|
+
|
|
158
|
+
normals = np.cross(v1 - v0, v2 - v0)
|
|
159
|
+
mag = np.linalg.norm(normals, axis=1, keepdims=True)
|
|
160
|
+
mag[mag == 0] = 1e-30
|
|
161
|
+
normals = normals / mag
|
|
162
|
+
|
|
163
|
+
region_keep = np.abs(normals[:, 2]) >= min_nz # |nz| < sin(θ) → 法向量接近水平 → 三角面接近垂直
|
|
164
|
+
keep_mask = np.ones(n_faces, dtype=bool)
|
|
165
|
+
keep_mask[region_indices] = region_keep
|
|
166
|
+
|
|
167
|
+
kept_faces = faces[keep_mask]
|
|
168
|
+
|
|
169
|
+
if len(kept_faces) == n_faces:
|
|
170
|
+
break # 本轮没有移除任何三角形,提前终止
|
|
171
|
+
|
|
172
|
+
faces = kept_faces
|
|
173
|
+
|
|
174
|
+
if len(faces) == 0:
|
|
175
|
+
return tin
|
|
176
|
+
|
|
177
|
+
# --- 顶点重新编号 ---
|
|
178
|
+
used_indices = np.unique(faces)
|
|
179
|
+
reindex_map = {old: new for new, old in enumerate(used_indices)}
|
|
180
|
+
reindexed_faces = np.array(
|
|
181
|
+
[[reindex_map[int(i)] for i in face] for face in faces],
|
|
182
|
+
dtype=int,
|
|
183
|
+
)
|
|
184
|
+
kept_points = points[used_indices]
|
|
185
|
+
|
|
186
|
+
return NativeTin(points=kept_points, faces=reindexed_faces)
|
|
187
|
+
|
|
188
|
+
|
|
72
189
|
def _tingeometry_to_native_tin(tin: TINGeometry) -> NativeTin:
|
|
73
190
|
"""将 TINGeometry 转换为 NativeTin"""
|
|
74
191
|
return NativeTin(
|
|
@@ -325,3 +442,76 @@ def multi_parallel_contour_modeling_impl(
|
|
|
325
442
|
except Exception as exc:
|
|
326
443
|
raise ParallelContourModelingError(f"多平行轮廓线建模失败: {exc}") from exc
|
|
327
444
|
return [_native_tin_to_tingeometry(item) for item in result]
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
class SurfaceModeling:
|
|
448
|
+
"""
|
|
449
|
+
地表建模 — 从等高线生成三角网地表(DTM)
|
|
450
|
+
|
|
451
|
+
推荐用法(无需实例化)
|
|
452
|
+
--------------------
|
|
453
|
+
>>> lines = [line1, line2, line3] # 等高线列表
|
|
454
|
+
>>> SurfaceModeling.create(lines, mode=0)
|
|
455
|
+
"""
|
|
456
|
+
|
|
457
|
+
@staticmethod
|
|
458
|
+
def create(contour_lines, mode: int = 0, *,
|
|
459
|
+
vertical_angle_threshold: float = 25.0,
|
|
460
|
+
vertical_iterations: int = 10) -> List[TINGeometry]:
|
|
461
|
+
"""
|
|
462
|
+
地表建模:从等高线生成三角网地表
|
|
463
|
+
|
|
464
|
+
Parameters
|
|
465
|
+
----------
|
|
466
|
+
contour_lines : List[Line] or List[np.ndarray] or List[List[List[float]]]
|
|
467
|
+
等高线列表,每条为三维点序列。
|
|
468
|
+
mode : int
|
|
469
|
+
建模模式,默认 0。
|
|
470
|
+
vertical_angle_threshold : float
|
|
471
|
+
判定伪影三角形的法向量夹角阈值(度),默认 25.0。
|
|
472
|
+
vertical_iterations : int
|
|
473
|
+
伪影剥离最大迭代次数,默认 10。某轮无新伪影则提前退出。
|
|
474
|
+
|
|
475
|
+
Returns
|
|
476
|
+
-------
|
|
477
|
+
List[TINGeometry]
|
|
478
|
+
生成的三角网地表列表。
|
|
479
|
+
"""
|
|
480
|
+
return surface_modeling_impl(
|
|
481
|
+
contour_lines, mode,
|
|
482
|
+
vertical_angle_threshold=vertical_angle_threshold,
|
|
483
|
+
vertical_iterations=vertical_iterations,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
def surface_modeling_impl(contour_lines, mode: int = 0, *,
|
|
488
|
+
vertical_angle_threshold: float = 25.0,
|
|
489
|
+
vertical_iterations: int = 10) -> List[TINGeometry]:
|
|
490
|
+
"""地表建模:输入等高线,输出三角网地表
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
contour_lines : list
|
|
495
|
+
等高线列表。
|
|
496
|
+
mode : int
|
|
497
|
+
建模模式,默认 0。
|
|
498
|
+
vertical_angle_threshold : float
|
|
499
|
+
判定伪影三角形的法向量夹角阈值(度),默认 25.0。
|
|
500
|
+
vertical_iterations : int
|
|
501
|
+
伪影剥离最大迭代次数,默认 10。某轮无新伪影则提前退出。
|
|
502
|
+
"""
|
|
503
|
+
normalized = [_normalize_line(line) for line in contour_lines]
|
|
504
|
+
try:
|
|
505
|
+
result = _native_surface_modeling(normalized, mode=mode)
|
|
506
|
+
except Exception as exc:
|
|
507
|
+
raise SurfaceModelingError(f"地表建模失败: {exc}") from exc
|
|
508
|
+
|
|
509
|
+
tins: List[TINGeometry] = []
|
|
510
|
+
for item in result:
|
|
511
|
+
item = _remove_vertical_triangles(
|
|
512
|
+
item,
|
|
513
|
+
angle_threshold=vertical_angle_threshold,
|
|
514
|
+
iterations=vertical_iterations,
|
|
515
|
+
)
|
|
516
|
+
tins.append(_native_tin_to_tingeometry(item))
|
|
517
|
+
return tins
|
|
@@ -261,3 +261,19 @@ def _normalize_polylines_set(data) -> List[List[List[float]]]:
|
|
|
261
261
|
raise TypeError(
|
|
262
262
|
f"不支持的 polylines_set 类型: {type(data)},支持 List[Line]、List[np.ndarray]、List[List[List[float]]]"
|
|
263
263
|
)
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class SurfaceModelingParam(ParamModel):
|
|
267
|
+
"""
|
|
268
|
+
地表建模参数
|
|
269
|
+
|
|
270
|
+
示例
|
|
271
|
+
------
|
|
272
|
+
>>> SurfaceModelingParam(mode=0)
|
|
273
|
+
"""
|
|
274
|
+
|
|
275
|
+
mode: int = Field(
|
|
276
|
+
default=0,
|
|
277
|
+
ge=0,
|
|
278
|
+
description="建模模式,0=默认模式",
|
|
279
|
+
)
|
|
@@ -221,17 +221,14 @@ def _model_entity_to_native(entity: Any) -> NativeEntity:
|
|
|
221
221
|
properties=props,
|
|
222
222
|
)
|
|
223
223
|
if isinstance(entity, TextInfo):
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
return NativeEntity(
|
|
229
|
-
entity_type="text",
|
|
230
|
-
name=name,
|
|
231
|
-
feature_name=feature_name,
|
|
232
|
-
geometry=np.asarray(entity.position, dtype=float),
|
|
224
|
+
normal = getattr(entity, "normal", [0, 0, 1]) or [0, 0, 1]
|
|
225
|
+
return NativeText(
|
|
226
|
+
position=np.asarray(entity.position, dtype=float),
|
|
227
|
+
text=entity.text,
|
|
233
228
|
color=color,
|
|
234
|
-
|
|
229
|
+
height=entity.size,
|
|
230
|
+
normal=np.asarray(normal, dtype=float),
|
|
231
|
+
rotation=getattr(entity, "rotate", 0.0) or 0.0,
|
|
235
232
|
)
|
|
236
233
|
raise DmfInsertError(f"不支持的实体类型: {type(entity).__name__}")
|
|
237
234
|
|
|
@@ -271,6 +268,10 @@ def _model_layer_to_native(layer: DmfLayer) -> NativeLayer:
|
|
|
271
268
|
entities = []
|
|
272
269
|
for idx, entity in enumerate(layer.entities):
|
|
273
270
|
ne = _model_entity_to_native(entity)
|
|
271
|
+
# NativeText 没有 name/feature_name 属性,跳过命名逻辑
|
|
272
|
+
if isinstance(ne, NativeText):
|
|
273
|
+
entities.append(ne)
|
|
274
|
+
continue
|
|
274
275
|
# 兼容旧行为:未命名实体使用 "feature-index" 作为实体名称
|
|
275
276
|
if not ne.name:
|
|
276
277
|
ne.name = f"{ne.feature_name or '0'}-{idx}"
|
|
@@ -557,11 +558,12 @@ class DmfFile:
|
|
|
557
558
|
*,
|
|
558
559
|
name: str = "",
|
|
559
560
|
color: Optional[List[int]] = None,
|
|
561
|
+
size: float = 20,
|
|
560
562
|
properties: Optional[List[PropertyValue]] = None,
|
|
561
563
|
) -> None:
|
|
562
564
|
"""向指定图层插入文本标注"""
|
|
563
565
|
_, lyr = self._resolve_layer(layer)
|
|
564
|
-
lyr.insert_text(position, text, name=name, color=color)
|
|
566
|
+
lyr.insert_text(position, text, name=name, color=color, size=size)
|
|
565
567
|
if properties:
|
|
566
568
|
lyr.entities[-1].properties = list(properties)
|
|
567
569
|
|
|
@@ -300,7 +300,7 @@ class DmfLayer(LayerInfo):
|
|
|
300
300
|
tin = TINGeometry(points=pts[:, :3], faces=fcs)
|
|
301
301
|
self.entities.append(Shell(feature=name, geometry=tin, color=color))
|
|
302
302
|
|
|
303
|
-
def insert_text(self, position: np.ndarray, text: str, *, name: str = "", color: Optional[List[int]] = None) -> None:
|
|
303
|
+
def insert_text(self, position: np.ndarray, text: str, *, name: str = "", color: Optional[List[int]] = None, size: float = 20) -> None:
|
|
304
304
|
"""向本图层插入文本标注"""
|
|
305
305
|
from dimine_python_sdk.lib.io.dmf_file import DmfInsertError
|
|
306
306
|
|
|
@@ -308,4 +308,4 @@ class DmfLayer(LayerInfo):
|
|
|
308
308
|
if pos.shape[0] < 3:
|
|
309
309
|
raise DmfInsertError(f"文本位置至少需要3个分量,当前: {pos.shape[0]}")
|
|
310
310
|
|
|
311
|
-
self.entities.append(TextInfo(feature=name, text=text, position=pos[:3].tolist(), color=color or [255, 255, 255]))
|
|
311
|
+
self.entities.append(TextInfo(feature=name, text=text, position=pos[:3].tolist(), color=color or [255, 255, 255], size=size))
|
|
@@ -82,6 +82,7 @@ from dimine_python_sdk.lib.native.exploitation import (
|
|
|
82
82
|
laneway_modeling,
|
|
83
83
|
multi_parallel_contour_modeling,
|
|
84
84
|
single_contour_modeling,
|
|
85
|
+
surface_modeling,
|
|
85
86
|
two_contour_modeling,
|
|
86
87
|
unite_polydata,
|
|
87
88
|
)
|
|
@@ -161,4 +162,5 @@ __all__ = [
|
|
|
161
162
|
"contour_extrapolate_modeling",
|
|
162
163
|
"multi_parallel_contour_modeling",
|
|
163
164
|
"unite_polydata",
|
|
165
|
+
"surface_modeling",
|
|
164
166
|
]
|
|
@@ -11,6 +11,7 @@ from typing import Any
|
|
|
11
11
|
from dimine_python_sdk.lib.native._core import Dm
|
|
12
12
|
from dimine_python_sdk.lib.native._base import (
|
|
13
13
|
NativeExploitationError,
|
|
14
|
+
ensure_points,
|
|
14
15
|
parse_json_response,
|
|
15
16
|
)
|
|
16
17
|
from dimine_python_sdk.lib.native.models import NativeLithologyModel, NativeTin
|
|
@@ -159,6 +160,66 @@ def implicit_stratum_modeling(param: dict | str) -> list[NativeLithologyModel]:
|
|
|
159
160
|
]
|
|
160
161
|
|
|
161
162
|
|
|
163
|
+
def surface_modeling(contour_lines: list, mode: int = 0) -> list[NativeTin]:
|
|
164
|
+
"""
|
|
165
|
+
地表建模:从等高线生成三角网地表(DTM)。
|
|
166
|
+
|
|
167
|
+
将输入的等高线写入临时 DMF 文件,调用 C++ SurfaceModeling 生成地表
|
|
168
|
+
三角网,读取结果后清理临时文件。
|
|
169
|
+
|
|
170
|
+
Parameters
|
|
171
|
+
----------
|
|
172
|
+
contour_lines : list of np.ndarray
|
|
173
|
+
等高线列表,每条为 shape (N, 3) 的 numpy 数组。
|
|
174
|
+
mode : int
|
|
175
|
+
建模模式,默认 0。
|
|
176
|
+
|
|
177
|
+
Returns
|
|
178
|
+
-------
|
|
179
|
+
list[NativeTin]
|
|
180
|
+
生成的三角网地表列表。
|
|
181
|
+
"""
|
|
182
|
+
import json
|
|
183
|
+
import os
|
|
184
|
+
import shutil
|
|
185
|
+
import tempfile
|
|
186
|
+
|
|
187
|
+
import numpy as np
|
|
188
|
+
|
|
189
|
+
from dimine_python_sdk.lib.native.io import write_dmf
|
|
190
|
+
from dimine_python_sdk.lib.native.models import NativeEntity, NativeLayer
|
|
191
|
+
|
|
192
|
+
# 构建 NativeLayer,每条等高线为一个 polyline 实体
|
|
193
|
+
entities: list[NativeEntity] = []
|
|
194
|
+
for i, line in enumerate(contour_lines):
|
|
195
|
+
pts = np.asarray(line, dtype=float)
|
|
196
|
+
if pts.ndim != 2 or pts.shape[1] < 2:
|
|
197
|
+
raise NativeExploitationError(
|
|
198
|
+
f"等高线 {i} 格式无效: shape={pts.shape},期望 (N, 3)"
|
|
199
|
+
)
|
|
200
|
+
entities.append(
|
|
201
|
+
NativeEntity(
|
|
202
|
+
entity_type="polyline",
|
|
203
|
+
name=f"contour_{i}",
|
|
204
|
+
geometry=ensure_points(pts),
|
|
205
|
+
)
|
|
206
|
+
)
|
|
207
|
+
layer = NativeLayer(name="contours", entities=entities)
|
|
208
|
+
|
|
209
|
+
tmp_dir = tempfile.mkdtemp(prefix="dm_surface_")
|
|
210
|
+
tmp_file = os.path.join(tmp_dir, "surface_input.dmf")
|
|
211
|
+
try:
|
|
212
|
+
write_dmf(tmp_file, [layer])
|
|
213
|
+
param = json.dumps({"file": tmp_file, "mode": int(mode)}, ensure_ascii=False)
|
|
214
|
+
try:
|
|
215
|
+
result = Dm.SurfaceModeling(param)
|
|
216
|
+
except Exception as exc:
|
|
217
|
+
raise NativeExploitationError(f"地表建模失败: {exc}") from exc
|
|
218
|
+
return _convert_polydata_list(result, "地表建模")
|
|
219
|
+
finally:
|
|
220
|
+
shutil.rmtree(tmp_dir, ignore_errors=True)
|
|
221
|
+
|
|
222
|
+
|
|
162
223
|
__all__ = [
|
|
163
224
|
"get_section_contour",
|
|
164
225
|
"laneway_modeling",
|
|
@@ -168,4 +229,5 @@ __all__ = [
|
|
|
168
229
|
"multi_parallel_contour_modeling",
|
|
169
230
|
"unite_polydata",
|
|
170
231
|
"implicit_stratum_modeling",
|
|
232
|
+
"surface_modeling",
|
|
171
233
|
]
|