Skip to content

dmf_file

DMF 文件业务层:DmfFile、dmf_conn 与相关异常

职责:提供 Pythonic 的 DMF 文件读写接口;直接调用 native.io 完成底层 文件操作,不再经过 _adapter 层。 允许类型:models.、np.ndarray、Path、str、标量 禁止类型:Dm 禁止 import DmPyBindInterface

DmfError

Bases: RuntimeError

DMF 操作异常基类

Source code in dimine_python_sdk\lib\io\dmf_file.py
59
60
61
62
class DmfError(RuntimeError):
    """DMF 操作异常基类"""

    pass

DmfFile

DMF 文件管理器,Python 侧完整内存模型

Source code in dimine_python_sdk\lib\io\dmf_file.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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
class DmfFile:
    """DMF 文件管理器,Python 侧完整内存模型"""

    def __init__(self, file_path: Optional[str] = None):
        self.file_path: Optional[str] = None
        self._layers: List[DmfLayer] = []
        self._features: List[DmfFeature] = []

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

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

    def load(self, file_path: str) -> None:
        """加载 DMF 文件到 Python 内存模型"""
        path = Path(file_path)
        if not path.exists():
            raise DmfLoadError(f"文件不存在: {file_path}")

        try:
            native_features, native_layers = _native_read_dmf(str(file_path))
        except Exception as exc:
            raise DmfLoadError(f"加载失败: {file_path}") from exc

        self._features = [_native_feature_to_model(f) for f in native_features]
        feature_index = _build_feature_index(self._features)
        self._layers = [
            _native_layer_to_model(lyr, feature_index, fallback_name=f"L{i}")
            for i, lyr in enumerate(native_layers)
        ]

        self.file_path = file_path

    def save(self, file_path: Optional[str] = None) -> None:
        """将 Python 内存模型保存为 DMF 文件"""
        save_path = file_path or self.file_path
        if not save_path:
            raise DmfSaveError("未指定保存路径")

        native_layers = [_model_layer_to_native(lyr) for lyr in self._layers]
        native_features = [_model_feature_to_native(f) for f in self._features]

        try:
            _native_write_dmf(str(save_path), native_layers, native_features)
        except Exception as exc:
            raise DmfSaveError(f"保存失败: {save_path}") from exc

        self.file_path = str(save_path)

    def close(self) -> None:
        """释放资源"""
        self._layers.clear()
        self._features.clear()
        self.file_path = None

    # ------------------------------------------------------------------
    # 内部辅助
    # ------------------------------------------------------------------

    def _resolve_layer(self, index_or_name: Union[int, str]) -> tuple[int, DmfLayer]:
        """解析图层索引/名称,返回 (idx, DmfLayer)"""
        if isinstance(index_or_name, int):
            idx = index_or_name
            if 0 <= idx < len(self._layers):
                return idx, self._layers[idx]
            raise IndexError(f"图层索引 {index_or_name} 超出范围")

        for i, layer in enumerate(self._layers):
            if layer.name == index_or_name:
                return i, layer
        raise KeyError(f"未找到图层: {index_or_name}")

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

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

    @property
    def layer_count(self) -> int:
        return len(self._layers)

    @property
    def layer_names(self) -> List[str]:
        return [layer.name for layer in self._layers]

    @property
    def layers(self) -> List[DmfLayer]:
        """所有图层(直接返回内存模型)"""
        return self._layers

    @property
    def info(self) -> Dict[str, Any]:
        total = sum(layer.entity_count for layer in self._layers)
        return {
            "file": self.file_path or "",
            "name": self.name,
            "layers": self.layer_count,
            "total_entities": total,
            "layer_names": self.layer_names,
            "features": self.feature_names,
            "feature_count": len(self._features),
        }

    # ------------------------------------------------------------------
    # 要素操作
    # ------------------------------------------------------------------

    @property
    def features(self) -> List[DmfFeature]:
        """已注册的要素定义列表"""
        return self._features

    @property
    def feature_names(self) -> List[str]:
        """已注册要素名称列表"""
        return [f.name for f in self._features]

    def add_feature(
        self,
        name: str,
        properties: Optional[List[PropertyInfo]] = None,
    ) -> DmfFeature:
        """
        注册要素定义(名称 + 属性列表)

        :param name: 要素名称
        :param properties: 属性定义列表,为空列表时表示该要素无预定义属性
        :return: 注册的 DmfFeature 实例
        """
        if not isinstance(name, str) or not name.strip():
            raise ValueError("要素名称不能为空字符串")
        feature = DmfFeature(feature_name=name.strip(), feature_define=properties or [])
        self._features.append(feature)
        return feature

    # ------------------------------------------------------------------
    # 图层操作
    # ------------------------------------------------------------------

    def get_layer(self, index_or_name: Union[int, str]) -> DmfLayer:
        """获取图层(直接返回内存模型)"""
        _, layer = self._resolve_layer(index_or_name)
        return layer

    def add_layer(self, name: str) -> DmfLayer:
        """添加新图层(仅更新内存模型)"""
        if not name.strip():
            raise ValueError("图层名称不能为空")

        idx = len(self._layers)
        new_layer = DmfLayer(
            id=str(idx),
            name=name.strip(),
            entities=[],
        )
        self._layers.append(new_layer)
        return new_layer

    # ------------------------------------------------------------------
    # 实体插入 —— 仅修改内存模型
    # ------------------------------------------------------------------

    def insert_point(
        self,
        layer: Union[int, str],
        position: np.ndarray,
        *,
        name: str = "",
        properties: Optional[List[PropertyValue]] = None,
    ) -> None:
        """向指定图层插入点实体"""
        _, lyr = self._resolve_layer(layer)
        lyr.insert_point(position, name=name)
        if properties:
            lyr.entities[-1].properties = list(properties)

    def insert_line(
        self,
        layer: Union[int, str],
        start: np.ndarray,
        end: np.ndarray,
        *,
        name: str = "",
        properties: Optional[List[PropertyValue]] = None,
    ) -> None:
        """向指定图层插入直线"""
        _, lyr = self._resolve_layer(layer)
        lyr.insert_line(start, end, name=name)
        if properties:
            lyr.entities[-1].properties = list(properties)

    def insert_polyline(
        self,
        layer: Union[int, str],
        points: np.ndarray,
        *,
        name: str = "",
        properties: Optional[List[PropertyValue]] = None,
    ) -> None:
        """向指定图层插入多段线"""
        _, lyr = self._resolve_layer(layer)
        lyr.insert_polyline(points, name=name)
        if properties:
            lyr.entities[-1].properties = list(properties)

    def insert_shell(
        self,
        layer: Union[int, str],
        points: np.ndarray,
        faces: np.ndarray,
        *,
        name: str = "",
        properties: Optional[List[PropertyValue]] = None,
    ) -> None:
        """向指定图层插入三维实体(Shell)"""
        _, lyr = self._resolve_layer(layer)
        lyr.insert_shell(points, faces, name=name)
        if properties:
            lyr.entities[-1].properties = list(properties)

    def insert_text(
        self,
        layer: Union[int, str],
        position: np.ndarray,
        text: str,
        *,
        name: str = "",
        properties: Optional[List[PropertyValue]] = None,
    ) -> None:
        """向指定图层插入文本标注"""
        _, lyr = self._resolve_layer(layer)
        lyr.insert_text(position, text, name=name)
        if properties:
            lyr.entities[-1].properties = list(properties)

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

    def __getitem__(self, index_or_name: Union[int, str]) -> DmfLayer:
        return self.get_layer(index_or_name)

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

    def __iter__(self):
        return iter(self._layers)

    def __contains__(self, name: str) -> bool:
        return name in self.layer_names

    def __repr__(self) -> str:
        return (
            f"DmfFile('{self.file_path or ''}', "
            f"layers={self.layer_count}, "
            f"entities={sum(layer.entity_count for layer in self._layers)})"
        )

    def __enter__(self):
        return self

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

feature_names property

已注册要素名称列表

features property

已注册的要素定义列表

layers property

所有图层(直接返回内存模型)

name property

文件名(不含扩展名)

add_feature(name, properties=None)

注册要素定义(名称 + 属性列表)

:param name: 要素名称 :param properties: 属性定义列表,为空列表时表示该要素无预定义属性 :return: 注册的 DmfFeature 实例

Source code in dimine_python_sdk\lib\io\dmf_file.py
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
def add_feature(
    self,
    name: str,
    properties: Optional[List[PropertyInfo]] = None,
) -> DmfFeature:
    """
    注册要素定义(名称 + 属性列表)

    :param name: 要素名称
    :param properties: 属性定义列表,为空列表时表示该要素无预定义属性
    :return: 注册的 DmfFeature 实例
    """
    if not isinstance(name, str) or not name.strip():
        raise ValueError("要素名称不能为空字符串")
    feature = DmfFeature(feature_name=name.strip(), feature_define=properties or [])
    self._features.append(feature)
    return feature

add_layer(name)

添加新图层(仅更新内存模型)

Source code in dimine_python_sdk\lib\io\dmf_file.py
460
461
462
463
464
465
466
467
468
469
470
471
472
def add_layer(self, name: str) -> DmfLayer:
    """添加新图层(仅更新内存模型)"""
    if not name.strip():
        raise ValueError("图层名称不能为空")

    idx = len(self._layers)
    new_layer = DmfLayer(
        id=str(idx),
        name=name.strip(),
        entities=[],
    )
    self._layers.append(new_layer)
    return new_layer

close()

释放资源

Source code in dimine_python_sdk\lib\io\dmf_file.py
361
362
363
364
365
def close(self) -> None:
    """释放资源"""
    self._layers.clear()
    self._features.clear()
    self.file_path = None

get_layer(index_or_name)

获取图层(直接返回内存模型)

Source code in dimine_python_sdk\lib\io\dmf_file.py
455
456
457
458
def get_layer(self, index_or_name: Union[int, str]) -> DmfLayer:
    """获取图层(直接返回内存模型)"""
    _, layer = self._resolve_layer(index_or_name)
    return layer

insert_line(layer, start, end, *, name='', properties=None)

向指定图层插入直线

Source code in dimine_python_sdk\lib\io\dmf_file.py
492
493
494
495
496
497
498
499
500
501
502
503
504
505
def insert_line(
    self,
    layer: Union[int, str],
    start: np.ndarray,
    end: np.ndarray,
    *,
    name: str = "",
    properties: Optional[List[PropertyValue]] = None,
) -> None:
    """向指定图层插入直线"""
    _, lyr = self._resolve_layer(layer)
    lyr.insert_line(start, end, name=name)
    if properties:
        lyr.entities[-1].properties = list(properties)

insert_point(layer, position, *, name='', properties=None)

向指定图层插入点实体

Source code in dimine_python_sdk\lib\io\dmf_file.py
478
479
480
481
482
483
484
485
486
487
488
489
490
def insert_point(
    self,
    layer: Union[int, str],
    position: np.ndarray,
    *,
    name: str = "",
    properties: Optional[List[PropertyValue]] = None,
) -> None:
    """向指定图层插入点实体"""
    _, lyr = self._resolve_layer(layer)
    lyr.insert_point(position, name=name)
    if properties:
        lyr.entities[-1].properties = list(properties)

insert_polyline(layer, points, *, name='', properties=None)

向指定图层插入多段线

Source code in dimine_python_sdk\lib\io\dmf_file.py
507
508
509
510
511
512
513
514
515
516
517
518
519
def insert_polyline(
    self,
    layer: Union[int, str],
    points: np.ndarray,
    *,
    name: str = "",
    properties: Optional[List[PropertyValue]] = None,
) -> None:
    """向指定图层插入多段线"""
    _, lyr = self._resolve_layer(layer)
    lyr.insert_polyline(points, name=name)
    if properties:
        lyr.entities[-1].properties = list(properties)

insert_shell(layer, points, faces, *, name='', properties=None)

向指定图层插入三维实体(Shell)

Source code in dimine_python_sdk\lib\io\dmf_file.py
521
522
523
524
525
526
527
528
529
530
531
532
533
534
def insert_shell(
    self,
    layer: Union[int, str],
    points: np.ndarray,
    faces: np.ndarray,
    *,
    name: str = "",
    properties: Optional[List[PropertyValue]] = None,
) -> None:
    """向指定图层插入三维实体(Shell)"""
    _, lyr = self._resolve_layer(layer)
    lyr.insert_shell(points, faces, name=name)
    if properties:
        lyr.entities[-1].properties = list(properties)

insert_text(layer, position, text, *, name='', properties=None)

向指定图层插入文本标注

Source code in dimine_python_sdk\lib\io\dmf_file.py
536
537
538
539
540
541
542
543
544
545
546
547
548
549
def insert_text(
    self,
    layer: Union[int, str],
    position: np.ndarray,
    text: str,
    *,
    name: str = "",
    properties: Optional[List[PropertyValue]] = None,
) -> None:
    """向指定图层插入文本标注"""
    _, lyr = self._resolve_layer(layer)
    lyr.insert_text(position, text, name=name)
    if properties:
        lyr.entities[-1].properties = list(properties)

load(file_path)

加载 DMF 文件到 Python 内存模型

Source code in dimine_python_sdk\lib\io\dmf_file.py
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
def load(self, file_path: str) -> None:
    """加载 DMF 文件到 Python 内存模型"""
    path = Path(file_path)
    if not path.exists():
        raise DmfLoadError(f"文件不存在: {file_path}")

    try:
        native_features, native_layers = _native_read_dmf(str(file_path))
    except Exception as exc:
        raise DmfLoadError(f"加载失败: {file_path}") from exc

    self._features = [_native_feature_to_model(f) for f in native_features]
    feature_index = _build_feature_index(self._features)
    self._layers = [
        _native_layer_to_model(lyr, feature_index, fallback_name=f"L{i}")
        for i, lyr in enumerate(native_layers)
    ]

    self.file_path = file_path

save(file_path=None)

将 Python 内存模型保存为 DMF 文件

Source code in dimine_python_sdk\lib\io\dmf_file.py
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
def save(self, file_path: Optional[str] = None) -> None:
    """将 Python 内存模型保存为 DMF 文件"""
    save_path = file_path or self.file_path
    if not save_path:
        raise DmfSaveError("未指定保存路径")

    native_layers = [_model_layer_to_native(lyr) for lyr in self._layers]
    native_features = [_model_feature_to_native(f) for f in self._features]

    try:
        _native_write_dmf(str(save_path), native_layers, native_features)
    except Exception as exc:
        raise DmfSaveError(f"保存失败: {save_path}") from exc

    self.file_path = str(save_path)

DmfInsertError

Bases: DmfError

实体插入参数校验失败

Source code in dimine_python_sdk\lib\io\dmf_file.py
77
78
79
80
class DmfInsertError(DmfError):
    """实体插入参数校验失败"""

    pass

DmfLoadError

Bases: DmfError

加载失败

Source code in dimine_python_sdk\lib\io\dmf_file.py
65
66
67
68
class DmfLoadError(DmfError):
    """加载失败"""

    pass

DmfParseError

Bases: DmfError

单个实体/图层解析失败(可记录日志后继续)

Source code in dimine_python_sdk\lib\io\dmf_file.py
83
84
85
86
class DmfParseError(DmfError):
    """单个实体/图层解析失败(可记录日志后继续)"""

    pass

DmfSaveError

Bases: DmfError

保存失败

Source code in dimine_python_sdk\lib\io\dmf_file.py
71
72
73
74
class DmfSaveError(DmfError):
    """保存失败"""

    pass

dmf_conn(file_path=None)

DMF 文件连接上下文管理器

Source code in dimine_python_sdk\lib\io\dmf_file.py
581
582
583
584
585
586
587
588
@contextmanager
def dmf_conn(file_path: Optional[str] = None) -> Generator[DmfFile, None, None]:
    """DMF 文件连接上下文管理器"""
    dmf = DmfFile(file_path)
    try:
        yield dmf
    finally:
        dmf.close()