137 lines
3.9 KiB
Python
137 lines
3.9 KiB
Python
# Copyright (c) 2019-2022, Manfred Moitzi
|
|
# License: MIT License
|
|
from __future__ import annotations
|
|
from typing import TYPE_CHECKING, Optional
|
|
|
|
if TYPE_CHECKING:
|
|
from ezdxf.document import Drawing
|
|
from ezdxf.entities import DXFEntity
|
|
from ezdxf.lldxf.extendedtags import ExtendedTags
|
|
|
|
|
|
__all__ = [
|
|
"register_entity",
|
|
"ENTITY_CLASSES",
|
|
"replace_entity",
|
|
"new",
|
|
"cls",
|
|
"is_bound",
|
|
"create_db_entry",
|
|
"load",
|
|
"bind",
|
|
]
|
|
# Stores all registered classes:
|
|
ENTITY_CLASSES = {}
|
|
# use @set_default_class to register the default entity class:
|
|
DEFAULT_CLASS = None
|
|
|
|
|
|
def set_default_class(cls):
|
|
global DEFAULT_CLASS
|
|
DEFAULT_CLASS = cls
|
|
return cls
|
|
|
|
|
|
def replace_entity(cls):
|
|
name = cls.DXFTYPE
|
|
ENTITY_CLASSES[name] = cls
|
|
return cls
|
|
|
|
|
|
def register_entity(cls):
|
|
name = cls.DXFTYPE
|
|
if name in ENTITY_CLASSES:
|
|
raise TypeError(f"Double registration for DXF type {name}.")
|
|
ENTITY_CLASSES[name] = cls
|
|
return cls
|
|
|
|
|
|
def new(
|
|
dxftype: str, dxfattribs=None, doc: Optional[Drawing] = None
|
|
) -> DXFEntity:
|
|
"""Create a new entity, does not require an instantiated DXF document."""
|
|
entity = cls(dxftype).new(
|
|
handle=None,
|
|
owner=None,
|
|
dxfattribs=dxfattribs,
|
|
doc=doc,
|
|
)
|
|
return entity.cast() if hasattr(entity, "cast") else entity
|
|
|
|
|
|
def create_db_entry(dxftype, dxfattribs, doc: Drawing) -> DXFEntity:
|
|
entity = new(dxftype=dxftype, dxfattribs=dxfattribs)
|
|
bind(entity, doc)
|
|
return entity
|
|
|
|
|
|
def load(tags: ExtendedTags, doc: Optional[Drawing] = None) -> DXFEntity:
|
|
entity = cls(tags.dxftype()).load(tags, doc)
|
|
return entity.cast() if hasattr(entity, "cast") else entity
|
|
|
|
|
|
def cls(dxftype: str) -> DXFEntity:
|
|
"""Returns registered class for `dxftype`."""
|
|
return ENTITY_CLASSES.get(dxftype, DEFAULT_CLASS)
|
|
|
|
|
|
def bind(entity: DXFEntity, doc: Drawing) -> None:
|
|
"""Bind `entity` to the DXF document `doc`.
|
|
|
|
The bind process stores the DXF `entity` in the entity database of the DXF
|
|
document.
|
|
|
|
"""
|
|
assert entity.is_alive, "Can not bind destroyed entity."
|
|
assert doc.entitydb is not None, "Missing entity database."
|
|
entity.doc = doc
|
|
doc.entitydb.add(entity)
|
|
|
|
# Do not call the post_bind_hook() while loading from external sources,
|
|
# not all entities and resources are loaded at this point of time!
|
|
if not doc.is_loading: # type: ignore
|
|
# bind extension dictionary
|
|
if entity.extension_dict is not None:
|
|
xdict = entity.extension_dict
|
|
if xdict.has_valid_dictionary:
|
|
xdict.update_owner(entity.dxf.handle)
|
|
dictionary = xdict.dictionary
|
|
if not is_bound(dictionary, doc):
|
|
bind(dictionary, doc)
|
|
doc.objects.add_object(dictionary)
|
|
entity.post_bind_hook()
|
|
|
|
|
|
def unbind(entity: DXFEntity):
|
|
"""Unbind `entity` from document and layout, but does not destroy the
|
|
entity.
|
|
|
|
Turns `entity` into a virtual entity: no handle, no owner, no document.
|
|
"""
|
|
if entity.is_alive and not entity.is_virtual:
|
|
doc = entity.doc
|
|
if entity.dxf.owner is not None:
|
|
try:
|
|
layout = doc.layouts.get_layout_for_entity(entity) # type: ignore
|
|
except KeyError:
|
|
pass
|
|
else:
|
|
layout.unlink_entity(entity) # type: ignore
|
|
|
|
process_sub_entities = getattr(entity, "process_sub_entities", None)
|
|
if process_sub_entities:
|
|
process_sub_entities(lambda e: unbind(e))
|
|
|
|
doc.entitydb.discard(entity) # type: ignore
|
|
entity.doc = None
|
|
|
|
|
|
def is_bound(entity: DXFEntity, doc: Drawing) -> bool:
|
|
"""Returns ``True`` if `entity`is bound to DXF document `doc`."""
|
|
if not entity.is_alive:
|
|
return False
|
|
if entity.is_virtual or entity.doc is not doc:
|
|
return False
|
|
assert doc.entitydb, "Missing entity database."
|
|
return entity.dxf.handle in doc.entitydb
|