dimine-python-sdk 0.2.0__py3-none-any.whl → 0.2.1__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.
Files changed (221) hide show
  1. dimine_python_sdk/__init__.py +1 -1
  2. dimine_python_sdk/cli/commands/geometry.py +144 -20
  3. dimine_python_sdk/conn/conn_client.py +24 -11
  4. dimine_python_sdk/docs/examples/import_csv_to_drill_db.md +60 -8
  5. dimine_python_sdk/docs/examples/lib_file_usage.md +5 -3
  6. dimine_python_sdk/docs/examples/reserve_estimation_pipeline.md +1031 -0
  7. dimine_python_sdk/docs/examples/summary.md +1 -0
  8. dimine_python_sdk/docs/guides/SUMMARY.md +23 -14
  9. dimine_python_sdk/docs/guides/conn/SUMMARY.md +6 -0
  10. dimine_python_sdk/docs/guides/{data_get.md → conn/data_get.md} +4 -56
  11. dimine_python_sdk/docs/guides/{io.md → conn/io.md} +6 -24
  12. dimine_python_sdk/docs/guides/lib/SUMMARY.md +6 -0
  13. dimine_python_sdk/docs/guides/lib/exploitation/SUMMARY.md +5 -0
  14. dimine_python_sdk/docs/guides/lib/exploitation/implicit_modeling.md +151 -0
  15. dimine_python_sdk/docs/guides/lib/io/SUMMARY.md +10 -0
  16. dimine_python_sdk/docs/guides/lib/io/dmb_file.md +172 -0
  17. dimine_python_sdk/docs/guides/lib/io/dmd_file.md +196 -0
  18. dimine_python_sdk/docs/guides/lib/io/dmf_file.md +271 -0
  19. dimine_python_sdk/docs/guides/lib/io/dmg_file.md +192 -0
  20. dimine_python_sdk/docs/guides/lib/io/dmt_file.md +168 -0
  21. dimine_python_sdk/docs/guides/{file_conversion.md → lib/io/file_conversion.md} +3 -3
  22. dimine_python_sdk/docs/guides/lib/prospecting/SUMMARY.md +4 -0
  23. dimine_python_sdk/docs/guides/{db.md → lib/prospecting/drill_db.md} +218 -111
  24. dimine_python_sdk/docs/guides/{reserve_estimation.md → lib/prospecting/reserve_estimation.md} +42 -82
  25. dimine_python_sdk/docs/guides/lib/visualization/SUMMARY.md +3 -0
  26. dimine_python_sdk/docs/guides/models/SUMMARY.md +3 -0
  27. dimine_python_sdk/docs/reference/SUMMARY.md +2 -1
  28. dimine_python_sdk/docs/reference/lib/io/dmb_file.md +3 -0
  29. dimine_python_sdk/docs/reference/lib/io/dmd_file.md +3 -0
  30. dimine_python_sdk/docs/reference/lib/prospecting/api.md +3 -3
  31. dimine_python_sdk/lib/__init__.py +8 -0
  32. dimine_python_sdk/lib/exploitation/models.py +7 -5
  33. dimine_python_sdk/lib/io/__init__.py +24 -0
  34. dimine_python_sdk/lib/io/dmb_file.py +322 -0
  35. dimine_python_sdk/lib/io/dmd_file.py +641 -0
  36. dimine_python_sdk/lib/io/dmf_file.py +28 -11
  37. dimine_python_sdk/lib/io/dmg_file.py +120 -43
  38. dimine_python_sdk/lib/io/file_converter.py +7 -3
  39. dimine_python_sdk/lib/io/models.py +11 -11
  40. dimine_python_sdk/lib/native/__init__.py +164 -157
  41. dimine_python_sdk/lib/native/_core.py +101 -10
  42. dimine_python_sdk/lib/native/data_table.py +2 -0
  43. dimine_python_sdk/lib/native/geometry.py +131 -19
  44. dimine_python_sdk/lib/native/io.py +3 -1
  45. dimine_python_sdk/lib/native/models.py +140 -7
  46. dimine_python_sdk/lib/native/prospecting.py +853 -464
  47. dimine_python_sdk/lib/prospecting/__init__.py +4 -22
  48. dimine_python_sdk/lib/prospecting/block_model.py +133 -200
  49. dimine_python_sdk/lib/prospecting/compositing.py +51 -9
  50. dimine_python_sdk/lib/prospecting/drill_db.py +65 -790
  51. dimine_python_sdk/lib/prospecting/ellipsoid.py +43 -51
  52. dimine_python_sdk/lib/prospecting/high_grade.py +43 -19
  53. dimine_python_sdk/lib/prospecting/models.py +47 -12
  54. dimine_python_sdk/logger.py +1 -1
  55. dimine_python_sdk/models/types.py +1 -1
  56. dimine_python_sdk/site/404.html +834 -22
  57. dimine_python_sdk/site/examples/cli_usage.html +834 -22
  58. dimine_python_sdk/site/examples/contour_modeling_visualization.html +834 -22
  59. dimine_python_sdk/site/examples/import_csv_to_drill_db.html +1013 -129
  60. dimine_python_sdk/site/examples/lib_file_usage.html +839 -25
  61. dimine_python_sdk/site/examples/reserve_estimation_pipeline.html +3561 -0
  62. dimine_python_sdk/site/examples/summary.html +835 -22
  63. dimine_python_sdk/site/guides/SUMMARY.html +999 -37
  64. dimine_python_sdk/site/guides/cli.html +844 -23
  65. dimine_python_sdk/site/guides/conn/SUMMARY.html +1915 -0
  66. dimine_python_sdk/site/guides/{data_edit.html → conn/data_edit.html} +895 -72
  67. dimine_python_sdk/site/guides/{data_get.html → conn/data_get.html} +886 -151
  68. dimine_python_sdk/site/guides/{features.html → conn/features.html} +917 -94
  69. dimine_python_sdk/site/guides/{io.html → conn/io.html} +1002 -214
  70. dimine_python_sdk/site/guides/lib/SUMMARY.html +1915 -0
  71. dimine_python_sdk/site/guides/lib/exploitation/SUMMARY.html +1916 -0
  72. dimine_python_sdk/site/guides/{contour_modeling.html → lib/exploitation/contour_modeling.html} +900 -75
  73. dimine_python_sdk/site/guides/lib/exploitation/implicit_modeling.html +2362 -0
  74. dimine_python_sdk/site/guides/{laneway.html → lib/exploitation/laneway.html} +886 -61
  75. dimine_python_sdk/site/guides/lib/io/SUMMARY.html +1922 -0
  76. dimine_python_sdk/site/guides/lib/io/dmb_file.html +2394 -0
  77. dimine_python_sdk/site/guides/lib/io/dmd_file.html +2475 -0
  78. dimine_python_sdk/site/guides/lib/io/dmf_file.html +2667 -0
  79. dimine_python_sdk/site/guides/lib/io/dmg_file.html +2473 -0
  80. dimine_python_sdk/site/guides/lib/io/dmt_file.html +2501 -0
  81. dimine_python_sdk/site/guides/{file_conversion.html → lib/io/file_conversion.html} +1092 -267
  82. dimine_python_sdk/site/guides/lib/prospecting/SUMMARY.html +1915 -0
  83. dimine_python_sdk/site/guides/{db.html → lib/prospecting/drill_db.html} +1295 -207
  84. dimine_python_sdk/site/guides/{reserve_estimation.html → lib/prospecting/reserve_estimation.html} +1075 -307
  85. dimine_python_sdk/site/guides/lib/visualization/SUMMARY.html +1914 -0
  86. dimine_python_sdk/site/guides/{visualization.html → lib/visualization/visualization.html} +880 -55
  87. dimine_python_sdk/site/guides/models/SUMMARY.html +1912 -0
  88. dimine_python_sdk/site/guides/{data_types.html → models/data_types.html} +1050 -227
  89. dimine_python_sdk/site/index.html +834 -22
  90. dimine_python_sdk/site/objects.inv +0 -0
  91. dimine_python_sdk/site/quickstart.html +834 -22
  92. dimine_python_sdk/site/reference/SUMMARY.html +837 -24
  93. dimine_python_sdk/site/reference/cli/commands/camera.html +834 -22
  94. dimine_python_sdk/site/reference/cli/commands/convert.html +834 -22
  95. dimine_python_sdk/site/reference/cli/commands/datatable.html +834 -22
  96. dimine_python_sdk/site/reference/cli/commands/entity.html +834 -22
  97. dimine_python_sdk/site/reference/cli/commands/feature.html +834 -22
  98. dimine_python_sdk/site/reference/cli/commands/file.html +834 -22
  99. dimine_python_sdk/site/reference/cli/commands/geometry.html +1267 -414
  100. dimine_python_sdk/site/reference/cli/commands/laneway.html +834 -22
  101. dimine_python_sdk/site/reference/cli/commands/layer.html +834 -22
  102. dimine_python_sdk/site/reference/cli/commands/text.html +834 -22
  103. dimine_python_sdk/site/reference/conn/base_conn_client.html +834 -22
  104. dimine_python_sdk/site/reference/conn/conn_client.html +1156 -292
  105. dimine_python_sdk/site/reference/lib/bridge.html +3836 -1125
  106. dimine_python_sdk/site/reference/lib/exploitation/api.html +855 -39
  107. dimine_python_sdk/site/reference/lib/exploitation/contour_modeling.html +834 -22
  108. dimine_python_sdk/site/reference/lib/exploitation/implicit_modeling.html +834 -22
  109. dimine_python_sdk/site/reference/lib/exploitation/lane_way.html +834 -22
  110. dimine_python_sdk/site/reference/lib/exploitation/models.html +855 -39
  111. dimine_python_sdk/site/reference/lib/io/dmb_file.html +3682 -0
  112. dimine_python_sdk/site/reference/lib/io/dmd_file.html +4226 -0
  113. dimine_python_sdk/site/reference/lib/io/dmf_file.html +1031 -199
  114. dimine_python_sdk/site/reference/lib/io/dmg_file.html +1408 -134
  115. dimine_python_sdk/site/reference/lib/io/dmt_file.html +834 -22
  116. dimine_python_sdk/site/reference/lib/io/file_converter.html +941 -129
  117. dimine_python_sdk/site/reference/lib/io/models.html +859 -47
  118. dimine_python_sdk/site/reference/lib/native/algorithm.html +834 -22
  119. dimine_python_sdk/site/reference/lib/native/data_table.html +868 -48
  120. dimine_python_sdk/site/reference/lib/native/exploitation.html +834 -22
  121. dimine_python_sdk/site/reference/lib/native/geometry.html +1682 -628
  122. dimine_python_sdk/site/reference/lib/native/io.html +838 -26
  123. dimine_python_sdk/site/reference/lib/native/models.html +1920 -211
  124. dimine_python_sdk/site/reference/lib/native/prospecting.html +2814 -452
  125. dimine_python_sdk/site/reference/lib/prospecting/api.html +2839 -5836
  126. dimine_python_sdk/site/reference/lib/prospecting/block_model.html +1337 -1434
  127. dimine_python_sdk/site/reference/lib/prospecting/compositing.html +1073 -160
  128. dimine_python_sdk/site/reference/lib/prospecting/drill_db.html +930 -3361
  129. dimine_python_sdk/site/reference/lib/prospecting/ellipsoid.html +959 -141
  130. dimine_python_sdk/site/reference/lib/prospecting/high_grade.html +960 -82
  131. dimine_python_sdk/site/reference/lib/prospecting/models.html +1328 -294
  132. dimine_python_sdk/site/reference/lib/visualization/exceptions.html +834 -22
  133. dimine_python_sdk/site/reference/lib/visualization/models.html +834 -22
  134. dimine_python_sdk/site/reference/lib/visualization/tin_renderer.html +834 -22
  135. dimine_python_sdk/site/reference/logger.html +834 -22
  136. dimine_python_sdk/site/reference/models/conn.html +834 -22
  137. dimine_python_sdk/site/reference/models/errors.html +834 -22
  138. dimine_python_sdk/site/reference/models/types.html +835 -23
  139. dimine_python_sdk/site/search/search_index.json +1 -1
  140. dimine_python_sdk/site/sitemap.xml +141 -81
  141. dimine_python_sdk/site/sitemap.xml.gz +0 -0
  142. dimine_python_sdk/site/summary.html +834 -22
  143. {dimine_python_sdk-0.2.0.dist-info → dimine_python_sdk-0.2.1.dist-info}/METADATA +2 -1
  144. {dimine_python_sdk-0.2.0.dist-info → dimine_python_sdk-0.2.1.dist-info}/RECORD +171 -178
  145. outline/build_dmd_from_scratch.py +426 -0
  146. outline/dmd_to_dmg.py +164 -0
  147. outline/drill_to_reserves.py +825 -0
  148. outline/ellipsoid_params.py +6 -6
  149. outline/implicit_modeling.py +365 -0
  150. outline/read_dmb.py +200 -0
  151. outline/read_dwg.py +353 -0
  152. outline/test_dmd_file.py +322 -0
  153. outline/test_dmg_to_segments.py +317 -0
  154. outline/test_extend_table.py +193 -0
  155. tests/conn_example.py +3 -3
  156. tests/test_csv_import_flow.py +6 -6
  157. tests/test_dmg_file.py +5 -5
  158. tests/test_high_grade_samples.py +4 -4
  159. tests/test_lib_refactor.py +35 -44
  160. tests/test_native_unit.py +0 -9
  161. tests/test_prospecting_api.py +110 -138
  162. tests/test_sample_compositing.py +11 -11
  163. dimine_python_sdk/docs/reference/lib/io/file_conversion.md +0 -15
  164. dimine_python_sdk/site/reference/lib/io/file_conversion.html +0 -3279
  165. outline/create_empty_block_model.py +0 -136
  166. outline/debug_compare.py +0 -100
  167. outline/debug_file.py +0 -75
  168. outline/debug_from_runtime.py +0 -102
  169. outline/debug_implicit.py +0 -111
  170. outline/debug_pipeline.py +0 -72
  171. outline/debug_simple.py +0 -232
  172. outline/debug_synthetic.py +0 -101
  173. outline/debug_verify.py +0 -76
  174. outline/distance_power_estimation.py +0 -454
  175. outline/dmg_test.py +0 -33
  176. outline/generate_drill_db.py +0 -77
  177. outline/high_grade_processor.py +0 -23
  178. outline/model_upload.py +0 -43
  179. outline/read_dmf_example.py +0 -202
  180. outline/sample_compositing.py +0 -23
  181. outline/test_contour_two_circles.py +0 -193
  182. outline/test_convert_dmd_to_dmg.py +0 -65
  183. outline/test_csv_to_drill_db.py +0 -184
  184. outline/test_dmf_conn.py +0 -55
  185. outline/test_dmf_create.py +0 -100
  186. outline/test_dmf_file_save.py +0 -219
  187. outline/test_dmf_modify.py +0 -85
  188. outline/test_dmf_read.py +0 -81
  189. outline/test_dmgfile.py +0 -108
  190. outline/test_drill_to_implicit_modeling.py +0 -218
  191. outline/test_full_pipeline.py +0 -406
  192. outline/test_geometry_update.py +0 -277
  193. outline/test_high_grade_processor.py +0 -535
  194. outline/test_laneway_connectivity.py +0 -188
  195. outline/test_multi_parallel_contour_modeling.py +0 -139
  196. outline/test_multilayer_ellipse.py +0 -169
  197. outline/test_native_min.py +0 -44
  198. outline/test_native_read.py +0 -100
  199. outline/test_pipeline_real.py +0 -54
  200. outline/test_read_dmd.py +0 -81
  201. outline/test_real_high_grade.py +0 -255
  202. outline/test_sample_compositing.py +0 -784
  203. outline/test_save_dmd.py +0 -84
  204. outline/test_save_synthetic.py +0 -86
  205. outline/test_shaft_generation.py +0 -174
  206. outline/test_viz_1_basic.py +0 -85
  207. outline/test_viz_2_combined.py +0 -83
  208. outline/test_viz_3_overlay.py +0 -92
  209. outline/test_viz_4_custom_camera.py +0 -96
  210. outline/test_viz_5_interactive.py +0 -85
  211. outline/test_viz_6_errors.py +0 -95
  212. outline/tt.py +0 -17
  213. /dimine_python_sdk/docs/guides/{data_edit.md → conn/data_edit.md} +0 -0
  214. /dimine_python_sdk/docs/guides/{features.md → conn/features.md} +0 -0
  215. /dimine_python_sdk/docs/guides/{contour_modeling.md → lib/exploitation/contour_modeling.md} +0 -0
  216. /dimine_python_sdk/docs/guides/{laneway.md → lib/exploitation/laneway.md} +0 -0
  217. /dimine_python_sdk/docs/guides/{visualization.md → lib/visualization/visualization.md} +0 -0
  218. /dimine_python_sdk/docs/guides/{data_types.md → models/data_types.md} +0 -0
  219. {dimine_python_sdk-0.2.0.dist-info → dimine_python_sdk-0.2.1.dist-info}/WHEEL +0 -0
  220. {dimine_python_sdk-0.2.0.dist-info → dimine_python_sdk-0.2.1.dist-info}/entry_points.txt +0 -0
  221. {dimine_python_sdk-0.2.0.dist-info → dimine_python_sdk-0.2.1.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
  from .conn import ConnClient
4
4
 
5
5
  DOCS_PATH = Path(__file__).parent / "docs"
6
- __VERSION__ = "0.2.0" # 由 build.bat 中的 generate_version.py 自动更新
6
+ __VERSION__ = "0.2.1" # 由 build.bat 中的 generate_version.py 自动更新
7
7
 
8
8
 
9
9
  __all__ = [
@@ -202,6 +202,112 @@ def _build_single_geo_from_flat(file_id: str, layer_id: str, feature: str,
202
202
  return [obj]
203
203
 
204
204
 
205
+ def _build_partial_geo_from_flat(entity_id: str, geo_type: str | None = None,
206
+ file_id: str | None = None, layer_id: str | None = None,
207
+ feature: str | None = None, point: str | None = None,
208
+ points: str | None = None, faces: str | None = None,
209
+ color: str | None = None) -> list:
210
+ """从扁平参数构建部分几何体对象(仅用于 update)。
211
+
212
+ 与 _build_single_geo_from_flat 不同:
213
+ - 仅 entity_id 是必需的
214
+ - 未提供的字段设为 None/空,不会被发送到服务端
215
+ - geo_type 仅在提供几何数据时需要
216
+ """
217
+ from dimine_python_sdk.models.types import Line, Point, Shell
218
+
219
+ color_val = parse_color(color) if color else None
220
+
221
+ # 构建公共参数,只包含非 None 字段
222
+ common_kwargs = {"id": entity_id}
223
+ if file_id is not None:
224
+ common_kwargs["file"] = file_id
225
+ if layer_id is not None:
226
+ common_kwargs["layer"] = layer_id
227
+ if feature is not None:
228
+ common_kwargs["feature"] = feature
229
+ if color_val is not None:
230
+ common_kwargs["color"] = color_val
231
+
232
+ if geo_type == "point":
233
+ kwargs = dict(common_kwargs)
234
+ if point:
235
+ kwargs["geometry"] = parse_point3d(point)
236
+ obj = Point(**kwargs)
237
+ elif geo_type == "line":
238
+ kwargs = dict(common_kwargs)
239
+ if points:
240
+ kwargs["geometry"] = parse_points2d(points)
241
+ obj = Line(**kwargs)
242
+ elif geo_type == "shell":
243
+ kwargs = dict(common_kwargs)
244
+ if points:
245
+ pts = parse_points2d(points)
246
+ face_list = parse_points2d(faces) if faces else []
247
+ kwargs["geometry"] = {"points": pts, "faces": face_list}
248
+ obj = Shell(**kwargs)
249
+ elif geo_type is None:
250
+ # 无几何类型的纯属性更新(如只改 color)
251
+ obj = Shell(**common_kwargs)
252
+ else:
253
+ raise ValueError(f"无效的几何体类型 '{geo_type}',可选: point/line/shell")
254
+
255
+ obj.related = True
256
+ return [obj]
257
+
258
+
259
+ def _build_partial_geometry_objects(geometries: list) -> list:
260
+ """将 JSON 字典列表转换为部分几何体对象(仅用于 update)。
261
+
262
+ 与 _build_geometry_objects 不同:
263
+ - 只设置字典中存在的字段,缺失字段不填默认值
264
+ - 每个字典必须包含 'id' 字段
265
+ """
266
+ from dimine_python_sdk.models.types import Line, Point, Shell
267
+
268
+ result = []
269
+ for g in geometries:
270
+ entity_id = g.get("id")
271
+ if not entity_id:
272
+ raise ValueError("update 模式下每个几何体必须提供 'id' 字段")
273
+
274
+ geo_type = g.get("type", "shell")
275
+ file_id = g.get("file")
276
+ layer_id = g.get("layer")
277
+ feature_name = g.get("feature")
278
+ color = g.get("color")
279
+ geometry = g.get("geometry", {})
280
+
281
+ kwargs = {
282
+ "id": entity_id,
283
+ "file": file_id,
284
+ "layer": layer_id,
285
+ "feature": feature_name,
286
+ "color": color,
287
+ }
288
+
289
+ if geo_type == "point":
290
+ if "geometry" in g and geometry:
291
+ pt = geometry.get("point", [0, 0, 0])
292
+ kwargs["geometry"] = pt
293
+ obj = Point(**kwargs)
294
+ elif geo_type == "line":
295
+ if "geometry" in g and geometry:
296
+ pts = geometry.get("points", [])
297
+ kwargs["geometry"] = pts
298
+ obj = Line(**kwargs)
299
+ else:
300
+ if "geometry" in g and geometry:
301
+ pts = geometry.get("points", [])
302
+ faces = geometry.get("faces", [])
303
+ kwargs["geometry"] = {"points": pts, "faces": faces}
304
+ obj = Shell(**kwargs)
305
+
306
+ obj.related = True
307
+ result.append(obj)
308
+ return result
309
+
310
+
205
311
  def cmd_geometry_get(fmt: str, file_id: str, layer_id: str | None,
206
312
  entity_types: str | None = None, features: str | None = None,
207
313
  with_geometry: bool = False) -> None:
@@ -332,8 +438,10 @@ def cmd_geometry_update(fmt: str, geometries: str | None = None,
332
438
  """更新现有几何体对象(需 Dimine 运行)。
333
439
 
334
440
  两种模式:
335
- 1. 扁平参数(单几何体): --id --type --point/--points [--file --layer --feature --color]
441
+ 1. 扁平参数(单几何体): --id [--type --point/--points] [--file --layer --feature --color]
442
+ 不传的字段保持服务端原值不变。
336
443
  2. JSON/文件/stdin(批量): --geometries JSON/@file.json/-
444
+ 字典中只包含需要更新的字段。
337
445
  """
338
446
  err = require_remote_sdk()
339
447
  if err:
@@ -344,21 +452,21 @@ def cmd_geometry_update(fmt: str, geometries: str | None = None,
344
452
  raw_geos = _read_geometries_input(geometries)
345
453
  except ValueError as e:
346
454
  output_error(str(e), fmt)
347
- elif entity_id and geo_type and file_id and layer_id and feature:
455
+ elif entity_id:
348
456
  try:
349
- raw_geos = _build_single_geo_from_flat(
457
+ raw_geos = _build_partial_geo_from_flat(
458
+ entity_id=entity_id, geo_type=geo_type,
350
459
  file_id=file_id, layer_id=layer_id, feature=feature,
351
- geo_type=geo_type, point=point, points=points, faces=faces, color=color,
352
- entity_id=entity_id,
460
+ point=point, points=points, faces=faces, color=color,
353
461
  )
354
462
  except ValueError as e:
355
463
  output_error(str(e), fmt)
356
464
  else:
357
- output_error("请提供 --geometries(批量)或 --id、--file、--layer、--feature、--type(单个更新)", fmt)
465
+ output_error("请提供 --geometries(批量)或 --id(单个更新)", fmt)
358
466
 
359
467
  if raw_geos and isinstance(raw_geos[0], dict):
360
468
  try:
361
- geo_objects = _build_geometry_objects(raw_geos)
469
+ geo_objects = _build_partial_geometry_objects(raw_geos)
362
470
  except Exception as e:
363
471
  output_error(f"构建几何体对象失败: {e}", fmt)
364
472
  else:
@@ -391,7 +499,10 @@ def cmd_geometry_upsert(fmt: str, geometries: str | None = None,
391
499
 
392
500
  两种模式:
393
501
  1. 扁平参数(单几何体): --file --layer --feature --type [--id] --point/--points [--color]
502
+ - 有 --id: 部分更新,不传的字段保持不变
503
+ - 无 --id: 新建几何体
394
504
  2. JSON/文件/stdin(批量): --geometries JSON/@file.json/-
505
+ - 字典中含 "id" 则部分更新,不含则新建
395
506
  """
396
507
  err = require_remote_sdk()
397
508
  if err:
@@ -402,26 +513,39 @@ def cmd_geometry_upsert(fmt: str, geometries: str | None = None,
402
513
  raw_geos = _read_geometries_input(geometries)
403
514
  except ValueError as e:
404
515
  output_error(str(e), fmt)
516
+ # 按是否有 id 分离:有 id 的部分更新,无 id 的新建
517
+ update_dicts = [g for g in raw_geos if g.get("id")]
518
+ create_dicts = [g for g in raw_geos if not g.get("id")]
519
+ geo_objects = []
520
+ if update_dicts:
521
+ try:
522
+ geo_objects.extend(_build_partial_geometry_objects(update_dicts))
523
+ except Exception as e:
524
+ output_error(f"构建更新几何体对象失败: {e}", fmt)
525
+ if create_dicts:
526
+ try:
527
+ geo_objects.extend(_build_geometry_objects(create_dicts))
528
+ except Exception as e:
529
+ output_error(f"构建新建几何体对象失败: {e}", fmt)
405
530
  elif geo_type and file_id and layer_id and feature:
406
531
  try:
407
- raw_geos = _build_single_geo_from_flat(
408
- file_id=file_id, layer_id=layer_id, feature=feature,
409
- geo_type=geo_type, point=point, points=points, faces=faces, color=color,
410
- entity_id=entity_id,
411
- )
532
+ if entity_id:
533
+ raw_geos = _build_partial_geo_from_flat(
534
+ entity_id=entity_id, geo_type=geo_type,
535
+ file_id=file_id, layer_id=layer_id, feature=feature,
536
+ point=point, points=points, faces=faces, color=color,
537
+ )
538
+ else:
539
+ raw_geos = _build_single_geo_from_flat(
540
+ file_id=file_id, layer_id=layer_id, feature=feature,
541
+ geo_type=geo_type, point=point, points=points, faces=faces, color=color,
542
+ )
412
543
  except ValueError as e:
413
544
  output_error(str(e), fmt)
545
+ geo_objects = raw_geos
414
546
  else:
415
547
  output_error("请提供 --geometries(批量)或 --file、--layer、--feature、--type(单个)", fmt)
416
548
 
417
- if raw_geos and isinstance(raw_geos[0], dict):
418
- try:
419
- geo_objects = _build_geometry_objects(raw_geos)
420
- except Exception as e:
421
- output_error(f"构建几何体对象失败: {e}", fmt)
422
- else:
423
- geo_objects = raw_geos
424
-
425
549
  async def _run():
426
550
  client = await get_client()
427
551
  result = await client.update_or_create_geometry(geo_objects)
@@ -163,7 +163,7 @@ class ConnClient(BaseConnClient):
163
163
  "layer": geom.layer,
164
164
  "feature": geom.feature or "0",
165
165
  "entity_type": geom.type,
166
- "color": geom.color,
166
+ "color": geom.color if geom.color is not None else [0, 0, 0],
167
167
  "properties": [
168
168
  {"name": prop.name, "value": prop.value}
169
169
  for prop in geom.properties
@@ -350,18 +350,31 @@ class ConnClient(BaseConnClient):
350
350
  # 格式化模型数据
351
351
  formatted_geometries = []
352
352
  for geom in geometries:
353
- formatted_geom = {
354
- "id": geom.id,
355
- "file": geom.file,
356
- "layer": geom.layer,
357
- "feature": geom.feature,
358
- "entity_type": geom.type,
359
- "geometry": geom.geometry.tolist() if geom.type!="shell" else {"indexs": geom.geometry.faces.tolist(), "points": geom.geometry.points.tolist()},
360
- "color": geom.color,
361
- }
353
+ formatted_geom: Dict[str, Any] = {"id": geom.id}
354
+ # 仅发送显式设置的非 None/空字段
355
+ if geom.file is not None:
356
+ formatted_geom["file"] = geom.file
357
+ if geom.layer is not None:
358
+ formatted_geom["layer"] = geom.layer
359
+ if geom.feature is not None:
360
+ formatted_geom["feature"] = geom.feature
361
+ if geom.type is not None:
362
+ formatted_geom["entity_type"] = geom.type
363
+ if geom.color is not None:
364
+ formatted_geom["color"] = geom.color
365
+ # geometry:仅当非空时发送
366
+ if geom.type == "shell" and geom.geometry is not None:
367
+ geo = geom.geometry
368
+ if geo.points is not None and len(geo.points) > 0:
369
+ formatted_geom.setdefault("geometry", {})["points"] = geo.points.tolist()
370
+ if geo.faces is not None and len(geo.faces) > 0:
371
+ formatted_geom.setdefault("geometry", {})["indexs"] = geo.faces.tolist()
372
+ elif geom.type in ("point", "line") and geom.geometry is not None and len(geom.geometry) > 0:
373
+ formatted_geom["geometry"] = geom.geometry.tolist()
362
374
 
363
375
  # 处理属性信息
364
- formatted_geom["properties"] = [
376
+ if geom.properties:
377
+ formatted_geom["properties"] = [
365
378
  {"name": prop.name, "value": prop.value}
366
379
  for prop in geom.properties
367
380
  ]
@@ -15,7 +15,7 @@ Dimine 需已启动并开启 WebSocket 服务(默认 `ws://localhost:8000`)
15
15
  ```python
16
16
  import asyncio
17
17
  import pandas as pd
18
- from dimine_python_sdk.lib.prospecting import DrillDBManager
18
+ from dimine_python_sdk.lib.io import DmdFile
19
19
  from dimine_python_sdk.conn import open_client
20
20
 
21
21
 
@@ -23,9 +23,9 @@ async def import_and_open():
23
23
  # ------------------------------------------------------------------
24
24
  # 1. 从 CSV 导入并映射为中文标准列名
25
25
  # ------------------------------------------------------------------
26
- db = DrillDBManager()
26
+ dmd = DmdFile()
27
27
 
28
- db.collar = pd.read_csv("raw_collar.csv").rename(columns={
28
+ dmd.collar = pd.read_csv("raw_collar.csv").rename(columns={
29
29
  "HoleID": "工程号",
30
30
  "X": "横坐标",
31
31
  "Y": "纵坐标",
@@ -34,14 +34,14 @@ async def import_and_open():
34
34
  "Line": "勘探线",
35
35
  })
36
36
 
37
- db.survey = pd.read_csv("raw_survey.csv").rename(columns={
37
+ dmd.survey = pd.read_csv("raw_survey.csv").rename(columns={
38
38
  "HoleID": "工程号",
39
39
  "Depth": "测斜深度",
40
40
  "Azimuth": "方位角",
41
41
  "Dip": "倾角",
42
42
  })
43
43
 
44
- db.lithology = pd.read_csv("raw_lithology.csv").rename(columns={
44
+ dmd.lithology = pd.read_csv("raw_lithology.csv").rename(columns={
45
45
  "HoleID": "工程号",
46
46
  "From": "起始",
47
47
  "To": "结束",
@@ -49,7 +49,7 @@ async def import_and_open():
49
49
  })
50
50
 
51
51
  # 样品表可选;除标准列外可保留元素品位等非标准列
52
- db.sample = pd.read_csv("raw_sample.csv").rename(columns={
52
+ dmd.sample = pd.read_csv("raw_sample.csv").rename(columns={
53
53
  "HoleID": "工程号",
54
54
  "SampleID": "样本编号",
55
55
  "From": "起始",
@@ -62,7 +62,7 @@ async def import_and_open():
62
62
  # 2. 保存为 .dmd 钻孔数据库
63
63
  # ------------------------------------------------------------------
64
64
  dmd_path = "C:/Projects/Mine/钻孔数据.dmd"
65
- db.save(dmd_path)
65
+ dmd.save(dmd_path)
66
66
  print(f"已保存: {dmd_path}")
67
67
 
68
68
  # ------------------------------------------------------------------
@@ -77,6 +77,57 @@ if __name__ == "__main__":
77
77
  asyncio.run(import_and_open())
78
78
  ```
79
79
 
80
+ ## 导入扩展表
81
+
82
+ 除四大核心表外,还可以将分层表、地质编录表等自定义数据作为扩展表导入:
83
+
84
+ ```python
85
+ import pandas as pd
86
+ from dimine_python_sdk.lib.io import DmdFile
87
+ from dimine_python_sdk.lib.native.models import NativeExtendTable
88
+
89
+ dmd = DmdFile()
90
+
91
+ # 设置核心表...
92
+ dmd.collar = pd.read_csv("raw_collar.csv").rename(columns={...})
93
+ dmd.survey = pd.read_csv("raw_survey.csv").rename(columns={...})
94
+ dmd.lithology = pd.read_csv("raw_lithology.csv").rename(columns={...})
95
+
96
+ # 方式一:使用 NativeExtendTable(推荐)
97
+ ext_df = pd.read_csv("raw_stratigraphy.csv").rename(columns={
98
+ "HoleID": "工程号",
99
+ "From": "起始",
100
+ "To": "结束",
101
+ "LayerName": "分层名称",
102
+ })
103
+
104
+ dmd.extend_tables = [
105
+ NativeExtendTable(
106
+ df=ext_df,
107
+ dmt_filename="分层表.dmt",
108
+ hole_id_column="工程号",
109
+ from_column="起始",
110
+ to_column="结束",
111
+ display_title="分层表",
112
+ ),
113
+ ]
114
+
115
+ # 方式二:使用 dict(向后兼容)
116
+ dmd.extend_tables = [
117
+ {
118
+ "df": ext_df,
119
+ "dmt_filename": "分层表.dmt",
120
+ "hole_id_column": "工程号",
121
+ "from_column": "起始",
122
+ "to_column": "结束",
123
+ "display_title": "分层表",
124
+ },
125
+ ]
126
+
127
+ # 保存(扩展表自动写入 _分层表.dmt 并在 .dmd 中记录引用)
128
+ dmd.save("C:/Projects/Mine/钻孔数据.dmd")
129
+ ```
130
+
80
131
  ## 列名映射速查
81
132
 
82
133
  | 外部 CSV 列名 | 中文标准列名 | 对应表 |
@@ -94,6 +145,7 @@ if __name__ == "__main__":
94
145
  | `Rock` | `岩性编号` | 岩性表 |
95
146
 
96
147
  - 列名映射使用 `pandas.DataFrame.rename(columns=...)` 完成
97
- - DataFrame 列名必须包含[标准列名映射规范](../guides/db.md#标准列名映射规范)中对应表的必选标准列
148
+ - DataFrame 列名必须包含[标准列名映射规范](../guides/lib/prospecting/drill_db.md#13-standard-column-mapping)中对应表的必选标准列
98
149
  - 元素品位等非标准列(如 `CU`、`AU`)无需映射,直接保留即可 — 它们会写入 `.dmt` 子表但不出现于 `.dmd` 引用
99
150
  - `.dmd` 文件与 `{stem}_collar.dmt` / `{stem}_survey.dmt` / `{stem}_lithology.dmt` 等子表文件保存在同一目录下
151
+ - 扩展表的 `.dmt` 文件名由 `dmt_filename` 参数指定(如 `分层表.dmt`),保存时写入同一目录
@@ -73,14 +73,15 @@ with DmfFile("input.dmf") as dmf:
73
73
  # 新增图层
74
74
  layer = dmf.add_layer("计算结果")
75
75
 
76
- # 插入点
77
- layer.insert_point(np.array([100.0, 200.0, 300.0]), name="测点-1")
76
+ # 插入点(可指定颜色 color=[R, G, B])
77
+ layer.insert_point(np.array([100.0, 200.0, 300.0]), name="测点-1", color=[255, 0, 0])
78
78
 
79
79
  # 插入直线
80
80
  layer.insert_line(
81
81
  np.array([0.0, 0.0, 0.0]),
82
82
  np.array([10.0, 0.0, 0.0]),
83
83
  name="中线",
84
+ color=[0, 255, 0],
84
85
  )
85
86
 
86
87
  # 插入多段线
@@ -92,6 +93,7 @@ with DmfFile("input.dmf") as dmf:
92
93
  [0, 10, 0],
93
94
  ]),
94
95
  name="轮廓线",
96
+ color=[0, 0, 255],
95
97
  )
96
98
 
97
99
  # 保存为新文件
@@ -120,7 +122,7 @@ faces = np.array([
120
122
 
121
123
  with DmfFile() as dmf:
122
124
  layer = dmf.add_layer("三角网")
123
- layer.insert_shell(points, faces, name="坡面")
125
+ layer.insert_shell(points, faces, name="坡面", color=[128, 128, 128])
124
126
  dmf.save("shell_model.dmf")
125
127
  ```
126
128