refactor: excel parse
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
# Copyright (c) 2011-2022, Manfred Moitzi
|
||||
# License: MIT License
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Iterator, Iterable, Union, cast, Optional
|
||||
from collections import Counter, OrderedDict
|
||||
import logging
|
||||
|
||||
from ezdxf.lldxf.const import DXFStructureError, DXF2004, DXF2000, DXFKeyError
|
||||
from ezdxf.entities.dxfclass import DXFClass
|
||||
from ezdxf.entities.dxfentity import DXFEntity, DXFTagStorage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ezdxf.document import Drawing
|
||||
from ezdxf.lldxf.tagwriter import AbstractTagWriter
|
||||
|
||||
logger = logging.getLogger("ezdxf")
|
||||
|
||||
# name: cpp_class_name (2), app_name (3), flags(90), was_a_proxy (280),
|
||||
# is_an_entity (281)
|
||||
# Multiple entries for 'name' are possible and supported, ClassSection stores
|
||||
# entries with key: (name, cpp_class_name).
|
||||
# 0 <ctrl> CLASS
|
||||
# 1 <str> MPOLYGON
|
||||
# 2 <str> AcDbMPolygon
|
||||
# 3 <str> "AcMPolygonObj15|Version(1.0.0.0) Product Desc: Object enabler for the AcDbMPolyg ... odesk.com"
|
||||
# 90 <int> 3071, b101111111111
|
||||
# 280 <int> 0
|
||||
# 281 <int> 1
|
||||
CLASS_DEFINITIONS = {
|
||||
"ACDBDICTIONARYWDFLT": [
|
||||
"AcDbDictionaryWithDefault",
|
||||
"ObjectDBX Classes",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"SUN": ["AcDbSun", "SCENEOE", 1153, 0, 0],
|
||||
"DICTIONARYVAR": ["AcDbDictionaryVar", "ObjectDBX Classes", 0, 0, 0],
|
||||
"TABLESTYLE": ["AcDbTableStyle", "ObjectDBX Classes", 4095, 0, 0],
|
||||
"MATERIAL": ["AcDbMaterial", "ObjectDBX Classes", 1153, 0, 0],
|
||||
"VISUALSTYLE": ["AcDbVisualStyle", "ObjectDBX Classes", 4095, 0, 0],
|
||||
"SCALE": ["AcDbScale", "ObjectDBX Classes", 1153, 0, 0],
|
||||
"MLEADERSTYLE": ["AcDbMLeaderStyle", "ACDB_MLEADERSTYLE_CLASS", 4095, 0, 0],
|
||||
"MLEADER": ["AcDbMLeader", "ACDB_MLEADER_CLASS", 3071, 0, 1],
|
||||
"MPOLYGON": ["AcDbMPolygon", "AcMPolygonObj15", 1025, 0, 1],
|
||||
"CELLSTYLEMAP": ["AcDbCellStyleMap", "ObjectDBX Classes", 1152, 0, 0],
|
||||
"EXACXREFPANELOBJECT": ["ExAcXREFPanelObject", "EXAC_ESW", 1025, 0, 0],
|
||||
"NPOCOLLECTION": [
|
||||
"AcDbImpNonPersistentObjectsCollection",
|
||||
"ObjectDBX Classes",
|
||||
1153,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"LAYER_INDEX": ["AcDbLayerIndex", "ObjectDBX Classes", 0, 0, 0],
|
||||
"SPATIAL_INDEX": ["AcDbSpatialIndex", "ObjectDBX Classes", 0, 0, 0],
|
||||
"IDBUFFER": ["AcDbIdBuffer", "ObjectDBX Classes", 0, 0, 0],
|
||||
"DIMASSOC": ["AcDbDimAssoc", "AcDbDimAssoc", 0, 0, 0],
|
||||
"ACDBSECTIONVIEWSTYLE": [
|
||||
"AcDbSectionViewStyle",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"ACDBDETAILVIEWSTYLE": [
|
||||
"AcDbDetailViewStyle",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"IMAGEDEF": ["AcDbRasterImageDef", "ISM", 0, 0, 0],
|
||||
"RASTERVARIABLES": ["AcDbRasterVariables", "ISM", 0, 0, 0],
|
||||
"IMAGEDEF_REACTOR": ["AcDbRasterImageDefReactor", "ISM", 1, 0, 0],
|
||||
"IMAGE": ["AcDbRasterImage", "ISM", 2175, 0, 1],
|
||||
"PDFDEFINITION": ["AcDbPdfDefinition", "ObjectDBX Classes", 1153, 0, 0],
|
||||
"PDFUNDERLAY": ["AcDbPdfReference", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"DWFDEFINITION": ["AcDbDwfDefinition", "ObjectDBX Classes", 1153, 0, 0],
|
||||
"DWFUNDERLAY": ["AcDbDwfReference", "ObjectDBX Classes", 1153, 0, 1],
|
||||
"DGNDEFINITION": ["AcDbDgnDefinition", "ObjectDBX Classes", 1153, 0, 0],
|
||||
"DGNUNDERLAY": ["AcDbDgnReference", "ObjectDBX Classes", 1153, 0, 1],
|
||||
"MENTALRAYRENDERSETTINGS": [
|
||||
"AcDbMentalRayRenderSettings",
|
||||
"SCENEOE",
|
||||
1024,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"ACDBPLACEHOLDER": ["AcDbPlaceHolder", "ObjectDBX Classes", 0, 0, 0],
|
||||
"LAYOUT": ["AcDbLayout", "ObjectDBX Classes", 0, 0, 0],
|
||||
"SURFACE": ["AcDbSurface", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"EXTRUDEDSURFACE": ["AcDbExtrudedSurface", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"LOFTEDSURFACE": ["AcDbLoftedSurface", "ObjectDBX Classes", 0, 0, 1],
|
||||
"REVOLVEDSURFACE": ["AcDbRevolvedSurface", "ObjectDBX Classes", 0, 0, 1],
|
||||
"SWEPTSURFACE": ["AcDbSweptSurface", "ObjectDBX Classes", 0, 0, 1],
|
||||
"PLANESURFACE": ["AcDbPlaneSurface", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"NURBSSURFACE": ["AcDbNurbSurface", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"ACDBASSOCEXTRUDEDSURFACEACTIONBODY": [
|
||||
"AcDbAssocExtrudedSurfaceActionBody",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"ACDBASSOCLOFTEDSURFACEACTIONBODY": [
|
||||
"AcDbAssocLoftedSurfaceActionBody",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"ACDBASSOCREVOLVEDSURFACEACTIONBODY": [
|
||||
"AcDbAssocRevolvedSurfaceActionBody",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"ACDBASSOCSWEPTSURFACEACTIONBODY": [
|
||||
"AcDbAssocSweptSurfaceActionBody",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
0,
|
||||
],
|
||||
"HELIX": ["AcDbHelix", "ObjectDBX Classes", 4095, 0, 1],
|
||||
"WIPEOUT": ["AcDbWipeout", "WipeOut", 127, 0, 1],
|
||||
"WIPEOUTVARIABLES": ["AcDbWipeoutVariables", "WipeOut", 0, 0, 0],
|
||||
"FIELDLIST": ["AcDbFieldList", "ObjectDBX Classes", 1152, 0, 0],
|
||||
"GEODATA": ["AcDbGeoData", "ObjectDBX Classes", 4095, 0, 0],
|
||||
"SORTENTSTABLE": ["AcDbSortentsTable", "ObjectDBX Classes", 0, 0, 0],
|
||||
"ACAD_TABLE": ["AcDbTable", "ObjectDBX Classes", 1025, 0, 1],
|
||||
"ARC_DIMENSION": ["AcDbArcDimension", "ObjectDBX Classes", 1025, 0, 1],
|
||||
"LARGE_RADIAL_DIMENSION": [
|
||||
"AcDbRadialDimensionLarge",
|
||||
"ObjectDBX Classes",
|
||||
1025,
|
||||
0,
|
||||
1,
|
||||
],
|
||||
}
|
||||
|
||||
REQ_R2000 = [
|
||||
"ACDBDICTIONARYWDFLT",
|
||||
"SUN",
|
||||
"VISUALSTYLE",
|
||||
"MATERIAL",
|
||||
"SCALE",
|
||||
"TABLESTYLE",
|
||||
"MLEADERSTYLE",
|
||||
"DICTIONARYVAR",
|
||||
"CELLSTYLEMAP",
|
||||
"MENTALRAYRENDERSETTINGS",
|
||||
"ACDBDETAILVIEWSTYLE",
|
||||
"ACDBSECTIONVIEWSTYLE",
|
||||
"RASTERVARIABLES",
|
||||
"ACDBPLACEHOLDER",
|
||||
"LAYOUT",
|
||||
]
|
||||
|
||||
REQ_R2004 = [
|
||||
"ACDBDICTIONARYWDFLT",
|
||||
"SUN",
|
||||
"VISUALSTYLE",
|
||||
"MATERIAL",
|
||||
"SCALE",
|
||||
"TABLESTYLE",
|
||||
"MLEADERSTYLE",
|
||||
"DICTIONARYVAR",
|
||||
"CELLSTYLEMAP",
|
||||
"MENTALRAYRENDERSETTINGS",
|
||||
"ACDBDETAILVIEWSTYLE",
|
||||
"ACDBSECTIONVIEWSTYLE",
|
||||
"RASTERVARIABLES",
|
||||
]
|
||||
|
||||
REQUIRED_CLASSES = {
|
||||
DXF2000: REQ_R2000,
|
||||
DXF2004: REQ_R2004,
|
||||
}
|
||||
|
||||
|
||||
class ClassesSection:
|
||||
def __init__(
|
||||
self,
|
||||
doc: Optional[Drawing] = None,
|
||||
entities: Optional[Iterable[DXFEntity]] = None,
|
||||
):
|
||||
# Multiple entries for 'name' possible -> key is (name, cpp_class_name)
|
||||
# DXFClasses are not stored in the entities database, because CLASS has
|
||||
# no handle.
|
||||
self.classes: dict[tuple[str, str], DXFClass] = OrderedDict()
|
||||
self.doc = doc
|
||||
if entities is not None:
|
||||
self.load(iter(entities))
|
||||
|
||||
def __iter__(self) -> Iterator[DXFClass]:
|
||||
return (cls for cls in self.classes.values())
|
||||
|
||||
def load(self, entities: Iterator[DXFEntity]) -> None:
|
||||
section_head = cast(DXFTagStorage, next(entities))
|
||||
|
||||
if section_head.dxftype() != "SECTION" or section_head.base_class[1] != (
|
||||
2,
|
||||
"CLASSES",
|
||||
):
|
||||
raise DXFStructureError("Critical structure error in CLASSES section.")
|
||||
|
||||
for cls_entity in entities:
|
||||
if isinstance(cls_entity, DXFClass):
|
||||
self.register(cls_entity)
|
||||
else:
|
||||
logger.warning(
|
||||
f"Ignored invalid DXF entity type '{cls_entity.dxftype()}'"
|
||||
f" in section CLASSES."
|
||||
)
|
||||
|
||||
def register(
|
||||
self, classes: Optional[Union[DXFClass, Iterable[DXFClass]]] = None
|
||||
) -> None:
|
||||
if classes is None:
|
||||
return
|
||||
|
||||
if isinstance(classes, DXFClass):
|
||||
classes = (classes,)
|
||||
|
||||
for dxfclass in classes:
|
||||
key = dxfclass.key
|
||||
if key not in self.classes:
|
||||
self.classes[key] = dxfclass
|
||||
|
||||
def add_class(self, name: str):
|
||||
"""Register a known class by `name`."""
|
||||
if name not in CLASS_DEFINITIONS:
|
||||
return
|
||||
cls_data = CLASS_DEFINITIONS[name]
|
||||
cls = DXFClass.new(doc=self.doc)
|
||||
cpp, app, flags, proxy, entity = cls_data
|
||||
cls.update_dxf_attribs(
|
||||
{
|
||||
"name": name,
|
||||
"cpp_class_name": cpp,
|
||||
"app_name": app,
|
||||
"flags": flags,
|
||||
"was_a_proxy": proxy,
|
||||
"is_an_entity": entity,
|
||||
}
|
||||
)
|
||||
self.register(cls)
|
||||
|
||||
def get(self, name: str) -> DXFClass:
|
||||
"""Returns the first class matching `name`.
|
||||
|
||||
Storage key is the ``(name, cpp_class_name)`` tuple, because there are
|
||||
some classes with the same :attr:`name` but different
|
||||
:attr:`cpp_class_names`.
|
||||
|
||||
"""
|
||||
for cls in self.classes.values():
|
||||
if cls.dxf.name == name:
|
||||
return cls
|
||||
raise DXFKeyError(name)
|
||||
|
||||
def add_required_classes(self, dxfversion: str) -> None:
|
||||
"""Add all required CLASS definitions for the specified DXF version."""
|
||||
names = REQUIRED_CLASSES.get(dxfversion, REQ_R2004)
|
||||
for name in names:
|
||||
self.add_class(name)
|
||||
|
||||
if self.doc is None: # testing environment SUT
|
||||
return
|
||||
|
||||
dxf_types_in_use = self.doc.entitydb.dxf_types_in_use()
|
||||
if "IMAGE" in dxf_types_in_use:
|
||||
self.add_class("IMAGE")
|
||||
self.add_class("IMAGEDEF")
|
||||
self.add_class("IMAGEDEF_REACTOR")
|
||||
if "PDFUNDERLAY" in dxf_types_in_use:
|
||||
self.add_class("PDFDEFINITION")
|
||||
self.add_class("PDFUNDERLAY")
|
||||
if "DWFUNDERLAY" in dxf_types_in_use:
|
||||
self.add_class("DWFDEFINITION")
|
||||
self.add_class("DWFUNDERLAY")
|
||||
if "DGNUNDERLAY" in dxf_types_in_use:
|
||||
self.add_class("DGNDEFINITION")
|
||||
self.add_class("DGNUNDERLAY")
|
||||
if "EXTRUDEDSURFACE" in dxf_types_in_use:
|
||||
self.add_class("EXTRUDEDSURFACE")
|
||||
self.add_class("ACDBASSOCEXTRUDEDSURFACEACTIONBODY")
|
||||
if "LOFTEDSURFACE" in dxf_types_in_use:
|
||||
self.add_class("LOFTEDSURFACE")
|
||||
self.add_class("ACDBASSOCLOFTEDSURFACEACTIONBODY")
|
||||
if "REVOLVEDSURFACE" in dxf_types_in_use:
|
||||
self.add_class("REVOLVEDSURFACE")
|
||||
self.add_class("ACDBASSOCREVOLVEDSURFACEACTIONBODY")
|
||||
if "SWEPTSURFACE" in dxf_types_in_use:
|
||||
self.add_class("SWEPTSURFACE")
|
||||
self.add_class("ACDBASSOCSWEPTSURFACEACTIONBODY")
|
||||
|
||||
for dxftype in dxf_types_in_use:
|
||||
self.add_class(dxftype)
|
||||
|
||||
def export_dxf(self, tagwriter: AbstractTagWriter) -> None:
|
||||
"""Export DXF tags. (internal API)"""
|
||||
tagwriter.write_str(" 0\nSECTION\n 2\nCLASSES\n")
|
||||
for dxfclass in self.classes.values():
|
||||
dxfclass.export_dxf(tagwriter)
|
||||
tagwriter.write_str(" 0\nENDSEC\n")
|
||||
|
||||
def update_instance_counters(self) -> None:
|
||||
"""Update CLASS instance counter for all registered classes, requires
|
||||
DXF R2004+.
|
||||
"""
|
||||
assert self.doc is not None
|
||||
if self.doc.dxfversion < DXF2004:
|
||||
return # instance counter not supported
|
||||
counter: dict[str, int] = Counter()
|
||||
# count all entities in the entity database
|
||||
for entity in self.doc.entitydb.values():
|
||||
counter[entity.dxftype()] += 1
|
||||
|
||||
for dxfclass in self.classes.values():
|
||||
dxfclass.dxf.instance_count = counter[dxfclass.dxf.name]
|
||||
Reference in New Issue
Block a user