Skip to content

native 桥接层

Native Layer 公开入口

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

BlockModelSession

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

Source code in dimine_python_sdk\lib\native\prospecting.py
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
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]:
        """最小块段尺寸"""
        return list(self._cpp_obj.GetMinSize())

    @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: str) -> Iterator[dict]:
        """遍历所有块段,逐块返回指定字段数据"""
        self._cpp_obj.InitCursor()
        while self._cpp_obj.AdvCursor() and not self._cpp_obj.IsBeyondBoundaryNode():
            success, data = self._cpp_obj.GetCursorData(field_name)
            if success:
                try:
                    yield json.loads(data)
                except (ValueError, TypeError):
                    yield {"_raw": str(data)}

field_definitions property

字段定义列表

max_level property

最大精度层级

min_size property

最小块段尺寸

origin property

模型原点

rotation property

模型旋转角度

total_block_count property

块段总数量

xyz_length property

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

iter_blocks(field_name)

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

Source code in dimine_python_sdk\lib\native\prospecting.py
351
352
353
354
355
356
357
358
359
360
def iter_blocks(self, field_name: str) -> Iterator[dict]:
    """遍历所有块段,逐块返回指定字段数据"""
    self._cpp_obj.InitCursor()
    while self._cpp_obj.AdvCursor() and not self._cpp_obj.IsBeyondBoundaryNode():
        success, data = self._cpp_obj.GetCursorData(field_name)
        if success:
            try:
                yield json.loads(data)
            except (ValueError, TypeError):
                yield {"_raw": str(data)}

open(file_path) classmethod

加载块段模型

Source code in dimine_python_sdk\lib\native\prospecting.py
304
305
306
307
308
309
310
@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
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
class DrillSession:
    """钻孔数据库会话,内部持有 C++ dmGeoDrillData 对象"""

    def __init__(self, cpp_obj: Any, ref_dict: dict):
        self._cpp_obj = cpp_obj
        self._ref_dict = 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)

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

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

    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 格式"""
        try:
            self._cpp_obj.Save(file_path)
        except Exception as exc:
            raise NativeProspectingError(f"保存 .dmg 失败: {file_path}") from exc

collar_table()

获取孔口表

Source code in dimine_python_sdk\lib\native\prospecting.py
200
201
202
203
204
205
206
207
208
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
148
149
150
151
@classmethod
def create_empty(cls) -> "DrillSession":
    """创建空钻孔数据库"""
    return cls(Dm.dmGeoDrillData(), {})

lithology_table()

获取岩性表

Source code in dimine_python_sdk\lib\native\prospecting.py
228
229
230
231
232
233
234
235
236
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
139
140
141
142
143
144
145
146
@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)

sample_table()

获取样品表

Source code in dimine_python_sdk\lib\native\prospecting.py
242
243
244
245
246
247
248
249
250
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 格式

Source code in dimine_python_sdk\lib\native\prospecting.py
256
257
258
259
260
261
def save_as_dmg(self, file_path: str) -> None:
    """保存为 .dmg 格式"""
    try:
        self._cpp_obj.Save(file_path)
    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
210
211
212
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
238
239
240
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
252
253
254
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
224
225
226
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
214
215
216
217
218
219
220
221
222
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
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:
        """返回记录总数"""
        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
201
202
203
204
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
206
207
208
209
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
211
212
213
214
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
195
196
197
198
199
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
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
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
def record_count(self) -> int:
    """返回记录总数"""
    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
216
217
218
219
220
221
222
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
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
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
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
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
773
774
775
776
777
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
779
780
781
def close_polyline(self) -> None:
    """闭合多段线"""
    self._cpp_obj.ClosePolyline()

create() classmethod

创建只读数据库

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

create_local() classmethod

创建可编辑本地数据库

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

features()

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

Source code in dimine_python_sdk\lib\native\geometry.py
681
682
683
684
685
686
687
688
689
690
691
692
693
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
648
649
650
651
652
653
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
667
668
669
670
671
672
673
674
675
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
634
635
636
637
638
639
640
641
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
655
656
657
658
659
660
661
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
643
644
645
646
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
612
613
614
615
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
617
618
619
620
621
622
623
624
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
677
678
679
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
783
784
785
786
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
695
696
697
698
699
700
701
702
703
704
705
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
626
627
628
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
62
63
64
65
66
67
68
69
70
71
@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
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
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
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:
        """转换为 NativeEntity 数据模型"""
        feature_name, props = self.att_record()
        if self.type_name == "text":
            # 文本内容优先从属性记录读取;缺失时回退到 GetText()
            if not any(p.name == "text" for p in props):
                try:
                    text = self._cpp_obj.GetText() or ""
                except Exception:
                    text = ""
                if text:
                    props = list(props)
                    props.append(NativeProperty(name="text", value=text, type="string"))
        return NativeEntity(
            entity_type=self.type_name,
            name=self.name,
            geometry=self.geometry(),
            color=self.color,
            properties=props,
            feature_name=feature_name,
        )

att_record()

读取实体属性记录

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

Source code in dimine_python_sdk\lib\native\geometry.py
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
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
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
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
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
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 数据模型

Source code in dimine_python_sdk\lib\native\geometry.py
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def to_model(self) -> NativeEntity:
    """转换为 NativeEntity 数据模型"""
    feature_name, props = self.att_record()
    if self.type_name == "text":
        # 文本内容优先从属性记录读取;缺失时回退到 GetText()
        if not any(p.name == "text" for p in props):
            try:
                text = self._cpp_obj.GetText() or ""
            except Exception:
                text = ""
            if text:
                props = list(props)
                props.append(NativeProperty(name="text", value=text, type="string"))
    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
89
90
91
92
93
94
@dataclass
class NativeFeature:
    """DMF 要素定义"""

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

NativeFieldDef dataclass

字段定义

Source code in dimine_python_sdk\lib\native\models.py
37
38
39
40
41
42
43
@dataclass
class NativeFieldDef:
    """字段定义"""

    name: str
    type: int | str
    size: int = 0

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
 97
 98
 99
100
101
102
@dataclass
class NativeLayer:
    """DMF 图层数据模型"""

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

NativeLayerHandle

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

Source code in dimine_python_sdk\lib\native\geometry.py
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
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
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]:
        """迭代图层中所有实体,返回 NativeEntity

        OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用,
        一旦进入下一次 OpenNextEntity(),之前的引用即可能失效。
        因此这里一次性把每个实体的数据拷贝到 Python 对象,并立即释放
        底层 C++ 引用后再读取下一个实体。
        """
        self._cpp_obj.StartQueryEntity()
        results: list[NativeEntity] = []
        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) -> NativeEntityHandle:
        """根据 NativeEntity 数据模型插入实体,并返回实体句柄

        插入几何后会通过返回的 ``NativeEntityHandle`` 设置实体名称、颜色,
        并以 ``att_record`` 的反向操作将属性值写入 C++ 属性记录。
        """
        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]
    ) -> list[NativeEntityHandle]:
        """批量插入 NativeEntity,返回实体句柄列表"""
        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,返回实体句柄列表

Source code in dimine_python_sdk\lib\native\geometry.py
578
579
580
581
582
def insert_entities(
    self, entities: Sequence[NativeEntity]
) -> list[NativeEntityHandle]:
    """批量插入 NativeEntity,返回实体句柄列表"""
    return [self.insert_native_entity(e) for e in entities]

insert_native_entity(entity)

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

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

Source code in dimine_python_sdk\lib\native\geometry.py
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
571
572
573
574
575
576
def insert_native_entity(self, entity: NativeEntity) -> NativeEntityHandle:
    """根据 NativeEntity 数据模型插入实体,并返回实体句柄

    插入几何后会通过返回的 ``NativeEntityHandle`` 设置实体名称、颜色,
    并以 ``att_record`` 的反向操作将属性值写入 C++ 属性记录。
    """
    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

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

Source code in dimine_python_sdk\lib\native\geometry.py
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
def iter_entities(self) -> Iterator[NativeEntity]:
    """迭代图层中所有实体,返回 NativeEntity

    OpenNextEntity() 返回的实体对象通常是图层查询游标的临时引用,
    一旦进入下一次 OpenNextEntity(),之前的引用即可能失效。
    因此这里一次性把每个实体的数据拷贝到 Python 对象,并立即释放
    底层 C++ 引用后再读取下一个实体。
    """
    self._cpp_obj.StartQueryEntity()
    results: list[NativeEntity] = []
    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
584
585
586
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
28
29
30
31
32
33
34
@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

文本实体数据模型

Source code in dimine_python_sdk\lib\native\models.py
74
75
76
77
78
79
80
81
82
83
84
85
86
@dataclass
class NativeText:
    """文本实体数据模型"""

    position: "np.ndarray"  # shape (3,)
    text: str
    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]
    )

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
46
47
48
49
50
51
@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
374
375
376
377
378
379
380
381
382
383
384
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
438
439
440
441
442
443
444
445
446
447
448
449
450
def calculate_reserves(
    block_model_file: str,
    constraint_json: str,
    reserve_json: str,
) -> dict:
    """储量计算"""
    result = Dm.ReservesCalculate(
        block_model_file,
        _serialize_constraints(constraint_json),
        _serialize_param(reserve_json),
    )
    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
367
368
369
370
371
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
793
794
795
def create_database():
    """创建 C++ dmDbDatabase 对象"""
    return Dm.dmDbDatabase()

create_layer()

创建 C++ dmDbLayer 对象

Source code in dimine_python_sdk\lib\native\geometry.py
803
804
805
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
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
798
799
800
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
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
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
def distance_power_evaluation(
    block_model_file: str,
    constraint_json: str,
    evaluation_json: str,
    overwrite: bool = True,
) -> dict:
    """距离幂估值"""
    print(f"[DEBUG] Dm.DistancePowerEvaluationValue 入参:")
    print(f"  block_model_file: {block_model_file}")
    print(f"  constraint_json: {constraint_json}")
    print(f"  evaluation_json: {evaluation_json}")
    print(f"  overwrite: {overwrite}")

    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
287
288
289
290
def extra_high_grade_process(param: dict | str) -> dict:
    """特高品位处理"""
    raw = Dm.ExtraHighGradeProcess(_serialize_param(param))
    return parse_json_response(raw, NativeProspectingError, "特高品位处理")

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)

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

克里格估值

Source code in dimine_python_sdk\lib\native\prospecting.py
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
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
82
83
84
85
86
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
76
77
78
79
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
89
90
91
92
93
94
95
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
70
71
72
73
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
275
276
277
278
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
281
282
283
284
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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, "两轮廓线建模")

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
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
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)