refactor: excel parse
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
# Copyright (c) 2022-2024, Manfred Moitzi
|
||||
# License: MIT License
|
||||
from __future__ import annotations
|
||||
from typing import Iterator, Callable, Any
|
||||
from .entities import (
|
||||
AcisEntity,
|
||||
NONE_REF,
|
||||
Face,
|
||||
Coedge,
|
||||
Loop,
|
||||
Vertex,
|
||||
)
|
||||
from . import sab
|
||||
|
||||
|
||||
class AcisDebugger:
|
||||
def __init__(self, root: AcisEntity = NONE_REF, start_id: int = 1):
|
||||
self._next_id = start_id - 1
|
||||
self._root: AcisEntity = root
|
||||
self.entities: dict[int, AcisEntity] = dict()
|
||||
if not root.is_none:
|
||||
self._store_entities(root)
|
||||
|
||||
@property
|
||||
def root(self) -> AcisEntity:
|
||||
return self._root
|
||||
|
||||
def _get_id(self) -> int:
|
||||
self._next_id += 1
|
||||
return self._next_id
|
||||
|
||||
def _store_entities(self, entity: AcisEntity) -> None:
|
||||
if not entity.is_none and entity.id == -1:
|
||||
entity.id = self._get_id()
|
||||
self.entities[entity.id] = entity
|
||||
for e in vars(entity).values():
|
||||
if isinstance(e, AcisEntity) and e.id == -1:
|
||||
self._store_entities(e)
|
||||
|
||||
def set_entities(self, entity: AcisEntity) -> None:
|
||||
self.entities.clear()
|
||||
self._root = entity
|
||||
self._store_entities(entity)
|
||||
|
||||
def walk(self, root: AcisEntity = NONE_REF) -> Iterator[AcisEntity]:
|
||||
def _walk(entity: AcisEntity):
|
||||
if entity.is_none:
|
||||
return
|
||||
yield entity
|
||||
done.add(entity.id)
|
||||
for e in vars(entity).values():
|
||||
if isinstance(e, AcisEntity) and e.id not in done:
|
||||
yield from _walk(e)
|
||||
|
||||
if root.is_none:
|
||||
root = self._root
|
||||
done: set[int] = set()
|
||||
yield from _walk(root)
|
||||
|
||||
def filter(
|
||||
self, func: Callable[[AcisEntity], bool], entity: AcisEntity = NONE_REF
|
||||
) -> Iterator[Any]:
|
||||
if entity.is_none:
|
||||
entity = self._root
|
||||
yield from filter(func, self.walk(entity))
|
||||
|
||||
def filter_type(
|
||||
self, name: str, entity: AcisEntity = NONE_REF
|
||||
) -> Iterator[Any]:
|
||||
if entity.is_none:
|
||||
entity = self._root
|
||||
yield from filter(lambda x: x.type == name, self.walk(entity))
|
||||
|
||||
@staticmethod
|
||||
def entity_attributes(entity: AcisEntity, indent: int = 0) -> Iterator[str]:
|
||||
indent_str = " " * indent
|
||||
for name, data in vars(entity).items():
|
||||
if name == "id":
|
||||
continue
|
||||
yield f"{indent_str}{name}: {data}"
|
||||
|
||||
def face_link_structure(self, face: Face, indent: int = 0) -> Iterator[str]:
|
||||
indent_str = " " * indent
|
||||
|
||||
while not face.is_none:
|
||||
partner_faces = list(self.partner_faces(face))
|
||||
error = ""
|
||||
linked_partner_faces = []
|
||||
unlinked_partner_faces = []
|
||||
for pface_id in partner_faces:
|
||||
pface = self.entities.get(pface_id)
|
||||
if pface is None:
|
||||
error += f" face {pface_id} does not exist;"
|
||||
if isinstance(pface, Face):
|
||||
reverse_faces = self.partner_faces(pface)
|
||||
if face.id in reverse_faces:
|
||||
linked_partner_faces.append(pface_id)
|
||||
else:
|
||||
unlinked_partner_faces.append(pface_id)
|
||||
else:
|
||||
error += f" entity {pface_id} is not a face;"
|
||||
if unlinked_partner_faces:
|
||||
error = f"unlinked partner faces: {unlinked_partner_faces} {error}"
|
||||
yield f"{indent_str}{str(face)} >> {partner_faces} {error}"
|
||||
face = face.next_face
|
||||
|
||||
@staticmethod
|
||||
def partner_faces(face: Face) -> Iterator[int]:
|
||||
coedges: list[Coedge] = []
|
||||
loop = face.loop
|
||||
while not loop.is_none:
|
||||
coedges.extend(co for co in loop.coedges())
|
||||
loop = loop.next_loop
|
||||
for coedge in coedges:
|
||||
for partner_coedge in coedge.partner_coedges():
|
||||
yield partner_coedge.loop.face.id
|
||||
|
||||
@staticmethod
|
||||
def coedge_structure(face: Face, ident: int = 4) -> list[str]:
|
||||
lines: list[str] = []
|
||||
coedges: list[Coedge] = []
|
||||
loop = face.loop
|
||||
|
||||
while not loop.is_none:
|
||||
coedges.extend(co for co in loop.coedges())
|
||||
loop = loop.next_loop
|
||||
for coedge in coedges:
|
||||
edge1 = coedge.edge
|
||||
sense1 = coedge.sense
|
||||
lines.append(f"Coedge={coedge.id} edge={edge1.id} sense={sense1}")
|
||||
for partner_coedge in coedge.partner_coedges():
|
||||
edge2 = partner_coedge.edge
|
||||
sense2 = partner_coedge.sense
|
||||
lines.append(
|
||||
f" Partner Coedge={partner_coedge.id} edge={edge2.id} sense={sense2}"
|
||||
)
|
||||
ident_str = " " * ident
|
||||
return [ident_str + line for line in lines]
|
||||
|
||||
@staticmethod
|
||||
def loop_vertices(loop: Loop, indent: int = 0) -> str:
|
||||
indent_str = " " * indent
|
||||
return f"{indent_str}{loop} >> {list(AcisDebugger.loop_edges(loop))}"
|
||||
|
||||
@staticmethod
|
||||
def loop_edges(loop: Loop) -> Iterator[list[int]]:
|
||||
coedge = loop.coedge
|
||||
first = coedge
|
||||
while not coedge.is_none:
|
||||
edge = coedge.edge
|
||||
sv = edge.start_vertex
|
||||
ev = edge.end_vertex
|
||||
if coedge.sense:
|
||||
yield [ev.id, sv.id]
|
||||
else:
|
||||
yield [sv.id, ev.id]
|
||||
coedge = coedge.next_coedge
|
||||
if coedge is first:
|
||||
break
|
||||
|
||||
def vertex_to_edge_relation(self) -> Iterator[str]:
|
||||
for vertex in (
|
||||
e for e in self.entities.values() if isinstance(e, Vertex)
|
||||
):
|
||||
edge = vertex.edge
|
||||
sv = edge.start_vertex
|
||||
ev = edge.end_vertex
|
||||
yield f"{vertex}: parent edge is {edge.id}; {sv.id} => {ev.id}; {edge.curve}"
|
||||
|
||||
def is_manifold(self) -> bool:
|
||||
for coedge in self.filter_type("coedge"):
|
||||
if len(coedge.partner_coedges()) > 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def dump_sab_as_text(data: bytes) -> Iterator[str]:
|
||||
def entity_data(e):
|
||||
for tag, value in e:
|
||||
name = sab.Tags(tag).name
|
||||
yield f"{name} = {value}"
|
||||
|
||||
decoder = sab.Decoder(data)
|
||||
header = decoder.read_header()
|
||||
yield from header.dumps()
|
||||
index = 0
|
||||
try:
|
||||
for record in decoder.read_records():
|
||||
yield f"--------------------- record: {index}"
|
||||
yield from entity_data(record)
|
||||
index += 1
|
||||
except sab.ParsingError as e:
|
||||
yield str(e)
|
||||
Reference in New Issue
Block a user