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

795 lines
27 KiB
Python

# Copyright (c) 2019-2024, Manfred Moitzi
# License: MIT License
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, cast, Any
from typing_extensions import Self
import logging
from dataclasses import dataclass
from ezdxf.lldxf import validator
from ezdxf.lldxf.attributes import (
DXFAttr,
DXFAttributes,
DefSubclass,
RETURN_DEFAULT,
group_code_mapping,
)
from ezdxf import colors as clr
from ezdxf.lldxf import const
from ezdxf.lldxf.const import (
DXF12,
SUBCLASS_MARKER,
DXF2000,
DXF2007,
DXF2004,
INVALID_NAME_CHARACTERS,
DXFValueError,
LINEWEIGHT_BYBLOCK,
LINEWEIGHT_BYLAYER,
LINEWEIGHT_DEFAULT,
)
from ezdxf.audit import AuditError
from ezdxf.entities.dxfentity import base_class, SubclassProcessor, DXFEntity
from .factory import register_entity
if TYPE_CHECKING:
from ezdxf.entities import DXFNamespace, Viewport, XRecord
from ezdxf.lldxf.tagwriter import AbstractTagWriter
from ezdxf.entitydb import EntityDB
from ezdxf import xref
from ezdxf.audit import Auditor
__all__ = ["Layer", "acdb_symbol_table_record", "LayerOverrides"]
logger = logging.getLogger("ezdxf")
def is_valid_layer_color_index(aci: int) -> bool:
# BYBLOCK or BYLAYER is not valid a layer color!
return (-256 < aci < 256) and aci != 0
def fix_layer_color(aci: int) -> int:
return aci if is_valid_layer_color_index(aci) else 7
def is_valid_layer_lineweight(lw: int) -> bool:
if validator.is_valid_lineweight(lw):
if lw not in (LINEWEIGHT_BYLAYER, LINEWEIGHT_BYBLOCK):
return True
return False
def fix_layer_lineweight(lw: int) -> int:
if lw in (LINEWEIGHT_BYLAYER, LINEWEIGHT_BYBLOCK):
return LINEWEIGHT_DEFAULT
else:
return validator.fix_lineweight(lw)
acdb_symbol_table_record: DefSubclass = DefSubclass("AcDbSymbolTableRecord", {})
acdb_layer_table_record = DefSubclass(
"AcDbLayerTableRecord",
{
# Layer name as string
"name": DXFAttr(2, validator=validator.is_valid_layer_name),
"flags": DXFAttr(70, default=0),
# ACI color index, color < 0 indicates layer status: off
"color": DXFAttr(
62,
default=7,
validator=is_valid_layer_color_index,
fixer=fix_layer_color,
),
# True color as 24 bit int value: 0x00RRGGBB
"true_color": DXFAttr(420, dxfversion=DXF2004, optional=True),
# Linetype name as string
"linetype": DXFAttr(
6, default="Continuous", validator=validator.is_valid_table_name
),
# 0 = don't plot layer; 1 = plot layer
"plot": DXFAttr(
290,
default=1,
dxfversion=DXF2000,
optional=True,
validator=validator.is_integer_bool,
fixer=RETURN_DEFAULT,
),
# Default lineweight 1/100 mm, min 0 = 0.0mm, max 211 = 2.11mm
"lineweight": DXFAttr(
370,
default=LINEWEIGHT_DEFAULT,
dxfversion=DXF2000,
validator=is_valid_layer_lineweight,
fixer=fix_layer_lineweight,
),
# Handle to PlotStyleName, group code 390 is required by AutoCAD
"plotstyle_handle": DXFAttr(390, dxfversion=DXF2000),
# Handle to Material object
"material_handle": DXFAttr(347, dxfversion=DXF2007),
# Handle to ???
"unknown1": DXFAttr(348, dxfversion=DXF2007, optional=True),
},
)
acdb_layer_table_record_group_codes = group_code_mapping(acdb_layer_table_record)
AcAecLayerStandard = "AcAecLayerStandard"
AcCmTransparency = "AcCmTransparency"
@register_entity
class Layer(DXFEntity):
"""DXF LAYER entity"""
DXFTYPE = "LAYER"
DXFATTRIBS = DXFAttributes(
base_class, acdb_symbol_table_record, acdb_layer_table_record
)
DEFAULT_ATTRIBS = {"name": "0"}
FROZEN = 0b00000001
THAW = 0b11111110
LOCK = 0b00000100
UNLOCK = 0b11111011
def load_dxf_attribs(
self, processor: Optional[SubclassProcessor] = None
) -> DXFNamespace:
dxf = super().load_dxf_attribs(processor)
if processor:
processor.simple_dxfattribs_loader(
dxf, acdb_layer_table_record_group_codes # type: ignore
)
return dxf
def export_entity(self, tagwriter: AbstractTagWriter) -> None:
super().export_entity(tagwriter)
if tagwriter.dxfversion > DXF12:
tagwriter.write_tag2(SUBCLASS_MARKER, acdb_symbol_table_record.name)
tagwriter.write_tag2(SUBCLASS_MARKER, acdb_layer_table_record.name)
self.dxf.export_dxf_attribs(
tagwriter,
[
"name",
"flags",
"color",
"true_color",
"linetype",
"plot",
"lineweight",
"plotstyle_handle",
"material_handle",
"unknown1",
],
)
def set_required_attributes(self):
assert self.doc is not None, "valid DXF document required"
if not self.dxf.hasattr("material_handle"):
global_ = self.doc.materials["Global"]
if isinstance(global_, DXFEntity):
handle = global_.dxf.handle
else:
handle = global_
self.dxf.material_handle = handle
if not self.dxf.hasattr("plotstyle_handle"):
normal = self.doc.plotstyles["Normal"]
if isinstance(normal, DXFEntity):
handle = normal.dxf.handle
else:
handle = normal
self.dxf.plotstyle_handle = handle
def is_frozen(self) -> bool:
"""Returns ``True`` if layer is frozen."""
return self.dxf.flags & Layer.FROZEN > 0
def freeze(self) -> None:
"""Freeze layer."""
self.dxf.flags = self.dxf.flags | Layer.FROZEN
def thaw(self) -> None:
"""Thaw layer."""
self.dxf.flags = self.dxf.flags & Layer.THAW
def is_locked(self) -> bool:
"""Returns ``True`` if layer is locked."""
return self.dxf.flags & Layer.LOCK > 0
def lock(self) -> None:
"""Lock layer, entities on this layer are not editable - just important
in CAD applications.
"""
self.dxf.flags = self.dxf.flags | Layer.LOCK
def unlock(self) -> None:
"""Unlock layer, entities on this layer are editable - just important
in CAD applications.
"""
self.dxf.flags = self.dxf.flags & Layer.UNLOCK
def is_off(self) -> bool:
"""Returns ``True`` if layer is off."""
return self.dxf.color < 0
def is_on(self) -> bool:
"""Returns ``True`` if layer is on."""
return not self.is_off()
def on(self) -> None:
"""Switch layer `on` (visible)."""
self.dxf.color = abs(self.dxf.color)
def off(self) -> None:
"""Switch layer `off` (invisible)."""
self.dxf.color = -abs(self.dxf.color)
def get_color(self) -> int:
"""Get layer color, safe method for getting the layer color, because
:attr:`dxf.color` is negative for layer status `off`.
"""
return abs(self.dxf.color)
def set_color(self, color: int) -> None:
"""Set layer color, safe method for setting the layer color, because
:attr:`dxf.color` is negative for layer status `off`.
"""
color = abs(color) if self.is_on() else -abs(color)
self.dxf.color = color
@property
def rgb(self) -> Optional[tuple[int, int, int]]:
"""Returns RGB true color as (r, g, b)-tuple or None if attribute
dxf.true_color is not set.
"""
if self.dxf.hasattr("true_color"):
return clr.int2rgb(self.dxf.get("true_color"))
else:
return None
@rgb.setter
def rgb(self, rgb: tuple[int, int, int]) -> None:
"""Set RGB true color as (r, g, b)-tuple e.g. (12, 34, 56)."""
self.dxf.set("true_color", clr.rgb2int(rgb))
@property
def color(self) -> int:
"""Get layer color, safe method for getting the layer color, because
:attr:`dxf.color` is negative for layer status `off`.
"""
return self.get_color()
@color.setter
def color(self, value: int) -> None:
"""Set layer color, safe method for setting the layer color, because
:attr:`dxf.color` is negative for layer status `off`.
"""
self.set_color(value)
@property
def description(self) -> str:
try:
xdata = self.get_xdata(AcAecLayerStandard)
except DXFValueError:
return ""
else:
if len(xdata) > 1:
# this is the usual case in BricsCAD
return xdata[1].value
else:
return ""
@description.setter
def description(self, value: str) -> None:
# create AppID table entry if not present
if self.doc and AcAecLayerStandard not in self.doc.appids:
self.doc.appids.new(AcAecLayerStandard)
self.discard_xdata(AcAecLayerStandard)
self.set_xdata(AcAecLayerStandard, [(1000, ""), (1000, value)])
@property
def transparency(self) -> float:
try:
xdata = self.get_xdata(AcCmTransparency)
except DXFValueError:
return 0.0
else:
t = xdata[0].value
if t & 0x2000000: # is this a real transparency value?
# Transparency BYBLOCK (0x01000000) make no sense for a layer!?
return clr.transparency2float(t)
return 0.0
@transparency.setter
def transparency(self, value: float) -> None:
# create AppID table entry if not present
if self.doc and AcCmTransparency not in self.doc.appids:
self.doc.appids.new(AcCmTransparency)
if 0 <= value <= 1:
self.discard_xdata(AcCmTransparency)
self.set_xdata(AcCmTransparency, [(1071, clr.float2transparency(value))])
else:
raise ValueError("Value out of range [0, 1].")
def rename(self, name: str) -> None:
"""
Rename layer and all known (documented) references to this layer.
.. warning::
The DXF format is not consistent in storing layer references, the
layers are mostly referenced by their case-insensitive name,
some later introduced entities do reference layers by handle, which
is the safer way in the context of renaming layers.
There is no complete overview of where layer references are
stored, third-party entities are black-boxes with unknown content
and layer names could be stored in the extended data section of any
DXF entity or in XRECORD entities.
Which means that in some rare cases references to the old layer name
can persist, at least this does not invalidate the DXF document.
Args:
name: new layer name
Raises:
ValueError: `name` contains invalid characters: <>/\\":;?*|=`
ValueError: layer `name` already exist
ValueError: renaming of layers ``'0'`` and ``'DEFPOINTS'`` not
possible
"""
if not validator.is_valid_layer_name(name):
raise ValueError(
f"Name contains invalid characters: {INVALID_NAME_CHARACTERS}."
)
assert self.doc is not None, "valid DXF document is required"
layers = self.doc.layers
if self.dxf.name.lower() in ("0", "defpoints"):
raise ValueError(f'Can not rename layer "{self.dxf.name}".')
if layers.has_entry(name):
raise ValueError(f'Layer "{name}" already exist.')
old = self.dxf.name
self.dxf.name = name
layers.replace(old, self)
self._rename_layer_references(old, name)
def _rename_layer_references(self, old_name: str, new_name: str) -> None:
assert self.doc is not None, "valid DXF document is required"
key = self.doc.layers.key
old_key = key(old_name)
for e in self.doc.entitydb.values():
if e.dxf.hasattr("layer") and key(e.dxf.layer) == old_key:
e.dxf.layer = new_name
entity_type = e.dxftype()
if entity_type == "VIEWPORT":
e.rename_frozen_layer(old_name, new_name) # type: ignore
elif entity_type == "LAYER_FILTER":
# todo: if LAYER_FILTER implemented, add support for
# renaming layers
logger.debug(
f'renaming layer "{old_name}" - document contains ' f"LAYER_FILTER"
)
elif entity_type == "LAYER_INDEX":
# todo: if LAYER_INDEX implemented, add support for
# renaming layers
logger.debug(
f'renaming layer "{old_name}" - document contains ' f"LAYER_INDEX"
)
def get_vp_overrides(self) -> LayerOverrides:
"""Returns the :class:`LayerOverrides` object for this layer."""
return LayerOverrides(self)
def register_resources(self, registry: xref.Registry) -> None:
"""Register required resources to the resource registry."""
assert self.doc is not None, "LAYER entity must be assigned to a document"
super().register_resources(registry)
registry.add_linetype(self.dxf.linetype)
registry.add_handle(self.dxf.get("material_handle"))
# current plot style will be replaced by default plot style "Normal"
def map_resources(self, clone: Self, mapping: xref.ResourceMapper) -> None:
"""Translate resources from self to the copied entity."""
assert isinstance(clone, Layer)
super().map_resources(clone, mapping)
self.dxf.linetype = mapping.get_linetype(self.dxf.linetype)
mapping.map_existing_handle(self, clone, "material_handle", optional=True)
# remove handles pointing to the source document:
clone.dxf.discard("plotstyle_handle") # replaced by plot style "Normal"
clone.dxf.discard("unknown1")
# create required handles to resources in the target document
clone.set_required_attributes()
# todo: map layer overrides
# remove layer overrides
clone.discard_extension_dict()
def audit(self, auditor: Auditor) -> None:
super().audit(auditor)
linetype = self.dxf.linetype
if auditor.doc.linetypes.has_entry(linetype):
return
self.dxf.linetype = "Continuous"
auditor.fixed_error(
code=AuditError.UNDEFINED_LINETYPE,
message=f"Replaced undefined linetype {linetype} in layer '{self.dxf.name}' by CONTINUOUS",
dxf_entity=self,
data=linetype,
)
@dataclass
class OverrideAttributes:
aci: int
rgb: Optional[clr.RGB]
transparency: float
linetype: str
lineweight: int
class LayerOverrides:
"""This object stores the layer attribute overridden in VIEWPORT entities,
where each VIEWPORT can have individual layer attribute overrides.
Layer attributes which can be overridden:
- ACI color
- true color (rgb)
- linetype
- lineweight
- transparency
"""
def __init__(self, layer: Layer):
assert layer.doc is not None, "valid DXF document required"
self._layer = layer
self._overrides = load_layer_overrides(layer)
def has_overrides(self, vp_handle: Optional[str] = None) -> bool:
"""Returns ``True`` if attribute overrides exist for the given
:class:`Viewport` handle.
Returns ``True`` if `any` attribute overrides exist if the given
handle is ``None``.
"""
if vp_handle is None:
return bool(self._overrides)
return vp_handle in self._overrides
def commit(self) -> None:
"""Write :class:`Viewport` overrides back into the :class:`Layer` entity.
Without a commit() all changes are lost!
"""
store_layer_overrides(self._layer, self._overrides)
def _acquire_overrides(self, vp_handle: str) -> OverrideAttributes:
"""Returns the OverrideAttributes() instance for `vp_handle`, creates a new
OverrideAttributes() instance if none exist.
"""
return self._overrides.setdefault(
vp_handle,
default_ovr_settings(self._layer),
)
def _get_overrides(self, vp_handle: str) -> OverrideAttributes:
"""Returns the overrides for `vp_handle`, returns the default layer
settings if no Override() instance exist.
"""
try:
return self._overrides[vp_handle]
except KeyError:
return default_ovr_settings(self._layer)
def set_color(self, vp_handle: str, value: int) -> None:
"""Override the :ref:`ACI`.
Raises:
ValueError: invalid color value
"""
# BYBLOCK or BYLAYER is not valid a layer color
if not is_valid_layer_color_index(value):
raise ValueError(f"invalid ACI value: {value}")
vp_overrides = self._acquire_overrides(vp_handle)
vp_overrides.aci = value
def get_color(self, vp_handle: str) -> int:
"""Returns the :ref:`ACI` override or the original layer value if no
override exist.
"""
vp_overrides = self._get_overrides(vp_handle)
return vp_overrides.aci
def set_rgb(self, vp_handle: str, value: Optional[clr.RGB]):
"""Set the RGB override as (red, gree, blue) tuple or ``None`` to remove
the true color setting.
Raises:
ValueError: invalid RGB value
"""
if value is not None and not validator.is_valid_rgb(value):
raise ValueError(f"invalid RGB value: {value}")
vp_overrides = self._acquire_overrides(vp_handle)
vp_overrides.rgb = value
def get_rgb(self, vp_handle: str) -> Optional[clr.RGB]:
"""Returns the RGB override or the original layer value if no
override exist. Returns ``None`` if no true color value is set.
"""
vp_overrides = self._get_overrides(vp_handle)
return vp_overrides.rgb
def set_transparency(self, vp_handle: str, value: float) -> None:
"""Set the transparency override. A transparency of 0.0 is opaque and
1.0 is fully transparent.
Raises:
ValueError: invalid transparency value
"""
if not (0.0 <= value <= 1.0):
raise ValueError(
f"invalid transparency: {value}, has to be in the range [0, 1]"
)
vp_overrides = self._acquire_overrides(vp_handle)
vp_overrides.transparency = value
def get_transparency(self, vp_handle: str) -> float:
"""Returns the transparency override or the original layer value if no
override exist. Returns 0.0 for opaque and 1.0 for fully transparent.
"""
vp_overrides = self._get_overrides(vp_handle)
return vp_overrides.transparency
def set_linetype(self, vp_handle: str, value: str) -> None:
"""Set the linetype override.
Raises:
ValueError: linetype without a LTYPE table entry
"""
if value not in self._layer.doc.linetypes: # type: ignore
raise ValueError(
f"invalid linetype: {value}, a linetype table entry is required"
)
vp_overrides = self._acquire_overrides(vp_handle)
vp_overrides.linetype = value
def get_linetype(self, vp_handle: str) -> str:
"""Returns the linetype override or the original layer value if no
override exist.
"""
vp_overrides = self._get_overrides(vp_handle)
return vp_overrides.linetype
def get_lineweight(self, vp_handle: str) -> int:
"""Returns the lineweight override or the original layer value if no
override exist.
"""
vp_overrides = self._get_overrides(vp_handle)
return vp_overrides.lineweight
def set_lineweight(self, vp_handle: str, value: int) -> None:
"""Set the lineweight override.
Raises:
ValueError: invalid lineweight value
"""
if not is_valid_layer_lineweight(value):
raise ValueError(
f"invalid lineweight: {value}, a linetype table entry is required"
)
vp_overrides = self._acquire_overrides(vp_handle)
vp_overrides.lineweight = value
def discard(self, vp_handle: Optional[str] = None) -> None:
"""Discard all attribute overrides for the given :class:`Viewport`
handle or for all :class:`Viewport` entities if the handle is ``None``.
"""
if vp_handle is None:
self._overrides.clear()
return
try:
del self._overrides[vp_handle]
except KeyError:
pass
def default_ovr_settings(layer) -> OverrideAttributes:
"""Returns the default settings of the layer."""
return OverrideAttributes(
aci=layer.color,
rgb=layer.rgb,
transparency=layer.transparency,
linetype=layer.dxf.linetype,
lineweight=layer.dxf.lineweight,
)
def is_layer_frozen_in_vp(layer, vp_handle) -> bool:
"""Returns ``True`` if layer is frozen in VIEWPORT defined by the vp_handle."""
vp = cast("Viewport", layer.doc.entitydb.get(vp_handle))
if vp is not None:
return layer.dxf.name in vp.frozen_layers
return False
def load_layer_overrides(layer: Layer) -> dict[str, OverrideAttributes]:
"""Load all VIEWPORT overrides from the layer extension dictionary."""
def get_ovr(vp_handle: str):
ovr = overrides.get(vp_handle)
if ovr is None:
ovr = default_ovr_settings(layer)
overrides[vp_handle] = ovr
return ovr
def set_alpha(vp_handle: str, value: int):
ovr = get_ovr(vp_handle)
ovr.transparency = clr.transparency2float(value)
def set_color(vp_handle: str, value: int):
ovr = get_ovr(vp_handle)
type_, data = clr.decode_raw_color(value)
if type_ == clr.COLOR_TYPE_ACI:
ovr.aci = data
elif type_ == clr.COLOR_TYPE_RGB:
ovr.rgb = data
def set_ltype(vp_handle: str, lt_handle: str):
ltype = entitydb.get(lt_handle)
if ltype is not None:
ovr = get_ovr(vp_handle)
ovr.linetype = ltype.dxf.name
def set_lw(vp_handle: str, value: int):
ovr = get_ovr(vp_handle)
ovr.lineweight = value
def set_xdict_state():
xdict = layer.get_extension_dict()
for key, code, setter in [
(const.OVR_ALPHA_KEY, const.OVR_ALPHA_CODE, set_alpha),
(const.OVR_COLOR_KEY, const.OVR_COLOR_CODE, set_color),
(const.OVR_LTYPE_KEY, const.OVR_LTYPE_CODE, set_ltype),
(const.OVR_LW_KEY, const.OVR_LW_CODE, set_lw),
]:
xrec = cast("XRecord", xdict.get(key))
if xrec is not None:
for vp_handle, value in _load_ovr_values(xrec, code):
setter(vp_handle, value)
assert layer.doc is not None, "valid DXF document required"
entitydb: EntityDB = layer.doc.entitydb
assert entitydb is not None, "valid entity database required"
overrides: dict[str, OverrideAttributes] = dict()
if not layer.has_extension_dict:
return overrides
set_xdict_state()
return overrides
def _load_ovr_values(xrec: XRecord, group_code):
tags = xrec.tags
handles = [value for code, value in tags.find_all(const.OVR_VP_HANDLE_CODE)]
values = [value for code, value in tags.find_all(group_code)]
return zip(handles, values)
def store_layer_overrides(
layer: Layer, overrides: dict[str, OverrideAttributes]
) -> None:
"""Store all VIEWPORT overrides in the layer extension dictionary.
Replaces all existing overrides!
"""
from ezdxf.lldxf.types import DXFTag
def get_xdict():
if layer.has_extension_dict:
return layer.get_extension_dict()
else:
return layer.new_extension_dict()
def set_xdict_tags(key: str, tags: list[DXFTag]):
from ezdxf.entities import XRecord
xdict = get_xdict()
xrec = xdict.get(key)
if not isinstance(xrec, XRecord) and xrec is not None:
logger.debug(
f"Found entity {str(xrec)} as override storage in {str(layer)} "
f"but expected XRECORD"
)
xrec = None
if xrec is None:
xrec = xdict.add_xrecord(key)
xrec.dxf.cloning = 1
xrec.reset(tags)
def del_xdict_tags(key: str):
if not layer.has_extension_dict:
return
xdict = layer.get_extension_dict()
xrec = xdict.get(key)
if xrec is not None:
xrec.destroy()
xdict.discard(key)
def make_tags(data: list[tuple[Any, str]], name: str, code: int) -> list[DXFTag]:
tags: list[DXFTag] = []
for value, vp_handle in data:
tags.extend(
[
DXFTag(102, name),
DXFTag(const.OVR_VP_HANDLE_CODE, vp_handle),
DXFTag(code, value),
DXFTag(102, "}"),
]
)
return tags
def collect_alphas():
for vp_handle, ovr in vp_exist.items():
if ovr.transparency != default.transparency:
yield clr.float2transparency(ovr.transparency), vp_handle
def collect_colors():
for vp_handle, ovr in vp_exist.items():
if ovr.aci != default.aci or ovr.rgb != default.rgb:
if ovr.rgb is None:
raw_color = clr.encode_raw_color(ovr.aci)
else:
raw_color = clr.encode_raw_color(ovr.rgb)
yield raw_color, vp_handle
def collect_linetypes():
for vp_handle, ovr in vp_exist.items():
if ovr.linetype != default.linetype:
ltype = layer.doc.linetypes.get(ovr.linetype)
if ltype is not None:
yield ltype.dxf.handle, vp_handle
def collect_lineweights():
for vp_handle, ovr in vp_exist.items():
if ovr.lineweight != default.lineweight:
yield ovr.lineweight, vp_handle
assert layer.doc is not None, "valid DXF document required"
entitydb = layer.doc.entitydb
vp_exist = {
vp_handle: ovr
for vp_handle, ovr in overrides.items()
if (vp_handle in entitydb) and entitydb[vp_handle].is_alive
}
default = default_ovr_settings(layer)
alphas = list(collect_alphas())
if alphas:
tags = make_tags(alphas, const.OVR_APP_ALPHA, const.OVR_ALPHA_CODE)
set_xdict_tags(const.OVR_ALPHA_KEY, tags)
else:
del_xdict_tags(const.OVR_ALPHA_KEY)
colors = list(collect_colors())
if colors:
tags = make_tags(colors, const.OVR_APP_COLOR, const.OVR_COLOR_CODE)
set_xdict_tags(const.OVR_COLOR_KEY, tags)
else:
del_xdict_tags(const.OVR_COLOR_KEY)
linetypes = list(collect_linetypes())
if linetypes:
tags = make_tags(linetypes, const.OVR_APP_LTYPE, const.OVR_LTYPE_CODE)
set_xdict_tags(const.OVR_LTYPE_KEY, tags)
else:
del_xdict_tags(const.OVR_LTYPE_KEY)
lineweights = list(collect_lineweights())
if lineweights:
tags = make_tags(lineweights, const.OVR_APP_LW, const.OVR_LW_CODE)
set_xdict_tags(const.OVR_LW_KEY, tags)
else:
del_xdict_tags(const.OVR_LW_KEY)