Skip to content

io

Native Layer v2 IO 模块

文件转换、DMF 读写、文本实体。 对外不暴露 C++ 对象。

NativeTextHandle

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

Source code in dimine_python_sdk\lib\native\io.py
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
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
157
158
159
160
161
162
163
@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
237
238
239
def set_normal(self) -> None:
    """自动计算法线方向"""
    self._cpp_obj.SetNormal()

to_model()

转换为 NativeText 数据模型

Source code in dimine_python_sdk\lib\native\io.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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,
    )

convert_file(source, target)

执行文件格式转换。

Raises:

Type Description
NativeIOError

不支持的格式或转换失败

Source code in dimine_python_sdk\lib\native\io.py
 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
def convert_file(source: str, target: str) -> None:
    """
    执行文件格式转换。

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

    # 以扩展名字符串为键,避免 native 层反向依赖 models.file_format
    if src_ext in _UNSUPPORTED_SOURCE_EXTS:
        raise NativeIOError(
            f"暂不支持的源文件格式: {src_ext}(MapGIS 仅支持作为目标格式,"
            f"即 dmf -> mgis;mgis -> dmf 当前不可用)"
        )

    if src_ext not in _CONVERTER_MAP:
        raise NativeIOError(f"不支持的源文件格式: {src_ext}")

    if tgt_ext not in _CONVERTER_MAP[src_ext]:
        raise NativeIOError(f"不支持的转换方向: {src_ext} -> {tgt_ext}")

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

    # native 转换函数(如 dmIO_CADToDmf)返回的是 JSON 字符串
    # {"state":"failed","message":"..."},而非 bool。若直接 `if not raw:`,
    # 非空字符串/字典恒为真,会把失败静默吞掉(表现为“成功但无文件产出”)。
    try:
        parse_json_response(raw, NativeIOError, f"转换 {source_path} -> {target_path}")
    except NativeProcessError as exc:
        raise NativeIOError(str(exc)) from exc

    # state=ok 只代表底层函数未硬报错,不代表目标文件真正产出(例如目标目录为空)。
    # 这里兜底校验产物存在且非空,避免“假成功”。
    # 注意:MapGIS 等格式的产物是文件夹而非 target 文件,必须按文件夹校验,
    # 否则会把正常生成 `.../新文件2/` 的转换误判为失败。
    if tgt_ext in _DIRECTORY_OUTPUT_EXTS:
        _validate_directory_output(
            output_artifact_path(target_path),
            _DIRECTORY_OUTPUT_SUFFIXES[tgt_ext],
        )
    else:
        _validate_file_output(target_path)

output_artifact_path(target)

返回转换产物的实际路径。

多数格式的产物就是 target 指向的文件;MapGIS(.mgis)等文件夹形式 格式的产物是同目录下去掉扩展名的同名文件夹。

:param target: 用户传入的目标路径 :return: 实际产物路径(文件或文件夹)

Source code in dimine_python_sdk\lib\native\io.py
58
59
60
61
62
63
64
65
66
67
68
69
70
def output_artifact_path(target: "str | Path") -> Path:
    """返回转换产物的实际路径。

    多数格式的产物就是 ``target`` 指向的文件;MapGIS(``.mgis``)等文件夹形式
    格式的产物是同目录下去掉扩展名的同名文件夹。

    :param target: 用户传入的目标路径
    :return: 实际产物路径(文件或文件夹)
    """
    target_path = Path(target)
    if target_path.suffix.lower() in _DIRECTORY_OUTPUT_EXTS:
        return target_path.parent / target_path.stem
    return target_path

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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
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

write_dmf(file_path, layers, features=None)

将 NativeLayer/NativeFeature 写入 DMF 文件。

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

Source code in dimine_python_sdk\lib\native\io.py
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
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)