Skip to content

native 桥接层

Native Layer 公开入口

对外暴露 Python 基础类型与 native dataclass, 所有 C++ 对象封装在内部句柄中。

BlockModelSession

块段模型会话,内部持有 C++ dmBlockDataNew 对象

Source code in dimine_python_sdk\lib\native\prospecting.py
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
class BlockModelSession:
    """块段模型会话,内部持有 C++ dmBlockDataNew 对象"""

    def __init__(self, cpp_obj: Any, file_path: str | None = None):
        self._cpp_obj = cpp_obj
        self._file_path = file_path

    @classmethod
    def open(cls, file_path: str) -> "BlockModelSession":
        """加载块段模型"""
        cpp_obj = Dm.dmBlockDataNew()
        if not cpp_obj.Open(file_path):
            raise NativeProspectingError(f"加载块段模型失败: {file_path}")
        return cls(cpp_obj, file_path)

    @property
    def origin(self) -> "np.ndarray":
        """模型原点"""
        import numpy as np

        pt = self._cpp_obj.GetOrigin()
        return np.array([pt.x, pt.y, pt.z], dtype=float)

    @property
    def xyz_length(self) -> list[float]:
        """模型 X/Y/Z 方向总长度"""
        return list(self._cpp_obj.GetXYZLen())

    @property
    def max_level(self) -> int:
        """最大精度层级"""
        return self._cpp_obj.GetMaxLevel()

    @property
    def min_size(self) -> list[float]:
        """最小块段尺寸(对应 max_level 层级的块段尺寸)"""
        return list(self._cpp_obj.GetMinSize())

    def get_level_size(self, level: int) -> list[float]:
        """获取指定层级的块段尺寸 [size_x, size_y, size_z]

        以 min_size(= max_level 时的尺寸)为基准反推:
            size_at_level(L) = min_size * 2^(max_level - L)

        Args:
            level: 层级(0 ~ max_level),0 为最粗粒度、max_level 为最细粒度

        Returns:
            [size_x, size_y, size_z]

        Raises:
            ValueError: level 超出 [0, max_level] 范围
        """
        if level < 0 or level > self.max_level:
            raise ValueError(
                f"level 必须在 [0, {self.max_level}] 范围内,实际: {level}"
            )
        factor = 2 ** (self.max_level - level)
        return [s * factor for s in self.min_size]

    def level_size_map(self) -> dict[int, list[float]]:
        """获取 0 ~ max_level 所有层级的块段尺寸对照表

        Returns:
            {level: [size_x, size_y, size_z], ...}
        """
        return {lv: self.get_level_size(lv) for lv in range(self.max_level + 1)}

    @property
    def rotation(self) -> list[float]:
        """模型旋转角度"""
        return list(self._cpp_obj.GetRotation())

    @property
    def field_definitions(self) -> list[NativeFieldDef]:
        """字段定义列表"""
        defs = self._cpp_obj.GetFieldDefine()
        return [NativeFieldDef(name=d["name"], type=d["type"]) for d in defs]

    @property
    def total_block_count(self) -> int:
        """块段总数量"""
        return self._cpp_obj.GetTotalBlockCount()

    def iter_blocks(self, field_name: Optional[str]=None) -> Iterator[dict]:
        """遍历所有块段,逐块返回指定字段数据"""
        self._cpp_obj.InitCursor()
        while 0 == self._cpp_obj.AdvCursor():    # 返回0 表示有数据,其他值表示没有数据了
            if self._cpp_obj.IsBeyondBoundaryNode():
                continue
            success, data = self._cpp_obj.GetCursorData(field_name or "")
            if success:
                try:
                    record = json.loads(data)
                    # 过滤:若所有 "距离" 开头的字段值均为 0,跳过该记录
                    if all(v == 0 for k, v in record.items() if k.startswith("距离")):
                        continue
                    # 去掉不需要的字段
                    _DROP_KEYS = {"xLen", "yLen", "zen", "I", "J", "K", "编号"}
                    record = {k: v for k, v in record.items() if k not in _DROP_KEYS}
                    yield record
                except (ValueError, TypeError):
                    continue
    def close(self) -> None:
        """释放 C++ 对象,解除文件占用"""
        self._cpp_obj = None
        self._file_path = None

field_definitions property

字段定义列表

max_level property

最大精度层级

min_size property

最小块段尺寸(对应 max_level 层级的块段尺寸)

origin property

模型原点

rotation property

模型旋转角度

total_block_count property

块段总数量

xyz_length property

模型 X/Y/Z 方向总长度

close()

释放 C++ 对象,解除文件占用

Source code in dimine_python_sdk\lib\native\prospecting.py
740
741
742
743
def close(self) -> None:
    """释放 C++ 对象,解除文件占用"""
    self._cpp_obj = None
    self._file_path = None

get_level_size(level)

获取指定层级的块段尺寸 [size_x, size_y, size_z]

以 min_size(= max_level 时的尺寸)为基准反推: size_at_level(L) = min_size * 2^(max_level - L)

Parameters:

Name Type Description Default
level int

层级(0 ~ max_level),0 为最粗粒度、max_level 为最细粒度

required

Returns:

Type Description
list[float]

[size_x, size_y, size_z]

Raises:

Type Description
ValueError

level 超出 [0, max_level] 范围

Source code in dimine_python_sdk\lib\native\prospecting.py
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
def get_level_size(self, level: int) -> list[float]:
    """获取指定层级的块段尺寸 [size_x, size_y, size_z]

    以 min_size(= max_level 时的尺寸)为基准反推:
        size_at_level(L) = min_size * 2^(max_level - L)

    Args:
        level: 层级(0 ~ max_level),0 为最粗粒度、max_level 为最细粒度

    Returns:
        [size_x, size_y, size_z]

    Raises:
        ValueError: level 超出 [0, max_level] 范围
    """
    if level < 0 or level > self.max_level:
        raise ValueError(
            f"level 必须在 [0, {self.max_level}] 范围内,实际: {level}"
        )
    factor = 2 ** (self.max_level - level)
    return [s * factor for s in self.min_size]

iter_blocks(field_name=None)

遍历所有块段,逐块返回指定字段数据

Source code in dimine_python_sdk\lib\native\prospecting.py
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
def iter_blocks(self, field_name: Optional[str]=None) -> Iterator[dict]:
    """遍历所有块段,逐块返回指定字段数据"""
    self._cpp_obj.InitCursor()
    while 0 == self._cpp_obj.AdvCursor():    # 返回0 表示有数据,其他值表示没有数据了
        if self._cpp_obj.IsBeyondBoundaryNode():
            continue
        success, data = self._cpp_obj.GetCursorData(field_name or "")
        if success:
            try:
                record = json.loads(data)
                # 过滤:若所有 "距离" 开头的字段值均为 0,跳过该记录
                if all(v == 0 for k, v in record.items() if k.startswith("距离")):
                    continue
                # 去掉不需要的字段
                _DROP_KEYS = {"xLen", "yLen", "zen", "I", "J", "K", "编号"}
                record = {k: v for k, v in record.items() if k not in _DROP_KEYS}
                yield record
            except (ValueError, TypeError):
                continue

level_size_map()

获取 0 ~ max_level 所有层级的块段尺寸对照表

Returns:

Type Description
dict[int, list[float]]

{level: [size_x, size_y, size_z], ...}

Source code in dimine_python_sdk\lib\native\prospecting.py
697
698
699
700
701
702
703
def level_size_map(self) -> dict[int, list[float]]:
    """获取 0 ~ max_level 所有层级的块段尺寸对照表

    Returns:
        {level: [size_x, size_y, size_z], ...}
    """
    return {lv: self.get_level_size(lv) for lv in range(self.max_level + 1)}

open(file_path) classmethod

加载块段模型

Source code in dimine_python_sdk\lib\native\prospecting.py
644
645
646
647
648
649
650
@classmethod
def open(cls, file_path: str) -> "BlockModelSession":
    """加载块段模型"""
    cpp_obj = Dm.dmBlockDataNew()
    if not cpp_obj.Open(file_path):
        raise NativeProspectingError(f"加载块段模型失败: {file_path}")
    return cls(cpp_obj, file_path)

DrillSession

钻孔数据库会话,内部持有 C++ dmGeoDrillData 对象

Source code in dimine_python_sdk\lib\native\prospecting.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
class DrillSession:
    """钻孔数据库会话,内部持有 C++ dmGeoDrillData 对象"""

    def __init__(self, cpp_obj: Any, ref_dict: dict, file_path: str | None = None):
        self._cpp_obj = cpp_obj
        self._ref_dict = ref_dict
        self._file_path: str | None = file_path
        self._extend_table_metas: list[NativeExtendTableMeta] = self._parse_extend_table_metas(ref_dict)

    @classmethod
    def load(cls, file_path: str) -> "DrillSession":
        """加载钻孔数据库"""
        cpp_obj = Dm.dmGeoDrillData()
        if not cpp_obj.Load(file_path):
            raise NativeProspectingError(f"加载钻孔数据库失败: {file_path}")
        ref_dict = _load_dmd_reference(file_path)
        return cls(cpp_obj, ref_dict, file_path)

    @classmethod
    def create_empty(cls) -> "DrillSession":
        """创建空钻孔数据库"""
        return cls(Dm.dmGeoDrillData(), {})

    @property
    def ref_dict(self) -> dict:
        return self._ref_dict

    @property
    def file_path(self) -> str | None:
        """DMD 文件路径"""
        return self._file_path

    # ------------------------------------------------------------------
    # 扩展表(附加表)元数据解析
    # ------------------------------------------------------------------

    @staticmethod
    def _parse_extend_table_metas(ref_dict: dict) -> list[NativeExtendTableMeta]:
        """从 ref_dict 解析扩展表元数据。

        ExtendTable{i}FieldList 格式:
        ``<钻孔编号列名>,<起始深度列名>,<结束深度列名>,<标题名称>``

        Returns:
            list of NativeExtendTableMeta
        """
        if not ref_dict:
            return []

        try:
            count = int(ref_dict.get("ExtendTableCount", 0))
        except (ValueError, TypeError):
            return []

        if count <= 0:
            return []

        metas = []
        for i in range(1, count + 1):
            path_key = f"ExtendTable{i}Path"
            fields_key = f"ExtendTable{i}FieldList"
            if path_key not in ref_dict:
                continue

            dmt_filename = ref_dict[path_key]
            field_list = ref_dict.get(fields_key, "")

            # 解析 4 个元数据字段
            field_names = [f.strip() for f in field_list.split(",") if f.strip()]
            hole_id_column = field_names[0] if len(field_names) >= 1 else None
            from_column = field_names[1] if len(field_names) >= 2 else None
            to_column = field_names[2] if len(field_names) >= 3 else None
            display_title = field_names[3] if len(field_names) >= 4 else None

            # table_name 优先使用 display_title,回退到 dmt 文件名
            table_name = display_title if display_title else dmt_filename.replace(".dmt", "")

            metas.append(NativeExtendTableMeta(
                dmt_filename=dmt_filename,
                field_list=field_list,
                hole_id_column=hole_id_column,
                from_column=from_column,
                to_column=to_column,
                display_title=display_title,
                table_name=table_name,
            ))

        return metas

    @property
    def extend_table_count(self) -> int:
        """扩展表数量"""
        return len(self._extend_table_metas)

    def extend_table_metas(self) -> list[NativeExtendTableMeta]:
        """返回扩展表元数据列表(不含 DataFrame)。

        Returns:
            list of NativeExtendTableMeta
        """
        return list(self._extend_table_metas)

    def get_extend_table(self, index: int) -> "pd.DataFrame":
        """按索引加载扩展表数据。

        从 DMT 文件加载数据,保留原始列名不做重命名。

        Args:
            index: 扩展表索引(0-based)

        Returns:
            pd.DataFrame,文件不存在或无元数据时返回空 DataFrame
        """
        require_pandas()
        import pandas as pd

        if index < 0 or index >= len(self._extend_table_metas):
            return pd.DataFrame()

        meta = self._extend_table_metas[index]
        dmt_filename = meta.dmt_filename

        if not self._file_path:
            return pd.DataFrame()

        dmt_path = Path(self._file_path).parent / dmt_filename
        if not dmt_path.exists():
            return pd.DataFrame()

        try:
            handle = NativeDataTableHandle.create()
            handle.load(str(dmt_path))
            return handle.to_dataframe()
        except Exception:
            logger.warning("加载扩展表失败: %s", dmt_path)
            return pd.DataFrame()

    def extend_tables(self) -> list[NativeExtendTable]:
        """加载全部扩展表,返回含数据和元数据的完整列表。

        DMT 文件路径根据 dmd 文件所在目录 + dmt_filename 拼接。

        Returns:
            list of NativeExtendTable
        """
        result = []

        for i in range(len(self._extend_table_metas)):
            df = self.get_extend_table(i)
            meta = self._extend_table_metas[i]
            result.append(NativeExtendTable(
                df=df,
                dmt_filename=meta.dmt_filename,
                field_list=meta.field_list,
                table_name=meta.table_name,
                hole_id_column=meta.hole_id_column,
                from_column=meta.from_column,
                to_column=meta.to_column,
                display_title=meta.display_title,
            ))

        return result

    def _get_table(self, getter_name: str, ref_table_key: str, ref_keys: set, std_map: dict, empty_columns: list[str]) -> "pd.DataFrame":
        """通用获取子表为 DataFrame"""
        require_pandas()
        import pandas as pd

        if not self._ref_dict or not self._ref_dict.get(ref_table_key):
            return pd.DataFrame(columns=empty_columns)

        cpp_table = getattr(self._cpp_obj, getter_name)()
        handle = NativeDataTableHandle(cpp_table)
        df = handle.to_dataframe()

        define = _build_define_from_ref(self._ref_dict, ref_keys)
        return _rename_with_define(df, define, std_map)

    def _set_table(
        self,
        df: "pd.DataFrame",
        getter_name: str,
        mapping: dict,
        required: list[str],
        ref_keys: set,
    ) -> None:
        """通用设置子表"""
        require_pandas()
        _validate_columns(df, mapping, getter_name, required)

        cpp_table = getattr(self._cpp_obj, getter_name)()
        handle = NativeDataTableHandle(cpp_table)
        handle.clear_records()

        define = _build_define_from_ref(self._ref_dict, ref_keys)
        column_mapping = {}
        if define:
            for std_key, actual_col in define.items():
                if actual_col in df.columns:
                    column_mapping[actual_col] = std_key
        for chinese, english in mapping.items():
            if chinese in df.columns and chinese not in column_mapping:
                column_mapping[chinese] = english

        handle.insert_from_dataframe(df, column_mapping=column_mapping)

    def collar_table(self) -> "pd.DataFrame":
        """获取孔口表"""
        return self._get_table(
            "GetCollarTable",
            "COLLAR",
            _COLLAR_REF_KEYS,
            _COLLAR_STD,
            list(COLLAR_COLUMN_MAP.keys()),
        )

    def set_collar_table(self, df: "pd.DataFrame") -> None:
        """设置孔口表"""
        self._set_table(df, "GetCollarTable", COLLAR_COLUMN_MAP, _COLLAR_REQUIRED, _COLLAR_REF_KEYS)

    def survey_table(self) -> "pd.DataFrame":
        """获取测斜表"""
        return self._get_table(
            "GetSurveyTable",
            "SURVEY",
            _SURVEY_REF_KEYS,
            _SURVEY_STD,
            list(SURVEY_COLUMN_MAP.keys()),
        )

    def set_survey_table(self, df: "pd.DataFrame") -> None:
        """设置测斜表"""
        self._set_table(df, "GetSurveyTable", SURVEY_COLUMN_MAP, _SURVEY_REQUIRED, _SURVEY_REF_KEYS)

    def lithology_table(self) -> "pd.DataFrame":
        """获取岩性表"""
        return self._get_table(
            "GetLithologyTable",
            "LITHOLOGY",
            _LITHOLOGY_REF_KEYS,
            _LITHOLOGY_STD,
            list(LITHOLOGY_COLUMN_MAP.keys()),
        )

    def set_lithology_table(self, df: "pd.DataFrame") -> None:
        """设置岩性表"""
        self._set_table(df, "GetLithologyTable", LITHOLOGY_COLUMN_MAP, _LITHOLOGY_REQUIRED, _LITHOLOGY_REF_KEYS)

    def sample_table(self) -> "pd.DataFrame":
        """获取样品表"""
        return self._get_table(
            "GetSampleTable",
            "SAMPLE",
            _SAMPLE_REF_KEYS,
            _SAMPLE_STD,
            list(SAMPLE_COLUMN_MAP.keys()),
        )

    def set_sample_table(self, df: "pd.DataFrame") -> None:
        """设置样品表"""
        self._set_table(df, "GetSampleTable", SAMPLE_COLUMN_MAP, _SAMPLE_REQUIRED, _SAMPLE_REF_KEYS)

    def save_as_dmg(self, file_path: str) -> None:
        """保存为 .dmg 格式

        先通过 GetDisplayDB 获取 dmDbDatabase 对象,保存为临时 .dmf 文件,
        再将 .dmf 拷贝并重命名为 .dmg。
        """
        """保存为 .dmg 格式"""
        try:
            self._cpp_obj.Save(file_path)
            import time
            time.sleep(2)
        except Exception as exc:
            raise NativeProspectingError(f"保存 .dmg 失败: {file_path}") from exc

    def close(self) -> None:
        """释放 C++ 对象,解除文件占用"""
        self._cpp_obj = None
        self._ref_dict = {}
        self._file_path = None
        self._extend_table_metas = []

extend_table_count property

扩展表数量

file_path property

DMD 文件路径

close()

释放 C++ 对象,解除文件占用

Source code in dimine_python_sdk\lib\native\prospecting.py
419
420
421
422
423
424
def close(self) -> None:
    """释放 C++ 对象,解除文件占用"""
    self._cpp_obj = None
    self._ref_dict = {}
    self._file_path = None
    self._extend_table_metas = []

collar_table()

获取孔口表

Source code in dimine_python_sdk\lib\native\prospecting.py
349
350
351
352
353
354
355
356
357
def collar_table(self) -> "pd.DataFrame":
    """获取孔口表"""
    return self._get_table(
        "GetCollarTable",
        "COLLAR",
        _COLLAR_REF_KEYS,
        _COLLAR_STD,
        list(COLLAR_COLUMN_MAP.keys()),
    )

create_empty() classmethod

创建空钻孔数据库

Source code in dimine_python_sdk\lib\native\prospecting.py
161
162
163
164
@classmethod
def create_empty(cls) -> "DrillSession":
    """创建空钻孔数据库"""
    return cls(Dm.dmGeoDrillData(), {})

extend_table_metas()

返回扩展表元数据列表(不含 DataFrame)。

Returns:

Type Description
list[NativeExtendTableMeta]

list of NativeExtendTableMeta

Source code in dimine_python_sdk\lib\native\prospecting.py
237
238
239
240
241
242
243
def extend_table_metas(self) -> list[NativeExtendTableMeta]:
    """返回扩展表元数据列表(不含 DataFrame)。

    Returns:
        list of NativeExtendTableMeta
    """
    return list(self._extend_table_metas)

extend_tables()

加载全部扩展表,返回含数据和元数据的完整列表。

DMT 文件路径根据 dmd 文件所在目录 + dmt_filename 拼接。

Returns:

Type Description
list[NativeExtendTable]

list of NativeExtendTable

Source code in dimine_python_sdk\lib\native\prospecting.py
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
def extend_tables(self) -> list[NativeExtendTable]:
    """加载全部扩展表,返回含数据和元数据的完整列表。

    DMT 文件路径根据 dmd 文件所在目录 + dmt_filename 拼接。

    Returns:
        list of NativeExtendTable
    """
    result = []

    for i in range(len(self._extend_table_metas)):
        df = self.get_extend_table(i)
        meta = self._extend_table_metas[i]
        result.append(NativeExtendTable(
            df=df,
            dmt_filename=meta.dmt_filename,
            field_list=meta.field_list,
            table_name=meta.table_name,
            hole_id_column=meta.hole_id_column,
            from_column=meta.from_column,
            to_column=meta.to_column,
            display_title=meta.display_title,
        ))

    return result

get_extend_table(index)

按索引加载扩展表数据。

从 DMT 文件加载数据,保留原始列名不做重命名。

Parameters:

Name Type Description Default
index int

扩展表索引(0-based)

required

Returns:

Type Description
'pd.DataFrame'

pd.DataFrame,文件不存在或无元数据时返回空 DataFrame

Source code in dimine_python_sdk\lib\native\prospecting.py
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def get_extend_table(self, index: int) -> "pd.DataFrame":
    """按索引加载扩展表数据。

    从 DMT 文件加载数据,保留原始列名不做重命名。

    Args:
        index: 扩展表索引(0-based)

    Returns:
        pd.DataFrame,文件不存在或无元数据时返回空 DataFrame
    """
    require_pandas()
    import pandas as pd

    if index < 0 or index >= len(self._extend_table_metas):
        return pd.DataFrame()

    meta = self._extend_table_metas[index]
    dmt_filename = meta.dmt_filename

    if not self._file_path:
        return pd.DataFrame()

    dmt_path = Path(self._file_path).parent / dmt_filename
    if not dmt_path.exists():
        return pd.DataFrame()

    try:
        handle = NativeDataTableHandle.create()
        handle.load(str(dmt_path))
        return handle.to_dataframe()
    except Exception:
        logger.warning("加载扩展表失败: %s", dmt_path)
        return pd.DataFrame()

lithology_table()

获取岩性表

Source code in dimine_python_sdk\lib\native\prospecting.py
377
378
379
380
381
382
383
384
385
def lithology_table(self) -> "pd.DataFrame":
    """获取岩性表"""
    return self._get_table(
        "GetLithologyTable",
        "LITHOLOGY",
        _LITHOLOGY_REF_KEYS,
        _LITHOLOGY_STD,
        list(LITHOLOGY_COLUMN_MAP.keys()),
    )

load(file_path) classmethod

加载钻孔数据库

Source code in dimine_python_sdk\lib\native\prospecting.py
152
153
154
155
156
157
158
159
@classmethod
def load(cls, file_path: str) -> "DrillSession":
    """加载钻孔数据库"""
    cpp_obj = Dm.dmGeoDrillData()
    if not cpp_obj.Load(file_path):
        raise NativeProspectingError(f"加载钻孔数据库失败: {file_path}")
    ref_dict = _load_dmd_reference(file_path)
    return cls(cpp_obj, ref_dict, file_path)

sample_table()

获取样品表

Source code in dimine_python_sdk\lib\native\prospecting.py
391
392
393
394
395
396
397
398
399
def sample_table(self) -> "pd.DataFrame":
    """获取样品表"""
    return self._get_table(
        "GetSampleTable",
        "SAMPLE",
        _SAMPLE_REF_KEYS,
        _SAMPLE_STD,
        list(SAMPLE_COLUMN_MAP.keys()),
    )

save_as_dmg(file_path)

保存为 .dmg 格式

先通过 GetDisplayDB 获取 dmDbDatabase 对象,保存为临时 .dmf 文件, 再将 .dmf 拷贝并重命名为 .dmg。

Source code in dimine_python_sdk\lib\native\prospecting.py
405
406
407
408
409
410
411
412
413
414
415
416
417
def save_as_dmg(self, file_path: str) -> None:
    """保存为 .dmg 格式

    先通过 GetDisplayDB 获取 dmDbDatabase 对象,保存为临时 .dmf 文件,
    再将 .dmf 拷贝并重命名为 .dmg。
    """
    """保存为 .dmg 格式"""
    try:
        self._cpp_obj.Save(file_path)
        import time
        time.sleep(2)
    except Exception as exc:
        raise NativeProspectingError(f"保存 .dmg 失败: {file_path}") from exc

set_collar_table(df)

设置孔口表

Source code in dimine_python_sdk\lib\native\prospecting.py
359
360
361
def set_collar_table(self, df: "pd.DataFrame") -> None:
    """设置孔口表"""
    self._set_table(df, "GetCollarTable", COLLAR_COLUMN_MAP, _COLLAR_REQUIRED, _COLLAR_REF_KEYS)

set_lithology_table(df)

设置岩性表

Source code in dimine_python_sdk\lib\native\prospecting.py
387
388
389
def set_lithology_table(self, df: "pd.DataFrame") -> None:
    """设置岩性表"""
    self._set_table(df, "GetLithologyTable", LITHOLOGY_COLUMN_MAP, _LITHOLOGY_REQUIRED, _LITHOLOGY_REF_KEYS)

set_sample_table(df)

设置样品表

Source code in dimine_python_sdk\lib\native\prospecting.py
401
402
403
def set_sample_table(self, df: "pd.DataFrame") -> None:
    """设置样品表"""
    self._set_table(df, "GetSampleTable", SAMPLE_COLUMN_MAP, _SAMPLE_REQUIRED, _SAMPLE_REF_KEYS)

set_survey_table(df)

设置测斜表

Source code in dimine_python_sdk\lib\native\prospecting.py
373
374
375
def set_survey_table(self, df: "pd.DataFrame") -> None:
    """设置测斜表"""
    self._set_table(df, "GetSurveyTable", SURVEY_COLUMN_MAP, _SURVEY_REQUIRED, _SURVEY_REF_KEYS)

survey_table()

获取测斜表

Source code in dimine_python_sdk\lib\native\prospecting.py
363
364
365
366
367
368
369
370
371
def survey_table(self) -> "pd.DataFrame":
    """获取测斜表"""
    return self._get_table(
        "GetSurveyTable",
        "SURVEY",
        _SURVEY_REF_KEYS,
        _SURVEY_STD,
        list(SURVEY_COLUMN_MAP.keys()),
    )

FileFormat

Bases: StrEnum

支持的文件格式

Source code in dimine_python_sdk\lib\native\io.py
29
30
31
32
33
34
35
36
37
class FileFormat(StrEnum):
    """支持的文件格式"""

    DMF = ".dmf"
    DWG = ".dwg"
    SURPAC = ".dtm"
    MICROMINE = ".STR"
    DATAMINE = ".DAT"
    MAPGIS = ".mgis"

NativeAlgorithmError

Bases: NativeModelError

几何算法异常

Source code in dimine_python_sdk\lib\native\_base.py
61
62
63
64
class NativeAlgorithmError(NativeModelError):
    """几何算法异常"""

    pass

NativeDBError

Bases: NativeModelError

数据库操作异常

Source code in dimine_python_sdk\lib\native\_base.py
49
50
51
52
class NativeDBError(NativeModelError):
    """数据库操作异常"""

    pass

NativeDataTableError

Bases: NativeModelError

数据表操作异常

Source code in dimine_python_sdk\lib\native\_base.py
43
44
45
46
class NativeDataTableError(NativeModelError):
    """数据表操作异常"""

    pass

NativeDataTableHandle

数据表不透明句柄,内部持有 C++ CDataTable 对象

Source code in dimine_python_sdk\lib\native\data_table.py
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
class NativeDataTableHandle:
    """数据表不透明句柄,内部持有 C++ CDataTable 对象"""

    def __init__(self, cpp_obj: Any):
        self._cpp_obj = cpp_obj

    @classmethod
    def create(cls) -> "NativeDataTableHandle":
        """创建空数据表"""
        return cls(Dm.CDataTable())

    @classmethod
    def from_dataframe(cls, df: "pd.DataFrame") -> "NativeDataTableHandle":
        """从 DataFrame 创建数据表"""
        require_pandas()
        import pandas as pd

        if not isinstance(df, pd.DataFrame):
            raise TypeError("df 必须为 pandas DataFrame")

        handle = cls.create()
        if len(df.columns) == 0:
            return handle

        for col in df.columns:
            handle.add_field(col, _infer_field_type_from_series(df[col]))

        for _, row in df.iterrows():
            record = handle.add_record()
            for col in df.columns:
                value = row[col]
                if pd.isna(value):
                    continue
                if isinstance(value, bool):
                    value = int(value)
                elif not isinstance(value, (str, int, float)):
                    value = str(value)
                record[col] = value

        return handle

    # ----------------------------------------------------------------------
    # 基本操作
    # ----------------------------------------------------------------------

    def load(self, file_path: str) -> None:
        """加载数据表文件"""
        result = self._cpp_obj.Load(file_path)
        if result is False:
            raise NativeDataTableError(f"加载数据表失败: {file_path}")

    def save(self, file_path: str | None = None) -> None:
        """保存数据表"""
        if file_path is not None:
            self._cpp_obj.SetFileName(file_path)
        self._cpp_obj.Save()
        #raise NativeDataTableError("保存数据表失败")

    def field_names(self) -> list[str]:
        """返回字段名列表"""
        count = self._cpp_obj.Get_Field_Count()
        return [self._cpp_obj.Get_Field_Name(i) for i in range(count)]

    def field_types(self) -> list[int]:
        """返回字段类型编码列表"""
        count = self._cpp_obj.Get_Field_Count()
        return [self._cpp_obj.Get_Field_Type(i) for i in range(count)]

    def field_definitions(self) -> list[NativeFieldDef]:
        """返回字段定义列表"""
        count = self._cpp_obj.Get_Field_Count()
        defs = []
        for i in range(count):
            name = self._cpp_obj.Get_Field_Name(i)
            ftype = self._cpp_obj.Get_Field_Type(i)
            defs.append(NativeFieldDef(name=name, type=ftype))
        return defs

    def record_count(self) -> int:
        """返回记录总数"""
        if self._cpp_obj is None:
            return 0
        return self._cpp_obj.Get_Record_Count()

    def get_record(self, index: int) -> dict:
        """通过索引获取单条记录字典"""
        if index < 0 or index >= self.record_count():
            raise IndexError(f"记录索引 {index} 超出范围 [0, {self.record_count()})")
        return self._cpp_obj.Get_Record_Data(index)

    def add_field(self, name: str, field_type: int | str) -> None:
        """添加字段"""
        code = _resolve_field_type(field_type)
        self._cpp_obj.Add_Field(name, code)

    def add_record(self) -> "_RecordProxy":
        """添加一条新记录,返回记录代理"""
        record = self._cpp_obj.Add_Record()
        return _RecordProxy(record)

    def clear_records(self) -> None:
        """清空所有记录"""
        while self.record_count() > 0:
            self._cpp_obj.Del_Record(0)

    def to_dataframe(self) -> "pd.DataFrame":
        """转换为 pandas DataFrame"""
        require_pandas()
        import pandas as pd

        rows = [self.get_record(i) for i in range(self.record_count())]
        return pd.DataFrame(rows, columns=self.field_names())

    def insert_from_dataframe(
        self,
        df: "pd.DataFrame",
        column_mapping: dict[str, str] | None = None,
        exclude_columns: list[str] | None = None,
        field_types: dict[str, str] | None = None,
    ) -> None:
        """从 DataFrame 批量插入数据"""
        require_pandas()
        import pandas as pd

        column_mapping = column_mapping or {}
        exclude = set(exclude_columns or [])
        field_types = field_types or {}

        if self.record_count() == 0 and self._cpp_obj.Get_Field_Count() == 0:
            for col in df.columns:
                field_name = column_mapping.get(col, col)
                ftype = field_types.get(field_name)
                if ftype is None:
                    ftype = _infer_field_type_from_series(df[col])
                self.add_field(field_name, ftype)

        for _, row in df.iterrows():
            record = self.add_record()
            for col in df.columns:
                field_name = column_mapping.get(col, col)
                if field_name in exclude:
                    continue
                value = row[col]
                if pd.isna(value):
                    continue
                if isinstance(value, bool):
                    value = int(value)
                elif not isinstance(value, (str, int, float)):
                    value = str(value)
                record[field_name] = value

    def __len__(self) -> int:
        return self.record_count()

    def __iter__(self):
        for i in range(self.record_count()):
            yield self.get_record(i)

    def __getitem__(self, key: str | int | slice):
        if isinstance(key, str):
            return [row[key] for row in self]
        if isinstance(key, int):
            return self.get_record(key)
        if isinstance(key, slice):
            return [self.get_record(i) for i in range(*key.indices(len(self)))]
        raise TypeError(f"不支持的 key 类型: {type(key)}")

add_field(name, field_type)

添加字段

Source code in dimine_python_sdk\lib\native\data_table.py
203
204
205
206
def add_field(self, name: str, field_type: int | str) -> None:
    """添加字段"""
    code = _resolve_field_type(field_type)
    self._cpp_obj.Add_Field(name, code)

add_record()

添加一条新记录,返回记录代理

Source code in dimine_python_sdk\lib\native\data_table.py
208
209
210
211
def add_record(self) -> "_RecordProxy":
    """添加一条新记录,返回记录代理"""
    record = self._cpp_obj.Add_Record()
    return _RecordProxy(record)

clear_records()

清空所有记录

Source code in dimine_python_sdk\lib\native\data_table.py
213
214
215
216
def clear_records(self) -> None:
    """清空所有记录"""
    while self.record_count() > 0:
        self._cpp_obj.Del_Record(0)

create() classmethod

创建空数据表

Source code in dimine_python_sdk\lib\native\data_table.py
119
120
121
122
@classmethod
def create(cls) -> "NativeDataTableHandle":
    """创建空数据表"""
    return cls(Dm.CDataTable())

field_definitions()

返回字段定义列表

Source code in dimine_python_sdk\lib\native\data_table.py
181
182
183
184
185
186
187
188
189
def field_definitions(self) -> list[NativeFieldDef]:
    """返回字段定义列表"""
    count = self._cpp_obj.Get_Field_Count()
    defs = []
    for i in range(count):
        name = self._cpp_obj.Get_Field_Name(i)
        ftype = self._cpp_obj.Get_Field_Type(i)
        defs.append(NativeFieldDef(name=name, type=ftype))
    return defs

field_names()

返回字段名列表

Source code in dimine_python_sdk\lib\native\data_table.py
171
172
173
174
def field_names(self) -> list[str]:
    """返回字段名列表"""
    count = self._cpp_obj.Get_Field_Count()
    return [self._cpp_obj.Get_Field_Name(i) for i in range(count)]

field_types()

返回字段类型编码列表

Source code in dimine_python_sdk\lib\native\data_table.py
176
177
178
179
def field_types(self) -> list[int]:
    """返回字段类型编码列表"""
    count = self._cpp_obj.Get_Field_Count()
    return [self._cpp_obj.Get_Field_Type(i) for i in range(count)]

from_dataframe(df) classmethod

从 DataFrame 创建数据表

Source code in dimine_python_sdk\lib\native\data_table.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@classmethod
def from_dataframe(cls, df: "pd.DataFrame") -> "NativeDataTableHandle":
    """从 DataFrame 创建数据表"""
    require_pandas()
    import pandas as pd

    if not isinstance(df, pd.DataFrame):
        raise TypeError("df 必须为 pandas DataFrame")

    handle = cls.create()
    if len(df.columns) == 0:
        return handle

    for col in df.columns:
        handle.add_field(col, _infer_field_type_from_series(df[col]))

    for _, row in df.iterrows():
        record = handle.add_record()
        for col in df.columns:
            value = row[col]
            if pd.isna(value):
                continue
            if isinstance(value, bool):
                value = int(value)
            elif not isinstance(value, (str, int, float)):
                value = str(value)
            record[col] = value

    return handle

get_record(index)

通过索引获取单条记录字典

Source code in dimine_python_sdk\lib\native\data_table.py
197
198
199
200
201
def get_record(self, index: int) -> dict:
    """通过索引获取单条记录字典"""
    if index < 0 or index >= self.record_count():
        raise IndexError(f"记录索引 {index} 超出范围 [0, {self.record_count()})")
    return self._cpp_obj.Get_Record_Data(index)

insert_from_dataframe(df, column_mapping=None, exclude_columns=None, field_types=None)

从 DataFrame 批量插入数据

Source code in dimine_python_sdk\lib\native\data_table.py
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def insert_from_dataframe(
    self,
    df: "pd.DataFrame",
    column_mapping: dict[str, str] | None = None,
    exclude_columns: list[str] | None = None,
    field_types: dict[str, str] | None = None,
) -> None:
    """从 DataFrame 批量插入数据"""
    require_pandas()
    import pandas as pd

    column_mapping = column_mapping or {}
    exclude = set(exclude_columns or [])
    field_types = field_types or {}

    if self.record_count() == 0 and self._cpp_obj.Get_Field_Count() == 0:
        for col in df.columns:
            field_name = column_mapping.get(col, col)
            ftype = field_types.get(field_name)
            if ftype is None:
                ftype = _infer_field_type_from_series(df[col])
            self.add_field(field_name, ftype)

    for _, row in df.iterrows():
        record = self.add_record()
        for col in df.columns:
            field_name = column_mapping.get(col, col)
            if field_name in exclude:
                continue
            value = row[col]
            if pd.isna(value):
                continue
            if isinstance(value, bool):
                value = int(value)
            elif not isinstance(value, (str, int, float)):
                value = str(value)
            record[field_name] = value

load(file_path)

加载数据表文件

Source code in dimine_python_sdk\lib\native\data_table.py
158
159
160
161
162
def load(self, file_path: str) -> None:
    """加载数据表文件"""
    result = self._cpp_obj.Load(file_path)
    if result is False:
        raise NativeDataTableError(f"加载数据表失败: {file_path}")

record_count()

返回记录总数

Source code in dimine_python_sdk\lib\native\data_table.py
191
192
193
194
195
def record_count(self) -> int:
    """返回记录总数"""
    if self._cpp_obj is None:
        return 0
    return self._cpp_obj.Get_Record_Count()

save(file_path=None)

保存数据表

Source code in dimine_python_sdk\lib\native\data_table.py
164
165
166
167
168
def save(self, file_path: str | None = None) -> None:
    """保存数据表"""
    if file_path is not None:
        self._cpp_obj.SetFileName(file_path)
    self._cpp_obj.Save()

to_dataframe()

转换为 pandas DataFrame

Source code in dimine_python_sdk\lib\native\data_table.py
218
219
220
221
222
223
224
def to_dataframe(self) -> "pd.DataFrame":
    """转换为 pandas DataFrame"""
    require_pandas()
    import pandas as pd

    rows = [self.get_record(i) for i in range(self.record_count())]
    return pd.DataFrame(rows, columns=self.field_names())

NativeDatabaseHandle

数据库不透明句柄,内部持有 C++ dmDbDatabase 对象

Source code in dimine_python_sdk\lib\native\geometry.py
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
class NativeDatabaseHandle:
    """数据库不透明句柄,内部持有 C++ dmDbDatabase 对象"""

    def __init__(self, cpp_obj: Any):
        self._cpp_obj = cpp_obj

    def __repr__(self) -> str:
        return f"NativeDatabaseHandle(layers={self.layer_count})"

    @classmethod
    def create(cls) -> "NativeDatabaseHandle":
        """创建只读数据库"""
        return cls(Dm.dmDbDatabase())

    @classmethod
    def create_local(cls) -> "NativeDatabaseHandle":
        """创建可编辑本地数据库"""
        return cls(Dm.dmDbDatabase.CreateLocalDB())

    def load(self, file_path: str) -> None:
        """加载 DMF 文件"""
        if not self._cpp_obj.Load(file_path):
            raise NativeDBError(f"加载 DMF 失败: {file_path}")

    def save(self, file_path: str | None = None) -> None:
        """保存 DMF 文件"""
        if file_path is None:
            if not self._cpp_obj.Save():
                raise NativeDBError("保存 DMF 失败")
        else:
            if not self._cpp_obj.Save(file_path):
                raise NativeDBError(f"保存 DMF 失败: {file_path}")

    def set_file_name(self, file_path: str) -> None:
        """设置文件路径"""
        self._cpp_obj.SetFileName(file_path)

    @property
    def layer_count(self) -> int:
        return self._cpp_obj.GetLayersCount()

    def get_layer(self, index: int) -> NativeLayerHandle:
        """通过索引获取图层"""
        if index < 0 or index >= self.layer_count:
            raise IndexError(f"图层索引 {index} 超出范围 [0, {self.layer_count})")
        cpp_layer = self._cpp_obj.GetLayerFromIndex(index)
        if not cpp_layer:
            raise NativeDBError(f"获取图层 {index} 返回空对象")
        return NativeLayerHandle(cpp_layer)

    def insert_layer(self, name: str) -> NativeLayerHandle:
        """插入新图层"""
        cpp_layer = self._cpp_obj.InsertLayer(str(name))
        return NativeLayerHandle(cpp_layer)

    def get_active_layer(self) -> NativeLayerHandle | None:
        """获取当前激活图层"""
        cpp_layer = self._cpp_obj.GetActiveLayer()
        if not cpp_layer:
            return None
        return NativeLayerHandle(cpp_layer)

    def insert_feature(self, name: str) -> NativeFeature:
        """插入新要素"""
        cpp_feature = self._cpp_obj.InsertFeature(str(name))
        return NativeFeature(
            name=cpp_feature.GetFeatureName(),
            properties=self._extract_feature_properties(cpp_feature),
        )

    def _insert_feature_raw(self, name: str) -> Any:
        """插入新要素并返回底层 C++ dmDbFeatureSet 对象"""
        return self._cpp_obj.InsertFeature(str(name))

    def get_feature(self, name: str) -> NativeFeature | None:
        """按名称获取要素"""
        cpp_feature = self._cpp_obj.GetFeatureFromName(str(name))
        if not cpp_feature:
            return None
        return NativeFeature(
            name=cpp_feature.GetFeatureName(),
            properties=self._extract_feature_properties(cpp_feature),
        )

    def set_active_feature(self, name: str) -> None:
        """设置当前激活要素"""
        self._cpp_obj.SetActiveFeature(str(name))

    def features(self) -> list[NativeFeature]:
        """获取所有要素定义(含属性定义清单)"""
        cpp_features = self._cpp_obj.GetFeatureSet()
        if not cpp_features:
            return []
        features= [
            NativeFeature(
                name=f.GetFeatureName(),
                properties=self._extract_feature_properties(f),
            )
            for f in cpp_features
        ]
        return features

    def set_features(self, features: Sequence[NativeFeature]) -> None:
        """注册所有要素及其属性定义。

        以 ``features`` 作为属性定义清单,直接写入各要素的 CDataTable;
        不再依赖实体反向推导,也不调用 ``add_property``。
        """
        for feat in features:
            if not feat.name:
                continue
            cpp_feature = self._insert_feature_raw(feat.name)
            self._register_feature_properties(cpp_feature, feat.properties)

    # 要素属性定义表中的元数据列,非用户自定义属性
    _FEATURE_META_COLUMNS = frozenset({"ent_handle", "实体类型", "实体名称", "XData"})

    def _extract_feature_properties(self, cpp_feature: Any) -> list[NativeProperty]:
        """从要素的属性定义表中提取属性定义清单

        属性定义表结构为:若干标准元数据列(ent_handle、实体类型、实体名称、
        XData)+ 若干用户自定义属性列。每列的列名即属性名,数据类型通过
        ``NativeDataTableHandle.field_definitions()`` 调用 ``Get_Field_Type``
        获取,不再依赖首行记录的值。
        """
        props: list[NativeProperty] = []
        try:
            cpp_table = cpp_feature.GetDataTable()
            if cpp_table is None:
                return props

            table = NativeDataTableHandle(cpp_table)
            for field_def in table.field_definitions():
                name = field_def.name
                if name in self._FEATURE_META_COLUMNS:
                    continue

                type_code = field_def.type if isinstance(field_def.type, int) else NativeFieldType.STRING
                ptype = _FIELD_TYPE_TO_PROPERTY_TYPE.get(type_code, "string")
                props.append(NativeProperty(name=name, type=ptype, value=None))
        except Exception as e:
            raise NativeDBError(f"提取属性定义失败: {e}") from e
        return props

    def _register_feature_properties(
        self,
        cpp_feature: Any,
        properties: Sequence[NativeProperty],
    ) -> None:
        """向要素的属性定义表写入属性定义清单。

        使用 ``NativeDataTableHandle`` 操作 CDataTable:属性名作为列名,
        列类型通过 ``Get_Field_Type`` 编码存放;元数据列仅确保存在,
        不再向首行记录写入类型码。
        """
        cpp_table = cpp_feature.GetDataTable()
        if cpp_table is None:
            raise NativeDBError("要素未关联属性定义表")

        table = NativeDataTableHandle(cpp_table)
        existing = set(table.field_names())

        # 确保元数据列存在
        for col in self._FEATURE_META_COLUMNS:
            if col not in existing:
                table.add_field(col, NativeFieldType.STRING)
                existing.add(col)

        # 添加用户属性列
        for prop in properties:
            if (
                not prop.name
                or prop.name in self._FEATURE_META_COLUMNS
                or prop.name in existing
            ):
                continue
            code = _PROPERTY_TYPE_TO_FIELD_TYPE.get(prop.type or "string", NativeFieldType.STRING)
            table.add_field(prop.name, code)
            existing.add(prop.name)

    def add_property(self, name: str, ptype: str) -> None:
        """添加属性定义"""
        success, message = self._cpp_obj.AddProperty(str(name), str(ptype))
        if not success:
            raise NativeDBError(f"添加属性失败: {message}")

    def close_polyline(self) -> None:
        """闭合多段线"""
        self._cpp_obj.ClosePolyline()

    def set_color(self, rgb: Sequence[int]) -> None:
        """设置当前颜色"""
        r, g, b = ensure_sequence_3(rgb)
        self._cpp_obj.SetColor(int(r), int(g), int(b))

add_property(name, ptype)

添加属性定义

Source code in dimine_python_sdk\lib\native\geometry.py
885
886
887
888
889
def add_property(self, name: str, ptype: str) -> None:
    """添加属性定义"""
    success, message = self._cpp_obj.AddProperty(str(name), str(ptype))
    if not success:
        raise NativeDBError(f"添加属性失败: {message}")

close_polyline()

闭合多段线

Source code in dimine_python_sdk\lib\native\geometry.py
891
892
893
def close_polyline(self) -> None:
    """闭合多段线"""
    self._cpp_obj.ClosePolyline()

create() classmethod

创建只读数据库

Source code in dimine_python_sdk\lib\native\geometry.py
714
715
716
717
@classmethod
def create(cls) -> "NativeDatabaseHandle":
    """创建只读数据库"""
    return cls(Dm.dmDbDatabase())

create_local() classmethod

创建可编辑本地数据库

Source code in dimine_python_sdk\lib\native\geometry.py
719
720
721
722
@classmethod
def create_local(cls) -> "NativeDatabaseHandle":
    """创建可编辑本地数据库"""
    return cls(Dm.dmDbDatabase.CreateLocalDB())

features()

获取所有要素定义(含属性定义清单)

Source code in dimine_python_sdk\lib\native\geometry.py
793
794
795
796
797
798
799
800
801
802
803
804
805
def features(self) -> list[NativeFeature]:
    """获取所有要素定义(含属性定义清单)"""
    cpp_features = self._cpp_obj.GetFeatureSet()
    if not cpp_features:
        return []
    features= [
        NativeFeature(
            name=f.GetFeatureName(),
            properties=self._extract_feature_properties(f),
        )
        for f in cpp_features
    ]
    return features

get_active_layer()

获取当前激活图层

Source code in dimine_python_sdk\lib\native\geometry.py
760
761
762
763
764
765
def get_active_layer(self) -> NativeLayerHandle | None:
    """获取当前激活图层"""
    cpp_layer = self._cpp_obj.GetActiveLayer()
    if not cpp_layer:
        return None
    return NativeLayerHandle(cpp_layer)

get_feature(name)

按名称获取要素

Source code in dimine_python_sdk\lib\native\geometry.py
779
780
781
782
783
784
785
786
787
def get_feature(self, name: str) -> NativeFeature | None:
    """按名称获取要素"""
    cpp_feature = self._cpp_obj.GetFeatureFromName(str(name))
    if not cpp_feature:
        return None
    return NativeFeature(
        name=cpp_feature.GetFeatureName(),
        properties=self._extract_feature_properties(cpp_feature),
    )

get_layer(index)

通过索引获取图层

Source code in dimine_python_sdk\lib\native\geometry.py
746
747
748
749
750
751
752
753
def get_layer(self, index: int) -> NativeLayerHandle:
    """通过索引获取图层"""
    if index < 0 or index >= self.layer_count:
        raise IndexError(f"图层索引 {index} 超出范围 [0, {self.layer_count})")
    cpp_layer = self._cpp_obj.GetLayerFromIndex(index)
    if not cpp_layer:
        raise NativeDBError(f"获取图层 {index} 返回空对象")
    return NativeLayerHandle(cpp_layer)

insert_feature(name)

插入新要素

Source code in dimine_python_sdk\lib\native\geometry.py
767
768
769
770
771
772
773
def insert_feature(self, name: str) -> NativeFeature:
    """插入新要素"""
    cpp_feature = self._cpp_obj.InsertFeature(str(name))
    return NativeFeature(
        name=cpp_feature.GetFeatureName(),
        properties=self._extract_feature_properties(cpp_feature),
    )

insert_layer(name)

插入新图层

Source code in dimine_python_sdk\lib\native\geometry.py
755
756
757
758
def insert_layer(self, name: str) -> NativeLayerHandle:
    """插入新图层"""
    cpp_layer = self._cpp_obj.InsertLayer(str(name))
    return NativeLayerHandle(cpp_layer)

load(file_path)

加载 DMF 文件

Source code in dimine_python_sdk\lib\native\geometry.py
724
725
726
727
def load(self, file_path: str) -> None:
    """加载 DMF 文件"""
    if not self._cpp_obj.Load(file_path):
        raise NativeDBError(f"加载 DMF 失败: {file_path}")

save(file_path=None)

保存 DMF 文件

Source code in dimine_python_sdk\lib\native\geometry.py
729
730
731
732
733
734
735
736
def save(self, file_path: str | None = None) -> None:
    """保存 DMF 文件"""
    if file_path is None:
        if not self._cpp_obj.Save():
            raise NativeDBError("保存 DMF 失败")
    else:
        if not self._cpp_obj.Save(file_path):
            raise NativeDBError(f"保存 DMF 失败: {file_path}")

set_active_feature(name)

设置当前激活要素

Source code in dimine_python_sdk\lib\native\geometry.py
789
790
791
def set_active_feature(self, name: str) -> None:
    """设置当前激活要素"""
    self._cpp_obj.SetActiveFeature(str(name))

set_color(rgb)

设置当前颜色

Source code in dimine_python_sdk\lib\native\geometry.py
895
896
897
898
def set_color(self, rgb: Sequence[int]) -> None:
    """设置当前颜色"""
    r, g, b = ensure_sequence_3(rgb)
    self._cpp_obj.SetColor(int(r), int(g), int(b))

set_features(features)

注册所有要素及其属性定义。

features 作为属性定义清单,直接写入各要素的 CDataTable; 不再依赖实体反向推导,也不调用 add_property

Source code in dimine_python_sdk\lib\native\geometry.py
807
808
809
810
811
812
813
814
815
816
817
def set_features(self, features: Sequence[NativeFeature]) -> None:
    """注册所有要素及其属性定义。

    以 ``features`` 作为属性定义清单,直接写入各要素的 CDataTable;
    不再依赖实体反向推导,也不调用 ``add_property``。
    """
    for feat in features:
        if not feat.name:
            continue
        cpp_feature = self._insert_feature_raw(feat.name)
        self._register_feature_properties(cpp_feature, feat.properties)

set_file_name(file_path)

设置文件路径

Source code in dimine_python_sdk\lib\native\geometry.py
738
739
740
def set_file_name(self, file_path: str) -> None:
    """设置文件路径"""
    self._cpp_obj.SetFileName(file_path)

NativeEntity dataclass

几何实体数据模型

Source code in dimine_python_sdk\lib\native\models.py
109
110
111
112
113
114
115
116
117
118
@dataclass
class NativeEntity:
    """几何实体数据模型"""

    entity_type: str         # "point" | "line" | "polyline" | "shell" | "text" | ...
    name: str = ""
    geometry: Optional["np.ndarray | NativeTin"] = None
    color: list[int] = field(default_factory=lambda: [0, 0, 0])
    properties: list[NativeProperty] = field(default_factory=list)
    feature_name: str = ""   # 所属要素名称

NativeEntityHandle

实体不透明句柄,内部持有 C++ dmDbEntity 对象。

警告:OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用。 当需要遍历图层中多个实体时,应使用 NativeLayerHandle.iter_entities(), 该函数会在进入下一次 OpenNextEntity() 之前把数据完整拷贝到 Python 对象。

Source code in dimine_python_sdk\lib\native\geometry.py
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
class NativeEntityHandle:
    """实体不透明句柄,内部持有 C++ dmDbEntity 对象。

    警告:OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用。
    当需要遍历图层中多个实体时,应使用 NativeLayerHandle.iter_entities(),
    该函数会在进入下一次 OpenNextEntity() 之前把数据完整拷贝到 Python 对象。
    """

    # 要素属性定义表中的元数据列,非用户自定义属性
    _ATT_META_COLUMNS = frozenset({"ent_handle", "实体类型", "实体名称", "XData"})

    def __init__(self, cpp_obj: Any):
        if cpp_obj is None:
            raise Exception("cpp obj is None.")
        self._cpp_obj = cpp_obj


    def __repr__(self) -> str:
        return f"NativeEntityHandle(type_code={self.type_code}, name={self.name!r})"

    @property
    def type_code(self) -> int:
        return self._cpp_obj.GetType()

    @property
    def type_name(self) -> str:
        return _type_code_to_name(self.type_code)

    @property
    def name(self) -> str:
        try:
            return self._cpp_obj.GetEntityName() or ""
        except Exception as exc:
            raise NativeGeometryError(f"读取实体名称失败: {exc}") from exc

    @name.setter
    def name(self, value: str) -> None:
        self._cpp_obj.SetEntityName(str(value))

    @property
    def color(self) -> list[int]:
        try:
            color = self._cpp_obj.GetColor()
            r, g, b = int(color[0]), int(color[1]), int(color[2])
            return [r, g, b]
        except Exception as exc:
            raise NativeGeometryError(f"读取实体颜色失败: {exc}") from exc

    @color.setter
    def color(self, rgb: Sequence[int]) -> None:
        r, g, b = ensure_sequence_3(rgb)
        self._cpp_obj.SetColor(int(r), int(g), int(b))

    def att_record(self) -> tuple[str, list[NativeProperty]]:
        """读取实体属性记录

        返回 (所属要素名称, 属性列表)。
        属性列的数据类型通过 ``NativeDataTableHandle.field_definitions()``
        调用 ``Get_Field_Type`` 获取,不再从首行记录推断;实体属性记录
        (record)中存放的是对应字段的真实属性值。record 仅提供
        asDouble/asString 两种读取接口,字符串类用 asString,其余数值型
        统一用 asDouble。
        """
        props: list[NativeProperty] = []
        try:
            record = self._cpp_obj.GetAttRecord()
        except Exception as exc:
            raise NativeDBError(f"获取属性记录失败: {exc}") from exc
        if record is None:
            return "", props

        try:
            feature = self._cpp_obj.GetFeatureSet()
            if feature is None:
                return "", props
            feature_name = feature.GetFeatureName() or ""

            dt = feature.GetDataTable()
            if dt is None:
                return feature_name, props
            table = NativeDataTableHandle(dt)

            for field_def in table.field_definitions():
                name = field_def.name
                if name in self._ATT_META_COLUMNS:
                    continue

                type_code = field_def.type if isinstance(field_def.type, int) else 7
                ptype = _FIELD_TYPE_TO_PROPERTY_TYPE.get(type_code, "double")
                value: Any
                if ptype == "string":
                    value = record.asString(name)
                elif ptype == "date":
                    value = datetime.strptime(record.asString(name), "%Y-%m-%d %H:%M")
                else:
                    # byte/short/int/long/float/double 等数值型统一用 asDouble
                    value = record.asDouble(name)

                props.append(NativeProperty(name=name, value=value, type=ptype))
            return feature_name, props
        except Exception as exc:
            raise NativeDBError(f"读取实体属性记录失败: {exc}") from exc

    # 数值型属性类型集合,写入属性记录时统一按 double 处理
    _NUMERIC_PROPERTY_TYPES = {"byte", "short", "int", "long", "float", "double"}

    def set_properties(self, properties: list[NativeProperty]) -> None:
        """将 NativeProperty 列表写入 C++ 实体属性记录。

        与 ``att_record`` 互为逆过程:先获取 ``self._cpp_obj.GetAttRecord()``,
        再对记录中的每个字段调用 ``Set_Value`` 写入真实属性值。
        单条属性写入失败不会中断整体写入。
        """
        if not properties:
            return

        try:
            record = self._cpp_obj.GetAttRecord()
        except Exception as exc:
            raise NativeDBError(f"获取属性记录失败: {exc}") from exc
        if record is None:
            return

        for prop in properties:
            if prop.value is None or prop.name == "text":
                continue
            try:
                if (prop.type or "string") in self._NUMERIC_PROPERTY_TYPES:
                    record.Set_Value(prop.name, float(prop.value))
                elif prop.type == "date":
                    if isinstance(prop.value, datetime):
                        record.Set_Value(prop.name, prop.value.strftime("%Y-%m-%d 0:0"))
                    else:
                        record.Set_Value(prop.name, str(prop.value))
                else:
                    record.Set_Value(prop.name, str(prop.value))
            except Exception:
                pass

    @staticmethod
    def _polydata_points(polydata: Any) -> "np.ndarray":
        """提取 polydata 中的顶点坐标"""
        import numpy as np

        n = polydata.GetNumberOfPoints()
        if n == 0:
            return np.zeros((0, 3), dtype=float)
        pts = []
        for i in range(n):
            pt = polydata.GetPoint(i)
            pts.append([float(pt.x), float(pt.y), float(pt.z)])
        return np.array(pts, dtype=float)

    def geometry(self) -> "np.ndarray | NativeTin":
        """读取实体几何数据"""
        import numpy as np

        tcode = self.type_code
        if tcode == _type_name_to_code("text"):
            try:
                polydata = self._cpp_obj.ToPolyData()
                pts = self._polydata_points(polydata)
                if len(pts) > 0:
                    return pts[0]
            except Exception:
                pass
            return ensure_array_3d([0, 0, 0])

        if tcode == _type_name_to_code("shell"):
            try:
                shell = self._cpp_obj.ConvertToShell()
                data = json.loads(shell.ParseToJson())
                points = np.array(data["points"], dtype=float).reshape(-1, 3)
                faces = np.array(data["indexs"], dtype=int).reshape(-1, 3)
                return NativeTin(points=points, faces=faces)
            except Exception:
                pass

        try:
            polydata = self._cpp_obj.ToPolyData()
            pts = self._polydata_points(polydata)
            if tcode == _type_name_to_code("point") and pts.shape[0] > 0:
                return pts[0]
            return pts
        except Exception as exc:
            raise NativeGeometryError(f"读取实体几何失败: {exc}") from exc

    def to_model(self) -> "NativeEntity | NativeText":
        """转换为 NativeEntity 或 NativeText 数据模型

        对于文本实体(type_name == "text"),通过 ConvertToText() 将
        dmDbEntity 转为 dmDbText,读取文本位置、内容、高度、旋转角、
        厚度、面向用户、法线等属性,返回 NativeText。
        """
        if self.type_name == "text":
            return self._to_text_model()
        elif self.type_name == "mtext":
            return self._to_mtext_model()

        feature_name, props = self.att_record()
        return NativeEntity(
            entity_type=self.type_name,
            name=self.name,
            geometry=self.geometry(),
            color=self.color,
            properties=props,
            feature_name=feature_name,
        )

    def _to_text_model(self) -> "NativeText":
        """将文本实体转换为 NativeText 数据模型

        通过 ConvertToText() 将 dmDbEntity 转为 dmDbText,
        然后读取文本位置、内容、高度、旋转角、厚度、面向用户、法线等属性。
        """
        import numpy as np

        text_obj = self._cpp_obj.ConvertToText()

        pos = text_obj.GetPosition()
        text = text_obj.GetText() or ""
        height = text_obj.GetHeight()
        rotation = text_obj.GetRotation()
        thickness = text_obj.GetThickness()
        face2_user = text_obj.IsFace2User()

        try:
            normal = text_obj.GetNormal()
            normal_arr = np.array([normal.x, normal.y, normal.z], dtype=float)
        except Exception:
            normal_arr = np.array([0, 0, 1], dtype=float)

        return NativeText(
            position=np.array([pos.x, pos.y, pos.z], dtype=float),
            color=self.color,
            text=text,
            height=height,
            rotation=rotation,
            thickness=thickness,
            face2_user=face2_user,
            normal=normal_arr,
        )


    def _to_mtext_model(self) -> "NativeText":
        """将多行文本实体转换为 NativeText 数据模型

        通过 ConvertToMText() 将 dmDbEntity 转为 dmDbMText,
        读取位置(Location)、内容、字高(TextHeight)、旋转角、倾斜角、
        厚度、文本框宽度、方向向量、法线等属性。
        多行文本无 face2_user 属性,始终为 False。
        """
        import numpy as np

        text_obj = self._cpp_obj.ConvertToMText()

        # --- 位置 ---
        loc = text_obj.GetLocation()
        position = np.array([loc.x, loc.y, loc.z], dtype=float)

        # --- 文本内容 ---
        text = text_obj.GetText() or ""

        # --- 字高 ---
        height = text_obj.GetTextHeight()

        # --- 旋转角 ---
        rotation = text_obj.GetRotation()

        # --- 倾斜角 ---
        try:
            oblique = text_obj.GetOblique()
        except Exception:
            oblique = 0.0

        # --- 厚度 ---
        thickness = text_obj.GetThickness()

        # --- 文本框宽度 ---
        try:
            width = text_obj.GetWidth()
        except Exception:
            width = 0.0

        # --- 法线 ---
        try:
            normal = text_obj.GetNormal()
            normal_arr = np.array([normal.x, normal.y, normal.z], dtype=float)
        except Exception:
            normal_arr = np.array([0, 0, 1], dtype=float)

        # --- 方向向量 ---
        try:
            direction = text_obj.GetDirection()
            direction_arr = np.array(
                [direction.x, direction.y, direction.z], dtype=float
            )
        except Exception:
            direction_arr = np.array([1, 0, 0], dtype=float)

        return NativeText(
            position=position,
            color=self.color,
            text=text,
            height=height,
            rotation=rotation,
            oblique=oblique,
            thickness=thickness,
            width=width,
            face2_user=False,
            normal=normal_arr,
            direction=direction_arr,
        )

att_record()

读取实体属性记录

返回 (所属要素名称, 属性列表)。 属性列的数据类型通过 NativeDataTableHandle.field_definitions() 调用 Get_Field_Type 获取,不再从首行记录推断;实体属性记录 (record)中存放的是对应字段的真实属性值。record 仅提供 asDouble/asString 两种读取接口,字符串类用 asString,其余数值型 统一用 asDouble。

Source code in dimine_python_sdk\lib\native\geometry.py
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
def att_record(self) -> tuple[str, list[NativeProperty]]:
    """读取实体属性记录

    返回 (所属要素名称, 属性列表)。
    属性列的数据类型通过 ``NativeDataTableHandle.field_definitions()``
    调用 ``Get_Field_Type`` 获取,不再从首行记录推断;实体属性记录
    (record)中存放的是对应字段的真实属性值。record 仅提供
    asDouble/asString 两种读取接口,字符串类用 asString,其余数值型
    统一用 asDouble。
    """
    props: list[NativeProperty] = []
    try:
        record = self._cpp_obj.GetAttRecord()
    except Exception as exc:
        raise NativeDBError(f"获取属性记录失败: {exc}") from exc
    if record is None:
        return "", props

    try:
        feature = self._cpp_obj.GetFeatureSet()
        if feature is None:
            return "", props
        feature_name = feature.GetFeatureName() or ""

        dt = feature.GetDataTable()
        if dt is None:
            return feature_name, props
        table = NativeDataTableHandle(dt)

        for field_def in table.field_definitions():
            name = field_def.name
            if name in self._ATT_META_COLUMNS:
                continue

            type_code = field_def.type if isinstance(field_def.type, int) else 7
            ptype = _FIELD_TYPE_TO_PROPERTY_TYPE.get(type_code, "double")
            value: Any
            if ptype == "string":
                value = record.asString(name)
            elif ptype == "date":
                value = datetime.strptime(record.asString(name), "%Y-%m-%d %H:%M")
            else:
                # byte/short/int/long/float/double 等数值型统一用 asDouble
                value = record.asDouble(name)

            props.append(NativeProperty(name=name, value=value, type=ptype))
        return feature_name, props
    except Exception as exc:
        raise NativeDBError(f"读取实体属性记录失败: {exc}") from exc

geometry()

读取实体几何数据

Source code in dimine_python_sdk\lib\native\geometry.py
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
def geometry(self) -> "np.ndarray | NativeTin":
    """读取实体几何数据"""
    import numpy as np

    tcode = self.type_code
    if tcode == _type_name_to_code("text"):
        try:
            polydata = self._cpp_obj.ToPolyData()
            pts = self._polydata_points(polydata)
            if len(pts) > 0:
                return pts[0]
        except Exception:
            pass
        return ensure_array_3d([0, 0, 0])

    if tcode == _type_name_to_code("shell"):
        try:
            shell = self._cpp_obj.ConvertToShell()
            data = json.loads(shell.ParseToJson())
            points = np.array(data["points"], dtype=float).reshape(-1, 3)
            faces = np.array(data["indexs"], dtype=int).reshape(-1, 3)
            return NativeTin(points=points, faces=faces)
        except Exception:
            pass

    try:
        polydata = self._cpp_obj.ToPolyData()
        pts = self._polydata_points(polydata)
        if tcode == _type_name_to_code("point") and pts.shape[0] > 0:
            return pts[0]
        return pts
    except Exception as exc:
        raise NativeGeometryError(f"读取实体几何失败: {exc}") from exc

set_properties(properties)

将 NativeProperty 列表写入 C++ 实体属性记录。

att_record 互为逆过程:先获取 self._cpp_obj.GetAttRecord(), 再对记录中的每个字段调用 Set_Value 写入真实属性值。 单条属性写入失败不会中断整体写入。

Source code in dimine_python_sdk\lib\native\geometry.py
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
def set_properties(self, properties: list[NativeProperty]) -> None:
    """将 NativeProperty 列表写入 C++ 实体属性记录。

    与 ``att_record`` 互为逆过程:先获取 ``self._cpp_obj.GetAttRecord()``,
    再对记录中的每个字段调用 ``Set_Value`` 写入真实属性值。
    单条属性写入失败不会中断整体写入。
    """
    if not properties:
        return

    try:
        record = self._cpp_obj.GetAttRecord()
    except Exception as exc:
        raise NativeDBError(f"获取属性记录失败: {exc}") from exc
    if record is None:
        return

    for prop in properties:
        if prop.value is None or prop.name == "text":
            continue
        try:
            if (prop.type or "string") in self._NUMERIC_PROPERTY_TYPES:
                record.Set_Value(prop.name, float(prop.value))
            elif prop.type == "date":
                if isinstance(prop.value, datetime):
                    record.Set_Value(prop.name, prop.value.strftime("%Y-%m-%d 0:0"))
                else:
                    record.Set_Value(prop.name, str(prop.value))
            else:
                record.Set_Value(prop.name, str(prop.value))
        except Exception:
            pass

to_model()

转换为 NativeEntity 或 NativeText 数据模型

对于文本实体(type_name == "text"),通过 ConvertToText() 将 dmDbEntity 转为 dmDbText,读取文本位置、内容、高度、旋转角、 厚度、面向用户、法线等属性,返回 NativeText。

Source code in dimine_python_sdk\lib\native\geometry.py
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
def to_model(self) -> "NativeEntity | NativeText":
    """转换为 NativeEntity 或 NativeText 数据模型

    对于文本实体(type_name == "text"),通过 ConvertToText() 将
    dmDbEntity 转为 dmDbText,读取文本位置、内容、高度、旋转角、
    厚度、面向用户、法线等属性,返回 NativeText。
    """
    if self.type_name == "text":
        return self._to_text_model()
    elif self.type_name == "mtext":
        return self._to_mtext_model()

    feature_name, props = self.att_record()
    return NativeEntity(
        entity_type=self.type_name,
        name=self.name,
        geometry=self.geometry(),
        color=self.color,
        properties=props,
        feature_name=feature_name,
    )

NativeExploitationError

Bases: NativeModelError

巷道/轮廓建模异常

Source code in dimine_python_sdk\lib\native\_base.py
73
74
75
76
class NativeExploitationError(NativeModelError):
    """巷道/轮廓建模异常"""

    pass

NativeFeature dataclass

DMF 要素定义

Source code in dimine_python_sdk\lib\native\models.py
152
153
154
155
156
157
@dataclass
class NativeFeature:
    """DMF 要素定义"""

    name: str
    properties: list[NativeProperty] = field(default_factory=list)

NativeFieldDef dataclass

字段定义

Attributes:

Name Type Description
name str

字段名称。

type int | str | float

C++ 类型编号(0-22),见 _DM_TYPE_MAP。

type_name str

只读,C++ 类型宏名称,如 "DM_INT"、"DM_DOUBLE"。

python_type type

只读,对应的 Python 类型,如 int、float、str、bool。

Source code in dimine_python_sdk\lib\native\models.py
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
@dataclass
class NativeFieldDef:
    """字段定义

    Attributes:
        name: 字段名称。
        type: C++ 类型编号(0-22),见 _DM_TYPE_MAP。
        type_name: 只读,C++ 类型宏名称,如 "DM_INT"、"DM_DOUBLE"。
        python_type: 只读,对应的 Python 类型,如 int、float、str、bool。
    """

    name: str
    type: int | str | float = "string"

    @property
    def type_name(self) -> str:
        """C++ 类型宏名称,如 'DM_INT'、'DM_DOUBLE'"""
        return _DM_TYPE_TO_NAME.get(int(self.type), f"UNKNOWN({self.type})")

    @property
    def python_type(self) -> type:
        """对应的 Python 类型"""
        return _DM_TYPE_TO_PYTHON.get(int(self.type), object)

python_type property

对应的 Python 类型

type_name property

C++ 类型宏名称,如 'DM_INT'、'DM_DOUBLE'

NativeFieldType

Bases: IntEnum

CDataTable 字段类型编码

Source code in dimine_python_sdk\lib\native\data_table.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class NativeFieldType(IntEnum):
    """CDataTable 字段类型编码"""

    UNKNOWN = 0
    BYTE = 1
    SHORT = 2
    INT = 3
    LONG = 4
    FLOAT = 5
    DOUBLE = 6
    STRING = 7
    COLOR = 8
    DATE = 9
    BINARY = 10
    LONG64 = 11

NativeGeometryError

Bases: NativeModelError

几何/实体/图层/数据库操作异常

Source code in dimine_python_sdk\lib\native\_base.py
37
38
39
40
class NativeGeometryError(NativeModelError):
    """几何/实体/图层/数据库操作异常"""

    pass

NativeIOError

Bases: NativeModelError

文件转换/出图/IO 异常

Source code in dimine_python_sdk\lib\native\_base.py
55
56
57
58
class NativeIOError(NativeModelError):
    """文件转换/出图/IO 异常"""

    pass

NativeLayer dataclass

DMF 图层数据模型

Source code in dimine_python_sdk\lib\native\models.py
160
161
162
163
164
165
@dataclass
class NativeLayer:
    """DMF 图层数据模型"""

    name: str
    entities: "list[NativeEntity | NativeText]" = field(default_factory=list)

NativeLayerHandle

图层不透明句柄,内部持有 C++ dmDbLayer 对象

Source code in dimine_python_sdk\lib\native\geometry.py
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
class NativeLayerHandle:
    """图层不透明句柄,内部持有 C++ dmDbLayer 对象"""

    def __init__(self, cpp_obj: Any):
        self._cpp_obj = cpp_obj

    def __repr__(self) -> str:
        return f"NativeLayerHandle(name={self.name!r}, entities={self.entity_count})"

    @property
    def name(self) -> str:
        raw = self._cpp_obj.GetLayerName()
        return raw if isinstance(raw, str) else ""

    @property
    def entity_count(self) -> int:
        return self._cpp_obj.GetEntitiesCount()

    def iter_entities(self) -> "Iterator[NativeEntity | NativeText]":
        """迭代图层中所有实体,返回 NativeEntity 或 NativeText

        OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用,
        一旦进入下一次 OpenNextEntity(),之前的引用即可能失效。
        因此这里一次性把每个实体的数据拷贝到 Python 对象,并立即释放
        底层 C++ 引用后再读取下一个实体。

        文本实体会返回 NativeText,其余类型返回 NativeEntity。
        """
        self._cpp_obj.StartQueryEntity()
        results: "list[NativeEntity | NativeText]" = []
        raw = self._cpp_obj.OpenNextEntity()
        while raw:
            results.append(NativeEntityHandle(raw).to_model())
            raw = self._cpp_obj.OpenNextEntity()
        return iter(results)

    def _insert_point_raw(self, position: "np.ndarray") -> NativeEntityHandle:
        """插入点,返回实体句柄"""
        cpp_entity = self._cpp_obj.InsertPoint(point_to_native(position))
        return NativeEntityHandle(cpp_entity)

    def _insert_line_raw(
        self, start: "np.ndarray", end: "np.ndarray"
    ) -> NativeEntityHandle:
        """插入直线,返回实体句柄"""
        cpp_entity = self._cpp_obj.InsertLine(
            point_to_native(start), point_to_native(end)
        )
        return NativeEntityHandle(cpp_entity)

    def _insert_polyline_raw(self, points: "np.ndarray") -> NativeEntityHandle:
        """插入多段线,返回实体句柄"""
        cpp_entity = self._cpp_obj.InsertPolyline(points_to_native(points))
        return NativeEntityHandle(cpp_entity)


    def _insert_shell_raw(self, tin: NativeTin) -> NativeEntityHandle:
        """插入 Shell,返回实体句柄"""
        polydata = tin_to_polydata(tin)
        cpp_entity = self._cpp_obj.InsertShell(polydata)
        return NativeEntityHandle(cpp_entity)

    def _insert_text_raw(
        self, position: "np.ndarray", text: str
    ) -> NativeEntityHandle:
        """插入文本,返回实体句柄"""
        cpp_entity = self._cpp_obj.InsertText(point_to_native(position), str(text))
        return NativeEntityHandle(cpp_entity)


    def insert_native_entity(self, entity: "NativeEntity | NativeText") -> NativeEntityHandle:
        """根据 NativeEntity 或 NativeText 数据模型插入实体,并返回实体句柄

        插入几何后会通过返回的 ``NativeEntityHandle`` 设置实体名称、颜色,
        并以 ``att_record`` 的反向操作将属性值写入 C++ 属性记录。
        """
        # NativeText 直接写入文本实体
        if isinstance(entity, NativeText):
            handle = self._insert_text_raw(entity.position, entity.text)
            return handle

        etype = entity.entity_type
        if etype == "point":
            handle = self._insert_point_raw(ensure_array_3d(entity.geometry))
        elif etype == "line":
            pts = ensure_points(entity.geometry)
            if len(pts) != 2:
                raise NativeGeometryError("line 实体需要 2 个顶点")
            handle = self._insert_line_raw(pts[0], pts[1])
        elif etype in ("polyline", "polygon"):
            handle = self._insert_polyline_raw(ensure_points(entity.geometry))
        elif etype == "shell":
            tin = entity.geometry
            if not isinstance(tin, NativeTin):
                raise NativeGeometryError("shell 实体 geometry 必须为 NativeTin")
            handle = self._insert_shell_raw(tin)
        elif etype == "text":
            pos = ensure_array_3d(entity.geometry)
            text = ""
            for prop in entity.properties:
                if prop.name == "text":
                    text = str(prop.value or "")
                    break
            handle = self._insert_text_raw(pos, text)
        else:
            raise NativeGeometryError(f"不支持的实体类型: {etype}")

        if entity.name:
            handle.name = entity.name
        if entity.color:
            handle.color = entity.color
        handle.set_properties(entity.properties)
        return handle

    def insert_entities(
        self, entities: "Sequence[NativeEntity | NativeText]"
    ) -> list[NativeEntityHandle]:
        """批量插入 NativeEntity 或 NativeText,返回实体句柄列表"""
        return [self.insert_native_entity(e) for e in entities]

    def to_model(self) -> NativeLayer:
        """转换为 NativeLayer 数据模型"""
        return NativeLayer(name=self.name, entities=list(self.iter_entities()))

insert_entities(entities)

批量插入 NativeEntity 或 NativeText,返回实体句柄列表

Source code in dimine_python_sdk\lib\native\geometry.py
690
691
692
693
694
def insert_entities(
    self, entities: "Sequence[NativeEntity | NativeText]"
) -> list[NativeEntityHandle]:
    """批量插入 NativeEntity 或 NativeText,返回实体句柄列表"""
    return [self.insert_native_entity(e) for e in entities]

insert_native_entity(entity)

根据 NativeEntity 或 NativeText 数据模型插入实体,并返回实体句柄

插入几何后会通过返回的 NativeEntityHandle 设置实体名称、颜色, 并以 att_record 的反向操作将属性值写入 C++ 属性记录。

Source code in dimine_python_sdk\lib\native\geometry.py
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
def insert_native_entity(self, entity: "NativeEntity | NativeText") -> NativeEntityHandle:
    """根据 NativeEntity 或 NativeText 数据模型插入实体,并返回实体句柄

    插入几何后会通过返回的 ``NativeEntityHandle`` 设置实体名称、颜色,
    并以 ``att_record`` 的反向操作将属性值写入 C++ 属性记录。
    """
    # NativeText 直接写入文本实体
    if isinstance(entity, NativeText):
        handle = self._insert_text_raw(entity.position, entity.text)
        return handle

    etype = entity.entity_type
    if etype == "point":
        handle = self._insert_point_raw(ensure_array_3d(entity.geometry))
    elif etype == "line":
        pts = ensure_points(entity.geometry)
        if len(pts) != 2:
            raise NativeGeometryError("line 实体需要 2 个顶点")
        handle = self._insert_line_raw(pts[0], pts[1])
    elif etype in ("polyline", "polygon"):
        handle = self._insert_polyline_raw(ensure_points(entity.geometry))
    elif etype == "shell":
        tin = entity.geometry
        if not isinstance(tin, NativeTin):
            raise NativeGeometryError("shell 实体 geometry 必须为 NativeTin")
        handle = self._insert_shell_raw(tin)
    elif etype == "text":
        pos = ensure_array_3d(entity.geometry)
        text = ""
        for prop in entity.properties:
            if prop.name == "text":
                text = str(prop.value or "")
                break
        handle = self._insert_text_raw(pos, text)
    else:
        raise NativeGeometryError(f"不支持的实体类型: {etype}")

    if entity.name:
        handle.name = entity.name
    if entity.color:
        handle.color = entity.color
    handle.set_properties(entity.properties)
    return handle

iter_entities()

迭代图层中所有实体,返回 NativeEntity 或 NativeText

OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用, 一旦进入下一次 OpenNextEntity(),之前的引用即可能失效。 因此这里一次性把每个实体的数据拷贝到 Python 对象,并立即释放 底层 C++ 引用后再读取下一个实体。

文本实体会返回 NativeText,其余类型返回 NativeEntity。

Source code in dimine_python_sdk\lib\native\geometry.py
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
def iter_entities(self) -> "Iterator[NativeEntity | NativeText]":
    """迭代图层中所有实体,返回 NativeEntity 或 NativeText

    OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用,
    一旦进入下一次 OpenNextEntity(),之前的引用即可能失效。
    因此这里一次性把每个实体的数据拷贝到 Python 对象,并立即释放
    底层 C++ 引用后再读取下一个实体。

    文本实体会返回 NativeText,其余类型返回 NativeEntity。
    """
    self._cpp_obj.StartQueryEntity()
    results: "list[NativeEntity | NativeText]" = []
    raw = self._cpp_obj.OpenNextEntity()
    while raw:
        results.append(NativeEntityHandle(raw).to_model())
        raw = self._cpp_obj.OpenNextEntity()
    return iter(results)

to_model()

转换为 NativeLayer 数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
696
697
698
def to_model(self) -> NativeLayer:
    """转换为 NativeLayer 数据模型"""
    return NativeLayer(name=self.name, entities=list(self.iter_entities()))

NativeModelError

Bases: RuntimeError

Native v2 异常基类

Source code in dimine_python_sdk\lib\native\_base.py
31
32
33
34
class NativeModelError(RuntimeError):
    """Native v2 异常基类"""

    pass

NativeProcessError

Bases: NativeModelError

JSON 处理函数返回 failed 时抛出,保留 response 字典。

Source code in dimine_python_sdk\lib\native\_base.py
79
80
81
82
83
84
85
86
class NativeProcessError(NativeModelError):
    """
    JSON 处理函数返回 failed 时抛出,保留 response 字典。
    """

    def __init__(self, message: str, response: dict | None = None):
        super().__init__(message)
        self.response = response

NativeProperty dataclass

属性键值对

Source code in dimine_python_sdk\lib\native\models.py
59
60
61
62
63
64
65
@dataclass
class NativeProperty:
    """属性键值对"""

    name: str
    value: str | int | float | datetime | None = None
    type: PropertyType = "string"

NativeProspectingError

Bases: NativeModelError

钻孔数据库/块段模型异常

Source code in dimine_python_sdk\lib\native\_base.py
67
68
69
70
class NativeProspectingError(NativeModelError):
    """钻孔数据库/块段模型异常"""

    pass

NativeText dataclass

文本实体数据模型(单行文本 / 多行文本共用)

多行文本(mtext)相比单行文本(text)额外支持: oblique(倾斜角)、width(文本框宽度)、direction(文本方向向量)。 同时多行文本无 face2_user 属性,始终为 False。

Source code in dimine_python_sdk\lib\native\models.py
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
@dataclass
class NativeText:
    """文本实体数据模型(单行文本 / 多行文本共用)

    多行文本(mtext)相比单行文本(text)额外支持:
    oblique(倾斜角)、width(文本框宽度)、direction(文本方向向量)。
    同时多行文本无 face2_user 属性,始终为 False。
    """

    position: "np.ndarray"  # shape (3,)
    text: str
    color: list[int] = field(default_factory=lambda: [0, 0, 0])
    """文本颜色 [r, g, b],从 NativeEntityHandle.color 获取"""
    height: float = 20.0
    rotation: float = 0.0
    thickness: float = 0.0
    face2_user: bool = False
    normal: "np.ndarray" = field(
        default_factory=lambda: np.array([0, 0, 1]) if np is not None else [0, 0, 1]
    )
    # ---- 以下为多行文本(mtext)专有字段 ----
    oblique: float = 0.0
    """倾斜角(度),仅多行文本有效"""
    width: float = 0.0
    """文本框宽度,仅多行文本有效"""
    direction: "np.ndarray" = field(
        default_factory=lambda: np.array([1, 0, 0]) if np is not None else [1, 0, 0]
    )
    """文本方向向量 shape (3,),仅多行文本有效"""

color = field(default_factory=(lambda: [0, 0, 0])) class-attribute instance-attribute

文本颜色 [r, g, b],从 NativeEntityHandle.color 获取

direction = field(default_factory=(lambda: np.array([1, 0, 0]) if np is not None else [1, 0, 0])) class-attribute instance-attribute

文本方向向量 shape (3,),仅多行文本有效

oblique = 0.0 class-attribute instance-attribute

倾斜角(度),仅多行文本有效

width = 0.0 class-attribute instance-attribute

文本框宽度,仅多行文本有效

NativeTextHandle

文本实体不透明句柄,内部持有 C++ dmDbText 对象

Source code in dimine_python_sdk\lib\native\io.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
class NativeTextHandle:
    """文本实体不透明句柄,内部持有 C++ dmDbText 对象"""

    def __init__(self, cpp_obj: Any):
        self._cpp_obj = cpp_obj

    @classmethod
    def create(cls) -> "NativeTextHandle":
        """创建文本实体"""
        # 运行时从 _core 获取 Dm,避免测试 mock 替换后缓存旧对象
        from dimine_python_sdk.lib.native._core import Dm

        return cls(Dm.dmDbText())

    def to_model(self) -> NativeText:
        """转换为 NativeText 数据模型"""
        import numpy as np

        pos = self._cpp_obj.GetPosition()
        try:
            normal = self._cpp_obj.GetNormal()
            normal_arr = np.array([normal.x, normal.y, normal.z], dtype=float)
        except Exception as exc:
            raise NativeIOError(f"读取文本法线失败: {exc}") from exc

        return NativeText(
            position=np.array([pos.x, pos.y, pos.z], dtype=float),
            text=self._cpp_obj.GetText() or "",
            height=self._cpp_obj.GetHeight(),
            rotation=self._cpp_obj.GetRotation(),
            thickness=self._cpp_obj.GetThickness(),
            face2_user=self._cpp_obj.IsFace2User(),
            normal=normal_arr,
        )

    @property
    def position(self) -> "np.ndarray":
        pos = self._cpp_obj.GetPosition()
        import numpy as np

        return np.array([pos.x, pos.y, pos.z], dtype=float)

    @position.setter
    def position(self, value: "np.ndarray") -> None:
        self._cpp_obj.SetPosition(_geom.point_to_native(value))

    @property
    def text(self) -> str:
        return self._cpp_obj.GetText() or ""

    @text.setter
    def text(self, value: str) -> None:
        self._cpp_obj.SetText(str(value))

    @property
    def height(self) -> float:
        return self._cpp_obj.GetHeight()

    @height.setter
    def height(self, value: float) -> None:
        self._cpp_obj.SetHeight(float(value))

    @property
    def rotation(self) -> float:
        return self._cpp_obj.GetRotation()

    @rotation.setter
    def rotation(self, value: float) -> None:
        self._cpp_obj.SetRotation(float(value))

    @property
    def thickness(self) -> float:
        return self._cpp_obj.GetThickness()

    @thickness.setter
    def thickness(self, value: float) -> None:
        self._cpp_obj.SetThickness(float(value))

    @property
    def face2_user(self) -> bool:
        return self._cpp_obj.IsFace2User()

    @face2_user.setter
    def face2_user(self, value: bool) -> None:
        self._cpp_obj.SetFace2User(bool(value))

    def set_normal(self) -> None:
        """自动计算法线方向"""
        self._cpp_obj.SetNormal()

create() classmethod

创建文本实体

Source code in dimine_python_sdk\lib\native\io.py
 98
 99
100
101
102
103
104
@classmethod
def create(cls) -> "NativeTextHandle":
    """创建文本实体"""
    # 运行时从 _core 获取 Dm,避免测试 mock 替换后缓存旧对象
    from dimine_python_sdk.lib.native._core import Dm

    return cls(Dm.dmDbText())

set_normal()

自动计算法线方向

Source code in dimine_python_sdk\lib\native\io.py
178
179
180
def set_normal(self) -> None:
    """自动计算法线方向"""
    self._cpp_obj.SetNormal()

to_model()

转换为 NativeText 数据模型

Source code in dimine_python_sdk\lib\native\io.py
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
def to_model(self) -> NativeText:
    """转换为 NativeText 数据模型"""
    import numpy as np

    pos = self._cpp_obj.GetPosition()
    try:
        normal = self._cpp_obj.GetNormal()
        normal_arr = np.array([normal.x, normal.y, normal.z], dtype=float)
    except Exception as exc:
        raise NativeIOError(f"读取文本法线失败: {exc}") from exc

    return NativeText(
        position=np.array([pos.x, pos.y, pos.z], dtype=float),
        text=self._cpp_obj.GetText() or "",
        height=self._cpp_obj.GetHeight(),
        rotation=self._cpp_obj.GetRotation(),
        thickness=self._cpp_obj.GetThickness(),
        face2_user=self._cpp_obj.IsFace2User(),
        normal=normal_arr,
    )

NativeTin dataclass

三角网模型

Source code in dimine_python_sdk\lib\native\models.py
93
94
95
96
97
98
@dataclass
class NativeTin:
    """三角网模型"""

    points: "np.ndarray"  # shape (N, 3)
    faces: "np.ndarray"   # shape (M, 3)

block_constrain_to_dmc_file(block_model_file, constraint_json, output_file)

块约束保存到约束结果 dmc 文件

Source code in dimine_python_sdk\lib\native\prospecting.py
757
758
759
760
761
762
763
764
765
766
767
def block_constrain_to_dmc_file(
    block_model_file: str,
    constraint_json: str,
    output_file: str,
) -> None:
    """块约束保存到约束结果 dmc 文件"""
    ok = Dm.BlockConstrainToDmcFile(block_model_file, constraint_json, output_file)
    if not ok:
        raise NativeProspectingError(
            f"块约束保存失败: {block_model_file} -> {output_file}"
        )

calculate_min_rectangle_2d(points, bounds)

计算二维点集最小外接矩形。

Parameters:

Name Type Description Default
points 'np.ndarray'

形状 (N, 3) 或 (N, 2)

required
bounds Sequence[float]

边界约束 [min_x, min_y, max_x, max_y]

required

Returns:

Type Description
'np.ndarray'

矩形角点 (4, 3)

Source code in dimine_python_sdk\lib\native\algorithm.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def calculate_min_rectangle_2d(points: "np.ndarray", bounds: Sequence[float]) -> "np.ndarray":
    """
    计算二维点集最小外接矩形。

    Args:
        points: 形状 (N, 3) 或 (N, 2)
        bounds: 边界约束 [min_x, min_y, max_x, max_y]

    Returns:
        矩形角点 (4, 3)
    """
    arr = ensure_points(points)
    cpp_points = _geom.points_to_native(arr)
    cpp_result = Dm.thModelFunc.CalcultateMinRectangle2D(cpp_points, list(bounds))
    return _geom.points_from_native(cpp_result)

calculate_reserves(block_model_file, constraint_json, reserve_json)

储量计算

Source code in dimine_python_sdk\lib\native\prospecting.py
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
def calculate_reserves(
    block_model_file: str,
    constraint_json: str,
    reserve_json: str,
) -> dict:
    """储量计算"""
    constraint_params = _serialize_constraints(constraint_json)
    reserve_params = _serialize_param(reserve_json)
    logger.debug(
        "Dm.ReservesCalculate 入参:\n"
        "  block_model_file: %s\n"
        "  constraints: %s\n"
        "  reserves: %s",
        block_model_file,
        constraint_params,
        reserve_params,
    )
    result = Dm.ReservesCalculate(
        block_model_file,
        constraint_params,
        reserve_params,
    )
    message = check_bool_message(result, NativeProspectingError, "储量计算")
    return {"success": True, "message": message}

contour_extrapolate_modeling(param)

轮廓线外推建模

Source code in dimine_python_sdk\lib\native\exploitation.py
77
78
79
80
81
82
83
def contour_extrapolate_modeling(param: dict | str) -> list[NativeTin]:
    """轮廓线外推建模"""
    try:
        result = Dm.ContourExtrapolateModeling(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"轮廓线外推建模失败: {exc}") from exc
    return _convert_polydata_list(result, "轮廓线外推建模")

convert_file(source, target)

执行文件格式转换。

Raises:

Type Description
NativeIOError

不支持的格式或转换失败

Source code in dimine_python_sdk\lib\native\io.py
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def convert_file(source: str, target: str) -> None:
    """
    执行文件格式转换。

    Raises:
        NativeIOError: 不支持的格式或转换失败
    """
    source_path = Path(source)
    target_path = Path(target)

    try:
        src_fmt = FileFormat(source_path.suffix)
    except ValueError:
        raise NativeIOError(f"不支持的源文件格式: {source_path.suffix}")

    try:
        tgt_fmt = FileFormat(target_path.suffix)
    except ValueError:
        raise NativeIOError(f"不支持的目标文件格式: {target_path.suffix}")

    if src_fmt not in _CONVERTER_MAP or tgt_fmt not in _CONVERTER_MAP[src_fmt]:
        raise NativeIOError(f"不支持的转换方向: {src_fmt.value} -> {tgt_fmt.value}")

    fn = _CONVERTER_MAP[src_fmt][tgt_fmt]
    try:
        ok = fn(str(source_path), str(target_path))
    except Exception as exc:
        raise NativeIOError(f"转换异常: {exc}") from exc

    if not ok:
        raise NativeIOError(f"转换失败: {source_path} -> {target_path}")

create_block_model(params)

创建空块段模型

Source code in dimine_python_sdk\lib\native\prospecting.py
750
751
752
753
754
def create_block_model(params: dict | str) -> dict:
    """创建空块段模型"""
    t = _serialize_param(params)
    raw = Dm.CreateBlockModel(t)
    return parse_json_response(raw, NativeProspectingError, "创建块段模型")

create_database()

创建 C++ dmDbDatabase 对象

Source code in dimine_python_sdk\lib\native\geometry.py
905
906
907
def create_database():
    """创建 C++ dmDbDatabase 对象"""
    return Dm.dmDbDatabase()

create_layer()

创建 C++ dmDbLayer 对象

Source code in dimine_python_sdk\lib\native\geometry.py
915
916
917
def create_layer():
    """创建 C++ dmDbLayer 对象"""
    return Dm.dmDbLayer()

create_line(start, end, *, name='', feature_name='', color=None, properties=None)

创建线实体数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
def create_line(
    start: "np.ndarray",
    end: "np.ndarray",
    *,
    name: str = "",
    feature_name: str = "",
    color: list[int] | None = None,
    properties: list[NativeProperty] | None = None,
) -> NativeEntity:
    """创建线实体数据模型"""
    import numpy as np

    s = ensure_array_3d(start)
    e = ensure_array_3d(end)
    return NativeEntity(
        entity_type="line",
        name=name,
        geometry=np.array([s, e], dtype=float),
        color=color or [0, 0, 0],
        feature_name=feature_name,
        properties=properties or [],
    )

create_local_database()

创建可编辑本地 C++ dmDbDatabase 对象

Source code in dimine_python_sdk\lib\native\geometry.py
910
911
912
def create_local_database():
    """创建可编辑本地 C++ dmDbDatabase 对象"""
    return Dm.dmDbDatabase.CreateLocalDB()

create_point(position, *, name='', feature_name='', color=None, properties=None)

创建点实体数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
def create_point(
    position: "np.ndarray",
    *,
    name: str = "",
    feature_name: str = "",
    color: list[int] | None = None,
    properties: list[NativeProperty] | None = None,
) -> NativeEntity:
    """创建点实体数据模型"""
    pos = ensure_array_3d(position)
    return NativeEntity(
        entity_type="point",
        name=name,
        geometry=pos,
        color=color or [0, 0, 0],
        feature_name=feature_name,
        properties=properties or [],
    )

create_polyline(points, *, name='', feature_name='', color=None, properties=None)

创建多段线实体数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
def create_polyline(
    points: "np.ndarray",
    *,
    name: str = "",
    feature_name: str = "",
    color: list[int] | None = None,
    properties: list[NativeProperty] | None = None,
) -> NativeEntity:
    """创建多段线实体数据模型"""
    return NativeEntity(
        entity_type="polyline",
        name=name,
        geometry=ensure_points(points),
        color=color or [0, 0, 0],
        feature_name=feature_name,
        properties=properties or [],
    )

create_shell(tin, *, name='', feature_name='', color=None, properties=None)

创建 Shell 实体数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
def create_shell(
    tin: NativeTin,
    *,
    name: str = "",
    feature_name: str = "",
    color: list[int] | None = None,
    properties: list[NativeProperty] | None = None,
) -> NativeEntity:
    """创建 Shell 实体数据模型"""
    return NativeEntity(
        entity_type="shell",
        name=name,
        geometry=tin,
        color=color or [0, 0, 0],
        feature_name=feature_name,
        properties=properties or [],
    )

create_text(position, text, *, name='', feature_name='', color=None, properties=None)

创建文本实体数据模型(作为 NativeEntity)

Source code in dimine_python_sdk\lib\native\geometry.py
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
def create_text(
    position: "np.ndarray",
    text: str,
    *,
    name: str = "",
    feature_name: str = "",
    color: list[int] | None = None,
    properties: list[NativeProperty] | None = None,
) -> NativeEntity:
    """创建文本实体数据模型(作为 NativeEntity)"""
    props: list[NativeProperty] = [NativeProperty(name="text", value=text, type="string")]
    if properties:
        props.extend(properties)
    return NativeEntity(
        entity_type="text",
        name=name,
        geometry=ensure_array_3d(position),
        color=color or [0, 0, 0],
        feature_name=feature_name,
        properties=props,
    )

cut_model_data(input_tin, origin, normal, num=1, dist=0)

裁剪模型数据。

Parameters:

Name Type Description Default
input_tin NativeTin

输入三角网

required
origin 'np.ndarray'

裁剪原点

required
normal 'np.ndarray'

裁剪法线

required
num int

裁剪次数

1
dist float

裁剪距离

0

Returns:

Type Description
NativeTin

裁剪后的三角网

Source code in dimine_python_sdk\lib\native\algorithm.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
def cut_model_data(
    input_tin: NativeTin,
    origin: "np.ndarray",
    normal: "np.ndarray",
    num: int = 1,
    dist: float = 0,
) -> NativeTin:
    """
    裁剪模型数据。

    Args:
        input_tin: 输入三角网
        origin: 裁剪原点
        normal: 裁剪法线
        num: 裁剪次数
        dist: 裁剪距离

    Returns:
        裁剪后的三角网
    """
    import numpy as np

    input_poly = _geom.tin_to_polydata(input_tin)
    output_poly = Dm.dmPolyData()
    o = _geom.point_to_native(ensure_array_3d(origin))
    n = _geom.point_to_native(ensure_array_3d(normal))

    ret = Dm.thModelFunc.CutModelData(input_poly, o, n, output_poly, num, dist)
    if ret != 1:
        raise NativeAlgorithmError(f"模型切割失败,底层返回结果码: {ret}")

    return _geom.tin_from_polydata(output_poly)

distance_power_evaluation(block_model_file, constraint_json, evaluation_json, overwrite=True)

距离幂估值

Source code in dimine_python_sdk\lib\native\prospecting.py
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
def distance_power_evaluation(
    block_model_file: str,
    constraint_json: str,
    evaluation_json: str,
    overwrite: bool = True,
) -> dict:
    """距离幂估值"""
    result = Dm.DistancePowerEvaluationValue(
        block_model_file,
        _serialize_constraints(constraint_json),
        _serialize_param(evaluation_json),
        overwrite,
    )
    message = check_bool_message(result, NativeProspectingError, "距离幂估值")
    return {"success": True, "message": message}

extra_high_grade_process(param)

特高品位处理

Source code in dimine_python_sdk\lib\native\prospecting.py
450
451
452
453
454
455
456
457
458
459
def extra_high_grade_process(param: dict | str) -> dict:
    """特高品位处理"""
    print(f"extra_high_grade_process: {_serialize_param(param)}")
    raw = Dm.ExtraHighGradeProcess(_serialize_param(param))
    try:
        return parse_json_response(raw, NativeProspectingError, "特高品位处理")
    except NativeProcessError as exc:
        if "所选字段数据为空" in str(exc.response.get("message")):
            return {"state": "true", "message": "所选字段数据为空"}
        raise exc

get_section_contour(param)

获取断面轮廓

Source code in dimine_python_sdk\lib\native\exploitation.py
36
37
38
39
40
41
42
43
44
45
46
47
def get_section_contour(param: dict | str) -> "np.ndarray":
    """获取断面轮廓"""
    import numpy as np

    try:
        result = Dm.GetSectionContour(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"断面生成失败: {exc}") from exc

    if result is None:
        raise NativeExploitationError("断面生成返回空结果")
    return np.asarray(result, dtype=float)

init_sdk()

初始化 SDK 底层(dm_Init)。

幂等调用:如果已经初始化,直接返回,不会重复 init。 首次初始化成功时自动注册 atexit 回调以在进程退出时调用 dm_Uninit。

Source code in dimine_python_sdk\lib\native\_core.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def init_sdk() -> None:
    """
    初始化 SDK 底层(dm_Init)。

    幂等调用:如果已经初始化,直接返回,不会重复 init。
    首次初始化成功时自动注册 atexit 回调以在进程退出时调用 dm_Uninit。
    """
    global _sdk_initialized

    with _sdk_lock:
        if _sdk_initialized:
            return
        try:
            Dm.dm_Init()
            _sdk_initialized = True
            atexit.register(_cleanup_on_exit)
        except Exception as exc:
            logger.error("SDK 底层初始化失败 (dm_Init): %s", exc)
            raise

kriging_evaluation(block_model_file, constraint_json, evaluation_json, overwrite=True)

克里格估值

Source code in dimine_python_sdk\lib\native\prospecting.py
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
def kriging_evaluation(
    block_model_file: str,
    constraint_json: str,
    evaluation_json: str,
    overwrite: bool = True,
) -> dict:
    """克里格估值"""
    result = Dm.KrigEvaluationValue(
        block_model_file,
        _serialize_constraints(constraint_json),
        _serialize_param(evaluation_json),
        overwrite,
    )
    message = check_bool_message(result, NativeProspectingError, "克里格估值")
    return {"success": True, "message": message}

laneway_modeling(param)

巷道/竖井建模

Source code in dimine_python_sdk\lib\native\exploitation.py
50
51
52
53
54
55
56
def laneway_modeling(param: dict | str) -> list[NativeTin]:
    """巷道/竖井建模"""
    try:
        result = Dm.LanewayModeling(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"巷道建模失败: {exc}") from exc
    return _convert_polydata_list(result, "巷道建模")

line_x_polyline(start, end, point_set, tolerance)

计算线段与多段线的交点。

Parameters:

Name Type Description Default
start 'np.ndarray'

线段起点

required
end 'np.ndarray'

线段终点

required
point_set 'np.ndarray'

多段线顶点 (N, 3)

required
tolerance float

容差

required

Returns:

Type Description
'np.ndarray'

交点数组 (M, 3)

Source code in dimine_python_sdk\lib\native\algorithm.py
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def line_x_polyline(
    start: "np.ndarray",
    end: "np.ndarray",
    point_set: "np.ndarray",
    tolerance: float,
) -> "np.ndarray":
    """
    计算线段与多段线的交点。

    Args:
        start: 线段起点
        end: 线段终点
        point_set: 多段线顶点 (N, 3)
        tolerance: 容差

    Returns:
        交点数组 (M, 3)
    """
    s = _geom.point_to_native(ensure_array_3d(start))
    e = _geom.point_to_native(ensure_array_3d(end))
    pts = _geom.points_to_native(ensure_points(point_set))
    cpp_result = Dm.thModelFunc.LineXPolyline(s, e, pts, float(tolerance))
    if not cpp_result:
        import numpy as np

        return np.zeros((0, 3), dtype=float)
    return _geom.points_from_native(cpp_result)

multi_parallel_contour_modeling(param)

多平行轮廓线建模

Source code in dimine_python_sdk\lib\native\exploitation.py
86
87
88
89
90
91
92
def multi_parallel_contour_modeling(param: dict | str) -> list[NativeTin]:
    """多平行轮廓线建模"""
    try:
        result = Dm.MultiParallelContourModeling(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"多平行轮廓线建模失败: {exc}") from exc
    return _convert_polydata_list(result, "多平行轮廓线建模")

point_from_native(cpp_point)

将 C++ dmDPoint 转换为 (3,) numpy 数组

Source code in dimine_python_sdk\lib\native\geometry.py
83
84
85
86
87
def point_from_native(cpp_point: Any) -> "np.ndarray":
    """将 C++ dmDPoint 转换为 (3,) numpy 数组"""
    import numpy as np

    return np.array([float(cpp_point.x), float(cpp_point.y), float(cpp_point.z)], dtype=float)

point_to_native(point)

将 (3,) numpy 数组转换为单个 C++ dmDPoint

Source code in dimine_python_sdk\lib\native\geometry.py
77
78
79
80
def point_to_native(point: "np.ndarray") -> Any:
    """将 (3,) numpy 数组转换为单个 C++ dmDPoint"""
    arr = ensure_array_3d(point)
    return Dm.dmDPoint(float(arr[0]), float(arr[1]), float(arr[2]))

points_from_native(cpp_points)

将 C++ dmDPoint 列表转换为 (N, 3) numpy 数组

Source code in dimine_python_sdk\lib\native\geometry.py
90
91
92
93
94
95
96
def points_from_native(cpp_points: list[Any]) -> "np.ndarray":
    """将 C++ dmDPoint 列表转换为 (N, 3) numpy 数组"""
    import numpy as np

    return np.array(
        [[float(p.x), float(p.y), float(p.z)] for p in cpp_points], dtype=float
    )

points_to_native(points)

将 (N, 3) numpy 数组转换为 C++ dmDPoint 列表

Source code in dimine_python_sdk\lib\native\geometry.py
71
72
73
74
def points_to_native(points: "np.ndarray") -> list[Any]:
    """将 (N, 3) numpy 数组转换为 C++ dmDPoint 列表"""
    arr = ensure_points(points)
    return [Dm.dmDPoint(float(p[0]), float(p[1]), float(p[2])) for p in arr]

read_dmf(file_path)

读取 DMF 文件,返回要素定义列表和图层列表。

Returns:

Type Description
tuple[list[NativeFeature], list[NativeLayer]]

(features, layers)

Source code in dimine_python_sdk\lib\native\io.py
187
188
189
190
191
192
193
194
195
196
197
198
199
200
def read_dmf(file_path: str) -> tuple[list[NativeFeature], list[NativeLayer]]:
    """
    读取 DMF 文件,返回要素定义列表和图层列表。

    Returns:
        (features, layers)
    """

    db = _geom.NativeDatabaseHandle.create_local()
    db.load(file_path)

    layers = [db.get_layer(i).to_model() for i in range(db.layer_count)]
    features = db.features()
    return features, layers

sample_length_combine(param)

样长组合

Source code in dimine_python_sdk\lib\native\prospecting.py
438
439
440
441
def sample_length_combine(param: dict | str) -> dict:
    """样长组合"""
    raw = Dm.SampleLengthCombine(_serialize_param(param))
    return parse_json_response(raw, NativeProspectingError, "样长组合")

single_contour_modeling(param)

单轮廓线封闭为面

Source code in dimine_python_sdk\lib\native\exploitation.py
68
69
70
71
72
73
74
def single_contour_modeling(param: dict | str) -> list[NativeTin]:
    """单轮廓线封闭为面"""
    try:
        result = Dm.SingleContourModeling(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"单轮廓线建模失败: {exc}") from exc
    return _convert_polydata_list(result, "单轮廓线建模")

step_combine(param)

台阶组合

Source code in dimine_python_sdk\lib\native\prospecting.py
444
445
446
447
def step_combine(param: dict | str) -> dict:
    """台阶组合"""
    raw = Dm.StepCombine(_serialize_param(param))
    return parse_json_response(raw, NativeProspectingError, "台阶组合")

tin_from_polydata(polydata)

C++ dmPolyData -> NativeTin

Source code in dimine_python_sdk\lib\native\geometry.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
def tin_from_polydata(polydata: Any) -> NativeTin:
    """C++ dmPolyData -> NativeTin"""
    import numpy as np

    n_points = polydata.GetNumberOfPoints()
    n_polys = polydata.GetNumberOfPolys()

    points = np.zeros((n_points, 3), dtype=float)
    for i in range(n_points):
        pt = polydata.GetPoint(i)
        points[i] = [float(pt.x), float(pt.y), float(pt.z)]

    faces = np.zeros((n_polys, 3), dtype=int)
    for i in range(n_polys):
        cell = polydata.GetPolyCell(i)
        faces[i] = [int(cell[0]), int(cell[1]), int(cell[2])]

    return NativeTin(points=points, faces=faces)

tin_to_polydata(tin)

NativeTin -> C++ dmPolyData

Source code in dimine_python_sdk\lib\native\geometry.py
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def tin_to_polydata(tin: NativeTin) -> Any:
    """NativeTin -> C++ dmPolyData"""
    import numpy as np

    points = np.asarray(tin.points, dtype=float)
    faces = np.asarray(tin.faces, dtype=int)
    if points.ndim != 2 or points.shape[1] != 3:
        raise ValueError(f"tin.points shape 必须为 (N, 3),当前: {points.shape}")
    if faces.ndim != 2 or faces.shape[1] != 3:
        raise ValueError(f"tin.faces shape 必须为 (M, 3),当前: {faces.shape}")

    dm_points = Dm.dmPoints()
    for p in points:
        dm_points.InsertNextPoint(Dm.dmDPoint(float(p[0]), float(p[1]), float(p[2])))

    polydata = Dm.dmPolyData()
    polydata.SetDmPoints(dm_points)
    for face in faces:
        polydata.InsertNextPolyCell([int(face[0]), int(face[1]), int(face[2])])
    return polydata

two_contour_modeling(param)

两轮廓线建模

Source code in dimine_python_sdk\lib\native\exploitation.py
59
60
61
62
63
64
65
def two_contour_modeling(param: dict | str) -> list[NativeTin]:
    """两轮廓线建模"""
    try:
        result = Dm.TwoContourModeling(_serialize_param(param))
    except Exception as exc:
        raise NativeExploitationError(f"两轮廓线建模失败: {exc}") from exc
    return _convert_polydata_list(result, "两轮廓线建模")

uninit_sdk()

释放 SDK 底层资源(dm_Uninit)。

幂等调用:如果已经释放或从未初始化,直接返回。 主动调用后 atexit 回调不会重复释放。

Source code in dimine_python_sdk\lib\native\_core.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
def uninit_sdk() -> None:
    """
    释放 SDK 底层资源(dm_Uninit)。

    幂等调用:如果已经释放或从未初始化,直接返回。
    主动调用后 atexit 回调不会重复释放。
    """
    global _sdk_initialized

    with _sdk_lock:
        if not _sdk_initialized:
            return
        try:
            Dm.dm_Uninit()
            _sdk_initialized = False
            logger.info("SDK 底层资源已释放 (dm_Uninit)")
        except Exception as exc:
            logger.error("SDK 底层资源释放失败 (dm_Uninit): %s", exc)
            raise

unite_polydata(tin_list)

实体合并

Source code in dimine_python_sdk\lib\native\exploitation.py
 95
 96
 97
 98
 99
100
101
102
def unite_polydata(tin_list: list[NativeTin]) -> list[NativeTin]:
    """实体合并"""
    native_objs = [_geom.tin_to_polydata(tin)._cpp_obj for tin in tin_list]
    try:
        result = Dm.UnitePolyData(native_objs)
    except Exception as exc:
        raise NativeExploitationError(f"实体合并失败: {exc}") from exc
    return _convert_polydata_list(result, "实体合并")

write_dmf(file_path, layers, features=None)

将 NativeLayer/NativeFeature 写入 DMF 文件。

会根据传入的 features 注册要素定义和属性字段,并将属性值写入每个 实体的属性记录。

Source code in dimine_python_sdk\lib\native\io.py
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
def write_dmf(
    file_path: str,
    layers: list[NativeLayer],
    features: list[NativeFeature] | None = None,
) -> None:
    """
    将 NativeLayer/NativeFeature 写入 DMF 文件。

    会根据传入的 ``features`` 注册要素定义和属性字段,并将属性值写入每个
    实体的属性记录。
    """
    db = _geom.NativeDatabaseHandle.create_local()
    features = features or []

    # 注册要素与属性定义
    db.set_features(features)

    for layer in layers:
        cpp_layer = db.insert_layer(layer.name)
        for feature_name, group in groupby(layer.entities, key=_entity_feature_key):
            if feature_name:
                db.set_active_feature(feature_name)
            cpp_layer.insert_entities(list(group))

    db.save(file_path)