From: Plom Heller Date: Sat, 8 Aug 2026 23:06:02 +0000 (+0200) Subject: Some refactoring. X-Git-Url: https://plomlompom.com/repos/%22https:/validator.w3.org/static/foo.html?a=commitdiff_plain;h=c6c00d2245c99840a14120e1aea5e5f5a95adfe9;p=bricksplom Some refactoring. --- diff --git a/src/bricksplom/ldraw.py b/src/bricksplom/ldraw.py index ae283d8..1a6fcfc 100644 --- a/src/bricksplom/ldraw.py +++ b/src/bricksplom/ldraw.py @@ -3,7 +3,7 @@ # standard libs from dataclasses import dataclass from pathlib import Path -from typing import Any, Callable, NamedTuple, Optional +from typing import Any, Callable, NamedTuple, Optional, Self # ourselves from bricksplom.constants import CHAR_NEWLINE @@ -23,7 +23,7 @@ LDRAW_STUDS = { LdrawRefsTree = tuple[Path, '_SubRefs'] _SubRefs = tuple[tuple[str, LdrawRefsTree], ...] -_N_TOKS_PER_REFLINE = 15 +_N_TOKS_PER_REFLINE = 14 _N_DIMS = 3 @@ -37,6 +37,57 @@ class _XYZ(NamedTuple): z: float +def _vectors_at( + toks: tuple[str, ...], + indices: tuple[int, ...] + ) -> tuple[_XYZ, ...]: + as_floats = tuple(float(tok) for tok in toks) + return tuple(_XYZ(*as_floats[idx * _N_DIMS:(idx + 1) * _N_DIMS]) + for idx in indices) + + +def _instructions_for( + path: Path, + collectables: tuple[str, ...] + ) -> tuple[tuple[str, str], ...]: + lines = [] + for line in path.read_text(encoding='utf8').split(CHAR_NEWLINE): + toks = line.lstrip().split(maxsplit=1) + if toks and toks[0] in collectables: + assert len(toks) == 2 + lines += [(toks[0], toks[1])] + return tuple(lines) + + +@dataclass +class _Transformation: + move: _XYZ + rotscal_x: _XYZ + rotscal_y: _XYZ + rotscal_z: _XYZ + + def apply_to( + self, + vector: _XYZ + ) -> _XYZ: + 'Rotate, scale, translate vector.' + xyz = ( + sum(rotscal[jdx] * vector[jdx] for jdx in range(_N_DIMS)) + + self.move[idx] + for idx, rotscal in enumerate((self.rotscal_x, + self.rotscal_y, + self.rotscal_z))) + return _XYZ(*xyz) + + @classmethod + def from_toks( + cls, + toks: tuple[str, ...] + ) -> Self: + 'Build from "1"-type geometry-transformation toks.' + return cls(*_vectors_at(toks, (0, 1, 2, 3))) + + class LdrawDb: 'Connection to local LDRAW archive.' @@ -65,10 +116,8 @@ class LdrawDb: ) -> Any: path = self.path(filename) collected = [] - for line in path.read_text(encoding='utf8').split(CHAR_NEWLINE): - toks = line.lstrip().split(maxsplit=_N_TOKS_PER_REFLINE - 1) - if not (toks and toks[0] == '1'): - continue + for _, line in _instructions_for(path, ('1',)): + toks = line.split(maxsplit=_N_TOKS_PER_REFLINE - 1) assert len(toks) == _N_TOKS_PER_REFLINE referenced = toks.pop().replace('\\', '/') collected += collect( @@ -98,9 +147,9 @@ class LdrawDb: ref: str, toks: list[str] ) -> tuple[int]: - matrix = tuple(tuple(toks[n:n+3]) for n in (5, 8, 11)) do_ignore = False - for row in [[float(x) for x in row] for row in matrix]: + t = _Transformation.from_toks(tuple(toks[1:])) + for row in (t.rotscal_x, t.rotscal_y, t.rotscal_z): if do_ignore: break for idx in range(len(row)): # pylint: disable=C0200 @@ -123,66 +172,36 @@ class LdrawDb: ) -> _XYZ: 'For object at filename, calculate LDU sizes over all three axes.' - @dataclass - class _Transformation: - move: _XYZ - rotscal_x: _XYZ - rotscal_y: _XYZ - rotscal_z: _XYZ - - def apply_to( - self, - vector: _XYZ - ) -> _XYZ: - 'Rotate, scale, translate vector.' - xyz = ( - sum(rotscal[jdx] * vector[jdx] for jdx in range(_N_DIMS)) - + self.move[idx] - for idx, rotscal in enumerate((self.rotscal_x, - self.rotscal_y, - self.rotscal_z))) - return _XYZ(*xyz) - @dataclass class _MovingPoint: start: _XYZ transformations: list[_Transformation] - def vectors_at( - toks: tuple[str, ...], - indices: tuple[int, ...] - ) -> tuple[_XYZ, ...]: - as_floats = tuple(float(tok) for tok in toks) - return tuple(_XYZ(*as_floats[idx * _N_DIMS:(idx + 1) * _N_DIMS]) - for idx in indices) - def walk_collect( walk: Callable[[], list[_MovingPoint]], _: str, toks: list[str] ) -> list[_MovingPoint]: - vectors = vectors_at(tuple(toks[2:]), (0, 1, 2, 3)) + transformation = _Transformation.from_toks(tuple(toks[1:])) moving_points = walk() for moving_point in moving_points: - moving_point.transformations += [_Transformation(*vectors)] + moving_point.transformations += [transformation] return moving_points def walk_result( path: Path, collected: list[_MovingPoint] ) -> list[_MovingPoint]: - collectables = {'2': (0, 1), - '3': (0, 1, 2), - '4': (0, 1, 2, 3), - '5': (1, 3)} - for line in path.read_text(encoding='utf8').split(CHAR_NEWLINE): - toks = line.lstrip().split(maxsplit=1) - if toks and toks[0] in collectables: - collected += [ - _MovingPoint(xyz, []) - for xyz in vectors_at(tuple(toks[1].split()[1:]), - collectables[toks[0]]) - ] + pt_indices = {'2': (0, 1), + '3': (0, 1, 2), + '4': (0, 1, 2, 3), + '5': (1, 3)} + for key, line in _instructions_for(path, tuple(pt_indices.keys())): + collected += [ + _MovingPoint(xyz, []) + for xyz in _vectors_at(tuple(line.split()[1:]), + pt_indices[key]) + ] return collected def outer_bounds(