Files
stepanalyser/.venv/lib/python3.12/site-packages/ezdxf/acis/hdr.py
Christian Anetzberger a197de9456 initial
2026-01-22 20:23:51 +01:00

111 lines
3.9 KiB
Python

# Copyright (c) 2022-2024, Manfred Moitzi
# License: MIT License
from __future__ import annotations
from dataclasses import dataclass, field
from datetime import datetime
import struct
from . import const
# ACIS versions exported by BricsCAD:
# R2000/AC1015: 400, "ACIS 4.00 NT", text length has no prefix "@"
# R2004/AC1018: 20800 @ "ACIS 208.00 NT", text length has "@" prefix ??? weird
# R2007/AC1021: 700 @ "ACIS 32.0 NT", text length has "@" prefix
# R2010/AC1024: 700 @ "ACIS 32.0 NT", text length has "@" prefix
# A test showed that R2000 files that contains ACIS v700/32.0 or v20800/208.0
# data can be opened by Autodesk TrueView, BricsCAD and Allplan, so exporting
# only v700/32.0 for all DXF versions should be OK!
# test script: exploration/acis/transplant_acis_data.py
def encode_str(s: str) -> bytes:
b = s.encode("utf8", errors="ignore")
return struct.pack("<BB", const.Tags.STR, len(b)) + b
def encode_double(value: float) -> bytes:
return struct.pack("<Bd", const.Tags.DOUBLE, value)
@dataclass
class AcisHeader:
"""Represents an ACIS file header."""
version: int = const.MIN_EXPORT_VERSION
n_records: int = 0 # can be 0
n_entities: int = 0
flags: int = 0
product_id: str = const.EZDXF_BUILDER_ID
acis_version: str = const.ACIS_VERSION[const.MIN_EXPORT_VERSION]
creation_date: datetime = field(default_factory=datetime.now)
units_in_mm: float = 1.0
asm_version: str = ""
asm_end_marker: bool = False # depends on DXF version: R2013, RT2018
@property
def has_asm_header(self) -> bool:
return self.asm_version != ""
def dumps(self) -> list[str]:
"""Returns the SAT file header as list of strings."""
return [
f"{self.version} {self.n_records} {self.n_entities} {self.flags} ",
self._header_str(),
f"{self.units_in_mm:g} 9.9999999999999995e-007 1e-010 ",
]
def dumpb(self) -> bytes:
"""Returns the SAB file header as bytes."""
buffer: list[bytes] = []
if self.version > 21800:
buffer.append(const.ASM_SIGNATURE)
else:
buffer.append(const.ACIS_SIGNATURE)
data = struct.pack(
"<iiii", self.version, self.n_records, self.n_entities, self.flags
)
buffer.append(data)
buffer.append(encode_str(self.product_id))
buffer.append(encode_str(self.acis_version))
buffer.append(encode_str(self.creation_date.ctime()))
buffer.append(encode_double(self.units_in_mm))
buffer.append(encode_double(const.RES_TOL))
buffer.append(encode_double(const.NOR_TOL))
return b"".join(buffer)
def _header_str(self) -> str:
p_len = len(self.product_id)
a_len = len(self.acis_version)
date = self.creation_date.ctime()
if self.version > 400:
return f"@{p_len} {self.product_id} @{a_len} {self.acis_version} @{len(date)} {date} "
else:
return f"{p_len} {self.product_id} {a_len} {self.acis_version} {len(date)} {date} "
def set_version(self, version: int) -> None:
"""Sets the ACIS version as an integer value and updates the version
string accordingly.
"""
try:
self.acis_version = const.ACIS_VERSION[version]
self.version = version
except KeyError:
raise ValueError(f"invalid ACIS version number {version}")
self.asm_version = const.ASM_VERSION.get(version, "")
def asm_header(self):
from .entities import AsmHeader
return AsmHeader(self.asm_version)
def sat_end_marker(self) -> str:
if self.asm_end_marker:
return const.END_OF_ASM_DATA_SAT + " "
else:
return const.END_OF_ACIS_DATA_SAT + " "
def sab_end_marker(self) -> bytes:
if self.asm_end_marker:
return const.END_OF_ASM_DATA_SAB
else:
return const.END_OF_ACIS_DATA_SAB