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

960 lines
33 KiB
Python

# Copyright (c) 2019-2024, Manfred Moitzi
# License: MIT License
from __future__ import annotations
from typing import TYPE_CHECKING, Iterable, Optional
from typing_extensions import Self
import logging
from ezdxf.enums import MTextLineAlignment
from ezdxf.lldxf.attributes import (
DXFAttr,
DXFAttributes,
DefSubclass,
VIRTUAL_TAG,
group_code_mapping,
RETURN_DEFAULT,
)
from ezdxf.lldxf import const
from ezdxf.lldxf.const import DXF12, DXF2007, DXF2000
from ezdxf.lldxf import validator
from ezdxf.render.arrows import ARROWS
from .dxfentity import SubclassProcessor, DXFEntity, base_class
from .layer import acdb_symbol_table_record
from .factory import register_entity
if TYPE_CHECKING:
from ezdxf.document import Drawing
from ezdxf.entities import DXFNamespace
from ezdxf.lldxf.tagwriter import AbstractTagWriter
from ezdxf import xref
__all__ = ["DimStyle"]
logger = logging.getLogger("ezdxf")
acdb_dimstyle = DefSubclass(
"AcDbDimStyleTableRecord",
{
"name": DXFAttr(2, default="Standard", validator=validator.is_valid_table_name),
"flags": DXFAttr(70, default=0),
"dimpost": DXFAttr(3, default=""),
"dimapost": DXFAttr(4, default=""),
# Arrow names are the base data -> handle (DXF2000) is set at export
"dimblk": DXFAttr(5, default=""),
"dimblk1": DXFAttr(6, default=""),
"dimblk2": DXFAttr(7, default=""),
"dimscale": DXFAttr(40, default=1),
# 0 has a special but unknown meaning, handle as 1.0
"dimasz": DXFAttr(41, default=2.5),
"dimexo": DXFAttr(42, default=0.625),
"dimdli": DXFAttr(43, default=3.75),
"dimexe": DXFAttr(44, default=1.25),
"dimrnd": DXFAttr(45, default=0),
"dimdle": DXFAttr(46, default=0), # dimension line extension
"dimtp": DXFAttr(47, default=0),
"dimtm": DXFAttr(48, default=0),
# undocumented: length of extension line if fixed (dimfxlon = 1)
"dimfxl": DXFAttr(49, dxfversion=DXF2007, default=2.5),
# jog angle, Angle of oblique dimension line segment in jogged radius dimension
"dimjogang": DXFAttr(50, dxfversion=DXF2007, default=90, optional=True),
# measurement text height
"dimtxt": DXFAttr(140, default=2.5),
# center marks and center lines; 0 = off, <0 = center line, >0 = center mark
"dimcen": DXFAttr(141, default=2.5),
"dimtsz": DXFAttr(142, default=0),
"dimaltf": DXFAttr(143, default=0.03937007874),
# measurement length factor
"dimlfac": DXFAttr(144, default=1),
# text vertical position if dimtad=0
"dimtvp": DXFAttr(145, default=0),
"dimtfac": DXFAttr(146, default=1),
# default gap around the measurement text
"dimgap": DXFAttr(147, default=0.625),
"dimaltrnd": DXFAttr(148, dxfversion=DXF2000, default=0),
# 0=None, 1=canvas color, 2=dimtfillclr
"dimtfill": DXFAttr(69, dxfversion=DXF2007, default=0),
# color index for dimtfill==2
"dimtfillclr": DXFAttr(70, dxfversion=DXF2007, default=0),
"dimtol": DXFAttr(71, default=0),
"dimlim": DXFAttr(72, default=0),
# text inside horizontal
"dimtih": DXFAttr(73, default=0),
# text outside horizontal
"dimtoh": DXFAttr(74, default=0),
# suppress extension line 1
"dimse1": DXFAttr(75, default=0),
# suppress extension line 2
"dimse2": DXFAttr(76, default=0),
# text vertical location: 0=center; 1+2+3=above; 4=below
"dimtad": DXFAttr(77, default=1),
"dimzin": DXFAttr(78, default=8),
# dimazin:
# 0 = Displays all leading and trailing zeros
# 1 = Suppresses leading zeros in decimal dimensions (for example, 0.5000 becomes .5000)
# 2 = Suppresses trailing zeros in decimal dimensions (for example, 12.5000 becomes 12.5)
# 3 = Suppresses leading and trailing zeros (for example, 0.5000 becomes .5)
"dimazin": DXFAttr(79, default=3, dxfversion=DXF2000),
# dimarcsym: show arc symbol
# 0 = preceding text
# 1 = above text
# 2 = disable
"dimarcsym": DXFAttr(90, dxfversion=DXF2000, optional=True),
"dimalt": DXFAttr(170, default=0),
"dimaltd": DXFAttr(171, default=3),
"dimtofl": DXFAttr(172, default=1),
"dimsah": DXFAttr(173, default=0),
# force dimension text inside
"dimtix": DXFAttr(174, default=0),
"dimsoxd": DXFAttr(175, default=0),
# dimension line color
"dimclrd": DXFAttr(176, default=0),
# extension line color
"dimclre": DXFAttr(177, default=0),
# text color
"dimclrt": DXFAttr(178, default=0),
"dimadec": DXFAttr(179, dxfversion=DXF2000, default=2),
"dimunit": DXFAttr(270), # obsolete
"dimdec": DXFAttr(271, dxfversion=DXF2000, default=2),
# can appear multiple times ???
"dimtdec": DXFAttr(272, dxfversion=DXF2000, default=2),
"dimaltu": DXFAttr(273, dxfversion=DXF2000, default=2),
"dimalttd": DXFAttr(274, dxfversion=DXF2000, default=3),
# 0 = Decimal degrees
# 1 = Degrees/minutes/seconds
# 2 = Grad
# 3 = Radians
"dimaunit": DXFAttr(
275,
dxfversion=DXF2000,
default=0,
validator=validator.is_in_integer_range(0, 4),
fixer=RETURN_DEFAULT,
),
"dimfrac": DXFAttr(276, dxfversion=DXF2000, default=0),
"dimlunit": DXFAttr(277, dxfversion=DXF2000, default=2),
"dimdsep": DXFAttr(278, dxfversion=DXF2000, default=44),
# 0 = Moves the dimension line with dimension text
# 1 = Adds a leader when dimension text is moved
# 2 = Allows text to be moved freely without a leader
"dimtmove": DXFAttr(279, dxfversion=DXF2000, default=0),
# 0=center; 1=left; 2=right; 3=above ext1; 4=above ext2
"dimjust": DXFAttr(280, dxfversion=DXF2000, default=0),
# suppress first part of the dimension line
"dimsd1": DXFAttr(281, dxfversion=DXF2000, default=0),
# suppress second part of the dimension line
"dimsd2": DXFAttr(282, dxfversion=DXF2000, default=0),
"dimtolj": DXFAttr(283, dxfversion=DXF2000, default=0),
"dimtzin": DXFAttr(284, dxfversion=DXF2000, default=8),
"dimaltz": DXFAttr(285, dxfversion=DXF2000, default=0),
"dimalttz": DXFAttr(286, dxfversion=DXF2000, default=0),
"dimfit": DXFAttr(287), # obsolete, now use DIMATFIT and DIMTMOVE
"dimupt": DXFAttr(288, dxfversion=DXF2000, default=0),
# Determines how dimension text and arrows are arranged when space is
# not sufficient to place both within the extension lines.
# 0 = Places both text and arrows outside extension lines
# 1 = Moves arrows first, then text
# 2 = Moves text first, then arrows
# 3 = Moves either text or arrows, whichever fits best
"dimatfit": DXFAttr(289, dxfversion=DXF2000, default=3),
# undocumented: 1 = fixed extension line length
"dimfxlon": DXFAttr(290, dxfversion=DXF2007, default=0),
# Virtual tags are transformed at DXF export - for DIMSTYLE the
# resource names are exported as <name>_handle tags:
# virtual: set/get STYLE by name
"dimtxsty": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2000),
# virtual: set/get leader arrow by block name
"dimldrblk": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2000),
# virtual: set/get LINETYPE by name
"dimltype": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007),
# virtual: set/get referenced LINETYPE by name
"dimltex2": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007),
# virtual: set/get referenced LINETYPE by name
"dimltex1": DXFAttr(VIRTUAL_TAG, dxfversion=DXF2007),
# Entity handles are not used internally (see virtual tags above),
# these handles are set at DXF export:
# handle of referenced STYLE entry
"dimtxsty_handle": DXFAttr(340, dxfversion=DXF2000),
# handle of referenced BLOCK_RECORD
"dimblk_handle": DXFAttr(342, dxfversion=DXF2000),
# handle of referenced BLOCK_RECORD
"dimblk1_handle": DXFAttr(343, dxfversion=DXF2000),
# handle of referenced BLOCK_RECORD
"dimblk2_handle": DXFAttr(344, dxfversion=DXF2000),
# handle of referenced BLOCK_RECORD
"dimldrblk_handle": DXFAttr(341, dxfversion=DXF2000),
# handle of linetype for dimension line
"dimltype_handle": DXFAttr(345, dxfversion=DXF2007),
# handle of linetype for extension line 1
"dimltex1_handle": DXFAttr(346, dxfversion=DXF2007),
# handle of linetype for extension line 2
"dimltex2_handle": DXFAttr(347, dxfversion=DXF2007),
# dimension line lineweight enum value, default BYBLOCK
"dimlwd": DXFAttr(371, default=const.LINEWEIGHT_BYBLOCK, dxfversion=DXF2000),
# extension line lineweight enum value, default BYBLOCK
"dimlwe": DXFAttr(372, default=const.LINEWEIGHT_BYBLOCK, dxfversion=DXF2000),
},
)
acdb_dimstyle_group_codes = group_code_mapping(acdb_dimstyle)
EXPORT_MAP_R2007 = [
"name",
"flags",
"dimscale",
"dimasz",
"dimexo",
"dimdli",
"dimexe",
"dimrnd",
"dimdle",
"dimtp",
"dimtm",
"dimfxl",
"dimjogang",
"dimtxt",
"dimcen",
"dimtsz",
"dimaltf",
"dimlfac",
"dimtvp",
"dimtfac",
"dimgap",
"dimaltrnd",
"dimtfill",
"dimtfillclr",
"dimtol",
"dimlim",
"dimtih",
"dimtoh",
"dimse1",
"dimse2",
"dimtad",
"dimzin",
"dimazin",
"dimarcsym",
"dimalt",
"dimaltd",
"dimtofl",
"dimsah",
"dimtix",
"dimsoxd",
"dimclrd",
"dimclre",
"dimclrt",
"dimadec",
"dimdec",
"dimtdec",
"dimaltu",
"dimalttd",
"dimaunit",
"dimfrac",
"dimlunit",
"dimdsep",
"dimtmove",
"dimjust",
"dimsd1",
"dimsd2",
"dimtolj",
"dimtzin",
"dimaltz",
"dimalttz",
"dimupt",
"dimatfit",
"dimfxlon",
"dimtxsty_handle",
"dimldrblk_handle",
"dimblk_handle",
"dimblk1_handle",
"dimblk2_handle",
"dimltype_handle",
"dimltex1_handle",
"dimltex2_handle",
"dimlwd",
"dimlwe",
]
EXPORT_MAP_R2000 = [
"name",
"flags",
"dimpost",
"dimapost",
"dimscale",
"dimasz",
"dimexo",
"dimdli",
"dimexe",
"dimrnd",
"dimdle",
"dimtp",
"dimtm",
"dimtxt",
"dimcen",
"dimtsz",
"dimaltf",
"dimlfac",
"dimtvp",
"dimtfac",
"dimgap",
"dimaltrnd",
"dimtol",
"dimlim",
"dimtih",
"dimtoh",
"dimse1",
"dimse2",
"dimtad",
"dimzin",
"dimazin",
"dimarcsym",
"dimalt",
"dimaltd",
"dimtofl",
"dimsah",
"dimtix",
"dimsoxd",
"dimclrd",
"dimclre",
"dimclrt",
"dimadec",
"dimdec",
"dimtdec",
"dimaltu",
"dimalttd",
"dimaunit",
"dimfrac",
"dimlunit",
"dimdsep",
"dimtmove",
"dimjust",
"dimsd1",
"dimsd2",
"dimtolj",
"dimtzin",
"dimaltz",
"dimalttz",
"dimupt",
"dimatfit",
"dimtxsty_handle",
"dimldrblk_handle",
"dimblk_handle",
"dimblk1_handle",
"dimblk2_handle",
"dimlwd",
"dimlwe",
]
EXPORT_MAP_R12 = [
"name",
"flags",
"dimpost",
"dimapost",
"dimblk",
"dimblk1",
"dimblk2",
"dimscale",
"dimasz",
"dimexo",
"dimdli",
"dimexe",
"dimrnd",
"dimdle",
"dimtp",
"dimtm",
"dimtxt",
"dimcen",
"dimtsz",
"dimaltf",
"dimlfac",
"dimtvp",
"dimtfac",
"dimgap",
"dimtol",
"dimlim",
"dimtih",
"dimtoh",
"dimse1",
"dimse2",
"dimtad",
"dimzin",
"dimalt",
"dimaltd",
"dimtofl",
"dimsah",
"dimtix",
"dimsoxd",
"dimclrd",
"dimclre",
"dimclrt",
]
DIM_TEXT_STYLE_ATTR = "dimtxsty"
DIM_ARROW_HEAD_ATTRIBS = ("dimblk", "dimblk1", "dimblk2", "dimldrblk")
DIM_LINETYPE_ATTRIBS = ("dimltype", "dimltex1", "dimltex2")
def dim_filter(name: str) -> bool:
return name.startswith("dim")
@register_entity
class DimStyle(DXFEntity):
"""DXF BLOCK_RECORD table entity"""
DXFTYPE = "DIMSTYLE"
DXFATTRIBS = DXFAttributes(base_class, acdb_symbol_table_record, acdb_dimstyle)
CODE_TO_DXF_ATTRIB = dict(DXFATTRIBS.build_group_code_items(dim_filter))
@property
def dxfversion(self):
return self.doc.dxfversion
def load_dxf_attribs(
self, processor: Optional[SubclassProcessor] = None
) -> DXFNamespace:
dxf = super().load_dxf_attribs(processor)
if processor:
# group code 70 is used 2x, simple_dxfattribs_loader() can't be used!
processor.fast_load_dxfattribs(dxf, acdb_dimstyle_group_codes, 2)
return dxf
def post_load_hook(self, doc: Drawing) -> None:
# 2nd Loading stage: resolve handles to names.
# ezdxf uses names for blocks, linetypes and text style as internal
# data, handles are set at export.
super().post_load_hook(doc)
db = doc.entitydb
for attrib_name in DIM_ARROW_HEAD_ATTRIBS:
if self.dxf.hasattr(attrib_name):
continue
block_record_handle = self.dxf.get(attrib_name + "_handle")
if block_record_handle and block_record_handle != "0":
try:
name = db[block_record_handle].dxf.name
except KeyError:
logger.info(
f"Replace undefined block reference "
f"#{block_record_handle} by default arrow."
)
name = "" # default arrow name
else:
name = "" # default arrow name
self.dxf.set(attrib_name, name)
style_handle = self.dxf.get("dimtxsty_handle", None)
if style_handle and style_handle != "0":
try:
self.dxf.dimtxsty = db[style_handle].dxf.name
except (KeyError, AttributeError):
logger.info(f"Ignore undefined text style #{style_handle}.")
for attrib_name in DIM_LINETYPE_ATTRIBS:
lt_handle = self.dxf.get(attrib_name + "_handle", None)
if lt_handle and lt_handle != "0":
try:
name = db[lt_handle].dxf.name
except (KeyError, AttributeError):
logger.info(f"Ignore undefined line type #{lt_handle}.")
else:
self.dxf.set(attrib_name, name)
# Remove all handles, to be sure setting handles for resource names
# at export.
self.discard_handles()
def export_entity(self, tagwriter: AbstractTagWriter) -> None:
super().export_entity(tagwriter)
if tagwriter.dxfversion > DXF12:
tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_symbol_table_record.name)
tagwriter.write_tag2(const.SUBCLASS_MARKER, acdb_dimstyle.name)
if tagwriter.dxfversion > DXF12:
# Set handles from dimblk names:
self.set_handles()
if tagwriter.dxfversion == DXF12:
attribs = EXPORT_MAP_R12
elif tagwriter.dxfversion < DXF2007:
attribs = EXPORT_MAP_R2000
else:
attribs = EXPORT_MAP_R2007
self.dxf.export_dxf_attribs(tagwriter, attribs)
def register_resources(self, registry: xref.Registry) -> None:
"""Register required resources to the resource registry."""
assert self.doc is not None, "DIMSTYLE entity must be assigned to a document"
super().register_resources(registry)
# ezdxf uses names for blocks, linetypes and text style as internal data
# register text style
text_style_name = self.dxf.get(DIM_TEXT_STYLE_ATTR)
if text_style_name:
try:
style = self.doc.styles.get(text_style_name)
registry.add_entity(style)
except const.DXFTableEntryError:
pass
# register linetypes
for attr_name in DIM_LINETYPE_ATTRIBS:
ltype_name = self.dxf.get(attr_name)
if ltype_name is None:
continue
try:
ltype = self.doc.linetypes.get(ltype_name)
registry.add_entity(ltype)
except const.DXFTableEntryError:
pass
# Note: ACAD arrow head blocks are created automatically at export in set_blk_handle()
for attr_name in DIM_ARROW_HEAD_ATTRIBS:
arrow_name = self.dxf.get(attr_name)
if arrow_name is None:
continue
if not ARROWS.is_acad_arrow(arrow_name):
# user defined arrow head block
registry.add_block_name(arrow_name)
def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None:
"""Translate resources from self to the copied entity."""
assert isinstance(clone, DimStyle)
super().map_resources(clone, mapping)
# ezdxf uses names for blocks, linetypes and text style as internal data
# map text style
text_style = self.dxf.get(DIM_TEXT_STYLE_ATTR)
if text_style:
clone.dxf.dimtxsty = mapping.get_text_style(text_style)
# map linetypes
for attr_name in DIM_LINETYPE_ATTRIBS:
ltype_name = self.dxf.get(attr_name)
if ltype_name:
clone.dxf.set(attr_name, mapping.get_linetype(ltype_name))
# Note: ACAD arrow head blocks are created automatically at export in set_blk_handle()
for attr_name in DIM_ARROW_HEAD_ATTRIBS:
arrow_name = self.dxf.get(attr_name)
if arrow_name is None:
continue
if not ARROWS.is_acad_arrow(arrow_name):
# user defined arrow head block
arrow_name = mapping.get_block_name(arrow_name)
clone.dxf.set(attr_name, arrow_name)
def set_handles(self):
style = self.dxf.get(DIM_TEXT_STYLE_ATTR)
if style:
self.dxf.dimtxsty_handle = self.doc.styles.get(style).dxf.handle
for attr_name in DIM_ARROW_HEAD_ATTRIBS:
block_name = self.dxf.get(attr_name)
if block_name:
self.set_blk_handle(attr_name + "_handle", block_name)
for attr_name in DIM_LINETYPE_ATTRIBS:
get_linetype = self.doc.linetypes.get
ltype_name = self.dxf.get(attr_name)
if ltype_name:
handle = get_linetype(ltype_name).dxf.handle
self.dxf.set(attr_name + "_handle", handle)
def discard_handles(self):
for attr in (
"dimblk",
"dimblk1",
"dimblk2",
"dimldrblk",
"dimltype",
"dimltex1",
"dimltex2",
"dimtxsty",
):
self.dxf.discard(attr + "_handle")
def set_blk_handle(self, attr: str, arrow_name: str) -> None:
if arrow_name == ARROWS.closed_filled:
# special arrow, no handle needed (is '0' if set)
# do not create block by default, this will be done if arrow is used
# and block record handle is not needed here
self.dxf.discard(attr)
return
assert self.doc is not None, "valid DXF document required"
blocks = self.doc.blocks
if ARROWS.is_acad_arrow(arrow_name):
# create block, because the block record handle is needed here
block_name = ARROWS.create_block(blocks, arrow_name)
else:
block_name = arrow_name
blk = blocks.get(block_name)
if blk is not None:
self.set_dxf_attrib(attr, blk.block_record_handle)
else:
raise const.DXFValueError(f'Block "{arrow_name}" does not exist.')
def get_arrow_block_name(self, name: str) -> str:
assert self.doc is not None, "valid DXF document required"
handle = self.get_dxf_attrib(name, None)
if handle in (None, "0"):
# unset handle or handle '0' is default closed filled arrow
return ARROWS.closed_filled
else:
block_name = get_block_name_by_handle(handle, self.doc)
# Returns standard arrow name or the user defined block name:
return ARROWS.arrow_name(block_name)
def set_linetypes(self, dimline=None, ext1=None, ext2=None) -> None:
if self.dxfversion < DXF2007:
logger.debug("Linetype support requires DXF R2007+.")
if dimline is not None:
self.dxf.dimltype = dimline
if ext1 is not None:
self.dxf.dimltex1 = ext1
if ext2 is not None:
self.dxf.dimltex2 = ext2
def print_dim_attribs(self) -> None:
attdef = self.DXFATTRIBS.get
for name, value in self.dxfattribs().items():
if name.startswith("dim"):
print(f"{name} ({attdef(name).code}) = {value}") # type: ignore
def copy_to_header(self, doc: Drawing):
"""Copy all dimension style variables to HEADER section of `doc`."""
attribs = self.dxfattribs()
header = doc.header
header["$DIMSTYLE"] = self.dxf.name
for name, value in attribs.items():
if name.startswith("dim"):
header_var = "$" + name.upper()
try:
header[header_var] = value
except const.DXFKeyError:
logger.debug(f"Unsupported header variable: {header_var}.")
def set_arrows(
self, blk: str = "", blk1: str = "", blk2: str = "", ldrblk: str = ""
) -> None:
"""Set arrows by block names or AutoCAD standard arrow names, set
DIMTSZ to ``0`` which disables tick.
Args:
blk: block/arrow name for both arrows, if DIMSAH is 0
blk1: block/arrow name for first arrow, if DIMSAH is 1
blk2: block/arrow name for second arrow, if DIMSAH is 1
ldrblk: block/arrow name for leader
"""
self.set_dxf_attrib("dimblk", blk)
self.set_dxf_attrib("dimblk1", blk1)
self.set_dxf_attrib("dimblk2", blk2)
self.set_dxf_attrib("dimldrblk", ldrblk)
self.set_dxf_attrib("dimtsz", 0) # use blocks
# only existing BLOCK definitions allowed
if self.doc:
blocks = self.doc.blocks
for b in (blk, blk1, blk2, ldrblk):
if ARROWS.is_acad_arrow(b): # not real blocks
ARROWS.create_block(blocks, b)
continue
if b and b not in blocks:
raise const.DXFValueError(f'BLOCK "{blk}" does not exist.')
def set_tick(self, size: float = 1) -> None:
"""Set tick `size`, which also disables arrows, a tick is just an
oblique stroke as marker.
Args:
size: arrow size in drawing units
"""
self.set_dxf_attrib("dimtsz", size)
def set_text_align(
self,
halign: Optional[str] = None,
valign: Optional[str] = None,
vshift: Optional[float] = None,
) -> None:
"""Set measurement text alignment, `halign` defines the horizontal
alignment (requires DXF R2000+), `valign` defines the vertical
alignment, `above1` and `above2` means above extension line 1 or 2 and
aligned with extension line.
Args:
halign: "left", "right", "center", "above1", "above2",
requires DXF R2000+
valign: "above", "center", "below"
vshift: vertical text shift, if `valign` is "center";
>0 shift upward,
<0 shift downwards
"""
if valign:
valign = valign.lower()
self.set_dxf_attrib("dimtad", const.DIMTAD[valign])
if valign == "center" and vshift is not None:
self.set_dxf_attrib("dimtvp", vshift)
if halign:
self.set_dxf_attrib("dimjust", const.DIMJUST[halign.lower()])
def set_text_format(
self,
prefix: str = "",
postfix: str = "",
rnd: Optional[float] = None,
dec: Optional[int] = None,
sep: Optional[str] = None,
leading_zeros: bool = True,
trailing_zeros: bool = True,
):
"""Set dimension text format, like prefix and postfix string, rounding
rule and number of decimal places.
Args:
prefix: Dimension text prefix text as string
postfix: Dimension text postfix text as string
rnd: Rounds all dimensioning distances to the specified value, for
instance, if DIMRND is set to 0.25, all distances round to the
nearest 0.25 unit. If you set DIMRND to 1.0, all distances round
to the nearest integer.
dec: Sets the number of decimal places displayed for the primary
units of a dimension, requires DXF R2000+
sep: "." or "," as decimal separator, requires DXF R2000+
leading_zeros: Suppress leading zeros for decimal dimensions
if ``False``
trailing_zeros: Suppress trailing zeros for decimal dimensions
if ``False``
"""
if prefix or postfix:
self.dxf.dimpost = prefix + "<>" + postfix
if rnd is not None:
self.dxf.dimrnd = rnd
# works only with decimal dimensions not inch and feet, US user set dimzin directly
if leading_zeros is not None or trailing_zeros is not None:
dimzin = 0
if leading_zeros is False:
dimzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
if trailing_zeros is False:
dimzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
self.dxf.dimzin = dimzin
if dec is not None:
self.dxf.dimdec = dec
if sep is not None:
self.dxf.dimdsep = ord(sep)
def set_dimline_format(
self,
color: Optional[int] = None,
linetype: Optional[str] = None,
lineweight: Optional[int] = None,
extension: Optional[float] = None,
disable1: Optional[bool] = None,
disable2: Optional[bool] = None,
):
"""Set dimension line properties
Args:
color: color index
linetype: linetype as string, requires DXF R2007+
lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm,
requires DXF R2000+
extension: extension length
disable1: ``True`` to suppress first part of dimension line,
requires DXF R2000+
disable2: ``True`` to suppress second part of dimension line,
requires DXF R2000+
"""
if color is not None:
self.dxf.dimclrd = color
if extension is not None:
self.dxf.dimdle = extension
if lineweight is not None:
self.dxf.dimlwd = lineweight
if disable1 is not None:
self.dxf.dimsd1 = disable1
if disable2 is not None:
self.dxf.dimsd2 = disable2
if linetype is not None:
self.dxf.dimltype = linetype
def set_extline_format(
self,
color: Optional[int] = None,
lineweight: Optional[int] = None,
extension: Optional[float] = None,
offset: Optional[float] = None,
fixed_length: Optional[float] = None,
):
"""Set common extension line attributes.
Args:
color: color index
lineweight: line weight as int, 13 = 0.13mm, 200 = 2.00mm
extension: extension length above dimension line
offset: offset from measurement point
fixed_length: set fixed length extension line, length below the
dimension line
"""
if color is not None:
self.dxf.dimclre = color
if extension is not None:
self.dxf.dimexe = extension
if offset is not None:
self.dxf.dimexo = offset
if lineweight is not None:
self.dxf.dimlwe = lineweight
if fixed_length is not None:
self.dxf.dimfxlon = 1
self.dxf.dimfxl = fixed_length
def set_extline1(self, linetype: Optional[str] = None, disable=False):
"""Set extension line 1 attributes.
Args:
linetype: linetype for extension line 1, requires DXF R2007+
disable: disable extension line 1 if ``True``
"""
if disable:
self.dxf.dimse1 = 1
if linetype is not None:
self.dxf.dimltex1 = linetype
def set_extline2(self, linetype: Optional[str] = None, disable=False):
"""Set extension line 2 attributes.
Args:
linetype: linetype for extension line 2, requires DXF R2007+
disable: disable extension line 2 if ``True``
"""
if disable:
self.dxf.dimse2 = 1
if linetype is not None:
self.dxf.dimltex2 = linetype
def set_tolerance(
self,
upper: float,
lower: Optional[float] = None,
hfactor: float = 1.0,
align: Optional[MTextLineAlignment] = None,
dec: Optional[int] = None,
leading_zeros: Optional[bool] = None,
trailing_zeros: Optional[bool] = None,
) -> None:
"""Set tolerance text format, upper and lower value, text height
factor, number of decimal places or leading and trailing zero
suppression.
Args:
upper: upper tolerance value
lower: lower tolerance value, if ``None`` same as upper
hfactor: tolerance text height factor in relation to the dimension
text height
align: tolerance text alignment enum :class:`ezdxf.enums.MTextLineAlignment`
requires DXF R2000+
dec: Sets the number of decimal places displayed,
requires DXF R2000+
leading_zeros: suppress leading zeros for decimal dimensions
if ``False``, requires DXF R2000+
trailing_zeros: suppress trailing zeros for decimal dimensions
if ``False``, requires DXF R2000+
"""
# Exclusive tolerances mode, disable limits
self.dxf.dimtol = 1
self.dxf.dimlim = 0
self.dxf.dimtp = float(upper)
if lower is not None:
self.dxf.dimtm = float(lower)
else:
self.dxf.dimtm = float(upper)
if hfactor is not None:
self.dxf.dimtfac = float(hfactor)
# Works only with decimal dimensions not inch and feet, US user set
# dimzin directly.
if leading_zeros is not None or trailing_zeros is not None:
dimtzin = 0
if leading_zeros is False:
dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
if trailing_zeros is False:
dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
self.dxf.dimtzin = dimtzin
if align is not None:
self.dxf.dimtolj = int()
if dec is not None:
self.dxf.dimtdec = int(dec)
def set_limits(
self,
upper: float,
lower: float,
hfactor: float = 1.0,
dec: Optional[int] = None,
leading_zeros: Optional[bool] = None,
trailing_zeros: Optional[bool] = None,
) -> None:
"""Set limits text format, upper and lower limit values, text height
factor, number of decimal places or leading and trailing zero
suppression.
Args:
upper: upper limit value added to measurement value
lower: lower limit value subtracted from measurement value
hfactor: limit text height factor in relation to the dimension
text height
dec: Sets the number of decimal places displayed,
requires DXF R2000+
leading_zeros: suppress leading zeros for decimal dimensions
if ``False``, requires DXF R2000+
trailing_zeros: suppress trailing zeros for decimal dimensions
if ``False``, requires DXF R2000+
"""
# Exclusive limits mode, disable tolerances
self.dxf.dimlim = 1
self.dxf.dimtol = 0
self.dxf.dimtp = float(upper)
self.dxf.dimtm = float(lower)
self.dxf.dimtfac = float(hfactor)
# Works only with decimal dimensions not inch and feet, US user set
# dimzin directly.
if leading_zeros is not None or trailing_zeros is not None:
dimtzin = 0
if leading_zeros is False:
dimtzin = const.DIMZIN_SUPPRESSES_LEADING_ZEROS
if trailing_zeros is False:
dimtzin += const.DIMZIN_SUPPRESSES_TRAILING_ZEROS
self.dxf.dimtzin = dimtzin
self.dxf.dimtolj = 0 # set bottom as default
if dec is not None:
self.dxf.dimtdec = int(dec)
def __referenced_blocks__(self) -> Iterable[str]:
"""Support for "ReferencedBlocks" protocol."""
if self.doc:
blocks = self.doc.blocks
for attrib_name in ("dimblk", "dimblk1", "dimblk2", "dimldrblk"):
name = self.dxf.get(attrib_name, None)
if name:
block = blocks.get(name, None)
if block is not None:
yield block.block_record.dxf.handle
def get_block_name_by_handle(handle, doc: Drawing, default="") -> str:
try:
entry = doc.entitydb[handle]
except const.DXFKeyError:
block_name = default
else:
block_name = entry.dxf.name
return block_name