Skip to content

dmb_file

DMB 文件业务层:DmbFile、dmb_conn 与相关异常

职责: - 提供 Pythonic 的 DMB 块段模型文件读取接口; - 内部通过 native.prospecting.BlockModelSession 持有 C++ dmBlockDataNew 对象; - 属性委托给 session,异常翻译为 DmbError 层次。

允许类型:np.ndarray、list、dict、Path、str 禁止类型:Dm* 禁止 import DmPyBindInterface

DmbError

Bases: RuntimeError

DMB 操作异常基类

Source code in dimine_python_sdk\lib\io\dmb_file.py
39
40
41
42
class DmbError(RuntimeError):
    """DMB 操作异常基类"""

    pass

DmbFile

DMB 块段模型文件管理器。

DMB 文件在 Dimine 中用于存储块段模型数据,包含模型原点、尺寸、 旋转角度、字段定义等元数据,以及各块段的属性数据。

用法::

# 从文件加载
dmb = DmbFile("model.dmb")
print(dmb.info)
print(dmb.origin)
print(dmb.total_block_count)

# 遍历块段数据
for block in dmb.iter_blocks("品位"):
    print(block)

# 上下文管理器
with dmb_conn("model.dmb") as dmb:
    print(dmb.field_definitions)
Source code in dimine_python_sdk\lib\io\dmb_file.py
 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
 86
 87
 88
 89
 90
 91
 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
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
class DmbFile:
    """
    DMB 块段模型文件管理器。

    DMB 文件在 Dimine 中用于存储块段模型数据,包含模型原点、尺寸、
    旋转角度、字段定义等元数据,以及各块段的属性数据。

    用法::

        # 从文件加载
        dmb = DmbFile("model.dmb")
        print(dmb.info)
        print(dmb.origin)
        print(dmb.total_block_count)

        # 遍历块段数据
        for block in dmb.iter_blocks("品位"):
            print(block)

        # 上下文管理器
        with dmb_conn("model.dmb") as dmb:
            print(dmb.field_definitions)
    """

    def __init__(self, file_path: Optional[Union[str, Path]] = None):
        """
        Args:
            file_path: 块段模型文件路径。为 None 时需手动调用 load()
        """
        self.file_path: Optional[str] = None
        self._session: Optional[BlockModelSession] = None

        if file_path is not None:
            self.load(file_path)

    # ------------------------------------------------------------------
    # 生命周期
    # ------------------------------------------------------------------

    def load(self, file_path: Union[str, Path]) -> "DmbFile":
        """
        加载 .dmb 块段模型文件。

        Returns:
            self(支持链式调用)

        Raises:
            DmbLoadError: 文件不存在或加载失败
        """
        path = Path(file_path)
        if not path.exists():
            raise DmbLoadError(f"文件不存在: {file_path}")

        try:
            self._session = BlockModelSession.open(str(path))
        except NativeProspectingError as exc:
            raise DmbLoadError(f"加载 .dmb 失败: {file_path}") from exc
        except Exception as exc:
            raise DmbLoadError(f"加载 .dmb 异常: {file_path}") from exc

        self.file_path = str(path)
        return self

    def close(self) -> None:
        """释放块段模型会话"""
        if self._session is not None:
            self._session.close()
        self._session = None
        self.file_path = None

    # ------------------------------------------------------------------
    # 属性
    # ------------------------------------------------------------------

    @property
    def origin(self) -> "np.ndarray":
        """模型原点坐标,返回形状 (3,) 的 numpy 数组"""
        self._check_open()
        return self._session.origin 

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

    @property
    def max_level(self) -> int:
        """模型最大精度层级"""
        self._check_open()
        return self._session.max_level

    @property
    def min_size(self) -> list[float]:
        """最小块段尺寸 [min_x, min_y, min_z](对应 max_level 层级)"""
        self._check_open()
        return list(self._session.min_size)

    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]
        """
        self._check_open()
        return self._session.get_level_size(level)

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

        Returns:
            {level: [size_x, size_y, size_z], ...}
        """
        self._check_open()
        return self._session.level_size_map()

    @property
    def rotation(self) -> list[float]:
        """模型旋转角度 [rot_x, rot_y, rot_z]"""
        self._check_open()
        return list(self._session.rotation)

    @property
    def field_definitions(self) -> list[dict]:
        """字段定义列表,每项包含 name / type"""
        self._check_open()
        return [
            {"name": d.name, "type": d.type}
            for d in self._session.field_definitions
        ]

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

    @property
    def name(self) -> str:
        """文件名(不含扩展名)"""
        return Path(self.file_path).stem if self.file_path else ""

    @property
    def info(self) -> dict[str, Any]:
        """DMB 文件摘要信息"""
        if self._session is None:
            return {
                "file": self.file_path or "",
                "name": self.name,
                "loaded": False,
            }
        return {
            "file": self.file_path or "",
            "name": self.name,
            "origin": self.origin.tolist(),
            "xyz_length": self.xyz_length,
            "max_level": self.max_level,
            "min_size": self.min_size,
            "rotation": self.rotation,
            "field_definitions": self.field_definitions,
            "total_block_count": self.total_block_count,
            "level_size_map": self.level_size_map(),
        }

    # ------------------------------------------------------------------
    # 迭代器
    # ------------------------------------------------------------------

    def iter_blocks(self, field_name: str|None=None) -> Generator[dict, None, None]:
        """
        遍历块段模型的所有块段数据。

        Args:
            field_name: 要读取的字段名列表,通过逗号分割(如 "品位,岩石类型")

        Yields:
            dict: 每个块段的字段数据
        """
        self._check_open()
        yield from self._session.iter_blocks(field_name)

    def to_dataframe(self) -> "pd.DataFrame":
        """
        将块段模型数据转换为 pandas DataFrame。

        Returns:
            pd.DataFrame: 块段模型数据表

        Raises:
            DmbError: 文件未加载时抛出
            ImportError: pandas 未安装时抛出
        """
        self._check_open()

        try:
            import pandas as pd
        except ImportError:
            raise ImportError("使用 to_dataframe() 需要安装 pandas: uv add pandas")

        # 获取字段定义作为表头
        all_fields = self.field_definitions  # list[dict] with "name" / "type"
        columns = [f["name"] for f in all_fields]
        import time
        # 逐行收集数据
        t0 = time.perf_counter()
        rows = list(self.iter_blocks())
        t1 = time.perf_counter()
        print(f"  [计时] to_dataframe() 耗时: {t1 - t0:.4f} 秒")
        if not rows:
            return pd.DataFrame(columns=columns)

        return pd.DataFrame(rows)

    # ------------------------------------------------------------------
    # 内部
    # ------------------------------------------------------------------

    def _check_open(self) -> None:
        if self._session is None:
            raise DmbError("请先调用 load() 加载块段模型")

    # ------------------------------------------------------------------
    # Pythonic 访问
    # ------------------------------------------------------------------

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

    def __repr__(self) -> str:
        loaded = "loaded" if self._session is not None else "closed"
        blocks = self.total_block_count if self._session is not None else 0
        return f"DmbFile('{self.file_path or ''}', {loaded}, blocks={blocks})"

    def __enter__(self) -> "DmbFile":
        return self

    def __exit__(self, exc_type, exc_val, exc_tb) -> None:
        self.close()

field_definitions property

字段定义列表,每项包含 name / type

info property

DMB 文件摘要信息

max_level property

模型最大精度层级

min_size property

最小块段尺寸 [min_x, min_y, min_z](对应 max_level 层级)

name property

文件名(不含扩展名)

origin property

模型原点坐标,返回形状 (3,) 的 numpy 数组

rotation property

模型旋转角度 [rot_x, rot_y, rot_z]

total_block_count property

块段总数量

xyz_length property

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

__init__(file_path=None)

Parameters:

Name Type Description Default
file_path Optional[Union[str, Path]]

块段模型文件路径。为 None 时需手动调用 load()

None
Source code in dimine_python_sdk\lib\io\dmb_file.py
80
81
82
83
84
85
86
87
88
89
def __init__(self, file_path: Optional[Union[str, Path]] = None):
    """
    Args:
        file_path: 块段模型文件路径。为 None 时需手动调用 load()
    """
    self.file_path: Optional[str] = None
    self._session: Optional[BlockModelSession] = None

    if file_path is not None:
        self.load(file_path)

close()

释放块段模型会话

Source code in dimine_python_sdk\lib\io\dmb_file.py
119
120
121
122
123
124
def close(self) -> None:
    """释放块段模型会话"""
    if self._session is not None:
        self._session.close()
    self._session = 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]

Source code in dimine_python_sdk\lib\io\dmb_file.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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]
    """
    self._check_open()
    return self._session.get_level_size(level)

iter_blocks(field_name=None)

遍历块段模型的所有块段数据。

Parameters:

Name Type Description Default
field_name str | None

要读取的字段名列表,通过逗号分割(如 "品位,岩石类型")

None

Yields:

Name Type Description
dict dict

每个块段的字段数据

Source code in dimine_python_sdk\lib\io\dmb_file.py
230
231
232
233
234
235
236
237
238
239
240
241
def iter_blocks(self, field_name: str|None=None) -> Generator[dict, None, None]:
    """
    遍历块段模型的所有块段数据。

    Args:
        field_name: 要读取的字段名列表,通过逗号分割(如 "品位,岩石类型")

    Yields:
        dict: 每个块段的字段数据
    """
    self._check_open()
    yield from self._session.iter_blocks(field_name)

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\io\dmb_file.py
169
170
171
172
173
174
175
176
def level_size_map(self) -> dict[int, list[float]]:
    """获取 0 ~ max_level 所有层级的块段尺寸对照表

    Returns:
        {level: [size_x, size_y, size_z], ...}
    """
    self._check_open()
    return self._session.level_size_map()

load(file_path)

加载 .dmb 块段模型文件。

Returns:

Type Description
'DmbFile'

self(支持链式调用)

Raises:

Type Description
DmbLoadError

文件不存在或加载失败

Source code in dimine_python_sdk\lib\io\dmb_file.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def load(self, file_path: Union[str, Path]) -> "DmbFile":
    """
    加载 .dmb 块段模型文件。

    Returns:
        self(支持链式调用)

    Raises:
        DmbLoadError: 文件不存在或加载失败
    """
    path = Path(file_path)
    if not path.exists():
        raise DmbLoadError(f"文件不存在: {file_path}")

    try:
        self._session = BlockModelSession.open(str(path))
    except NativeProspectingError as exc:
        raise DmbLoadError(f"加载 .dmb 失败: {file_path}") from exc
    except Exception as exc:
        raise DmbLoadError(f"加载 .dmb 异常: {file_path}") from exc

    self.file_path = str(path)
    return self

to_dataframe()

将块段模型数据转换为 pandas DataFrame。

Returns:

Type Description
'pd.DataFrame'

pd.DataFrame: 块段模型数据表

Raises:

Type Description
DmbError

文件未加载时抛出

ImportError

pandas 未安装时抛出

Source code in dimine_python_sdk\lib\io\dmb_file.py
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
def to_dataframe(self) -> "pd.DataFrame":
    """
    将块段模型数据转换为 pandas DataFrame。

    Returns:
        pd.DataFrame: 块段模型数据表

    Raises:
        DmbError: 文件未加载时抛出
        ImportError: pandas 未安装时抛出
    """
    self._check_open()

    try:
        import pandas as pd
    except ImportError:
        raise ImportError("使用 to_dataframe() 需要安装 pandas: uv add pandas")

    # 获取字段定义作为表头
    all_fields = self.field_definitions  # list[dict] with "name" / "type"
    columns = [f["name"] for f in all_fields]
    import time
    # 逐行收集数据
    t0 = time.perf_counter()
    rows = list(self.iter_blocks())
    t1 = time.perf_counter()
    print(f"  [计时] to_dataframe() 耗时: {t1 - t0:.4f} 秒")
    if not rows:
        return pd.DataFrame(columns=columns)

    return pd.DataFrame(rows)

DmbLoadError

Bases: DmbError

加载失败

Source code in dimine_python_sdk\lib\io\dmb_file.py
45
46
47
48
class DmbLoadError(DmbError):
    """加载失败"""

    pass

dmb_conn(file_path=None)

DMB 文件连接上下文管理器

用法::

with dmb_conn("model.dmb") as dmb:
    print(dmb.info)
    for block in dmb.iter_blocks("品位"):
        print(block)
Source code in dimine_python_sdk\lib\io\dmb_file.py
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
@contextmanager
def dmb_conn(file_path: Optional[Union[str, Path]] = None) -> Generator[DmbFile, None, None]:
    """DMB 文件连接上下文管理器

    用法::

        with dmb_conn("model.dmb") as dmb:
            print(dmb.info)
            for block in dmb.iter_blocks("品位"):
                print(block)
    """
    dmb = DmbFile(file_path)
    try:
        yield dmb
    finally:
        dmb.close()