refactor: excel parse
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# Purpose: create sierpinski pyramid geometry
|
||||
# Copyright (c) 2016-2022 Manfred Moitzi
|
||||
# License: MIT License
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, Iterable, Sequence, Iterator, Optional
|
||||
import math
|
||||
from ezdxf.math import Vec3, UVec, Matrix44, UCS
|
||||
from ezdxf.render.mesh import MeshVertexMerger, MeshTransformer
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ezdxf.eztypes import GenericLayoutType
|
||||
|
||||
HEIGHT4 = 1.0 / math.sqrt(2.0) # pyramid4 height (* length)
|
||||
HEIGHT3 = math.sqrt(6.0) / 3.0 # pyramid3 height (* length)
|
||||
|
||||
DY1_FACTOR = math.tan(math.pi / 6.0) / 2.0 # inner circle radius
|
||||
DY2_FACTOR = 0.5 / math.cos(math.pi / 6.0) # outer circle radius
|
||||
|
||||
|
||||
class SierpinskyPyramid:
|
||||
"""
|
||||
Args:
|
||||
location: location of base center as (x, y, z) tuple
|
||||
length: side length
|
||||
level: subdivide level
|
||||
sides: sides of base geometry
|
||||
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
location: UVec = (0.0, 0.0, 0.0),
|
||||
length: float = 1.0,
|
||||
level: int = 1,
|
||||
sides: int = 4,
|
||||
):
|
||||
self.sides = sides
|
||||
self.pyramid_definitions = sierpinsky_pyramid(
|
||||
location=location, length=length, level=level, sides=sides
|
||||
)
|
||||
|
||||
def vertices(self) -> Iterator[list[Vec3]]:
|
||||
"""Yields the pyramid vertices as list of :class:`ezdxf.math.Vec3`."""
|
||||
for location, length in self.pyramid_definitions:
|
||||
yield self._calc_vertices(location, length)
|
||||
|
||||
__iter__ = vertices
|
||||
|
||||
def _calc_vertices(
|
||||
self, location: UVec, length: float
|
||||
) -> list[Vec3]:
|
||||
"""
|
||||
Calculates the pyramid vertices.
|
||||
|
||||
Args:
|
||||
location: location of the pyramid as center point of the base
|
||||
length: pyramid side length
|
||||
|
||||
Returns: list of :class:`ezdxf.math.Vec3`
|
||||
|
||||
"""
|
||||
len2 = length / 2.0
|
||||
x, y, z = location
|
||||
if self.sides == 4:
|
||||
return [
|
||||
Vec3(x - len2, y - len2, z),
|
||||
Vec3(x + len2, y - len2, z),
|
||||
Vec3(x + len2, y + len2, z),
|
||||
Vec3(x - len2, y + len2, z),
|
||||
Vec3(x, y, z + length * HEIGHT4),
|
||||
]
|
||||
elif self.sides == 3:
|
||||
dy1 = length * DY1_FACTOR
|
||||
dy2 = length * DY2_FACTOR
|
||||
return [
|
||||
Vec3(x - len2, y - dy1, z),
|
||||
Vec3(x + len2, y - dy1, z),
|
||||
Vec3(x, y + dy2, z),
|
||||
Vec3(x, y, z + length * HEIGHT3),
|
||||
]
|
||||
else:
|
||||
raise ValueError("sides has to be 3 or 4.")
|
||||
|
||||
def faces(self) -> list[Sequence[int]]:
|
||||
"""Returns list of pyramid faces. All pyramid vertices have the same
|
||||
order, so one faces list fits them all.
|
||||
|
||||
"""
|
||||
if self.sides == 4:
|
||||
return [(3, 2, 1, 0), (0, 1, 4), (1, 2, 4), (2, 3, 4), (3, 0, 4)]
|
||||
elif self.sides == 3:
|
||||
return [(2, 1, 0), (0, 1, 3), (1, 2, 3), (2, 0, 3)]
|
||||
else:
|
||||
raise ValueError("sides has to be 3 or 4.")
|
||||
|
||||
def render(
|
||||
self,
|
||||
layout: GenericLayoutType,
|
||||
merge: bool = False,
|
||||
dxfattribs=None,
|
||||
matrix: Optional[Matrix44] = None,
|
||||
ucs: Optional[UCS] = None,
|
||||
) -> None:
|
||||
"""Renders the sierpinsky pyramid into layout, set `merge` to ``True``
|
||||
for rendering the whole sierpinsky pyramid into one MESH entity, set
|
||||
`merge` to ``False`` for individual pyramids as MESH entities.
|
||||
|
||||
Args:
|
||||
layout: DXF target layout
|
||||
merge: ``True`` for one MESH entity, ``False`` for individual MESH
|
||||
entities per pyramid
|
||||
dxfattribs: DXF attributes for the MESH entities
|
||||
matrix: apply transformation matrix at rendering
|
||||
ucs: apply UCS at rendering
|
||||
|
||||
"""
|
||||
if merge:
|
||||
mesh = self.mesh()
|
||||
mesh.render_mesh(
|
||||
layout, dxfattribs=dxfattribs, matrix=matrix, ucs=ucs
|
||||
)
|
||||
else:
|
||||
for pyramid in self.pyramids():
|
||||
pyramid.render_mesh(layout, dxfattribs, matrix=matrix, ucs=ucs)
|
||||
|
||||
def pyramids(self) -> Iterable[MeshTransformer]:
|
||||
"""Yields all pyramids of the sierpinsky pyramid as individual
|
||||
:class:`MeshTransformer` objects.
|
||||
"""
|
||||
faces = self.faces()
|
||||
for vertices in self:
|
||||
mesh = MeshTransformer()
|
||||
mesh.add_mesh(vertices=vertices, faces=faces)
|
||||
yield mesh
|
||||
|
||||
def mesh(self) -> MeshTransformer:
|
||||
"""Returns geometry as one :class:`MeshTransformer` object."""
|
||||
faces = self.faces()
|
||||
mesh = MeshVertexMerger()
|
||||
for vertices in self:
|
||||
mesh.add_mesh(vertices=vertices, faces=faces)
|
||||
return MeshTransformer.from_builder(mesh)
|
||||
|
||||
|
||||
def sierpinsky_pyramid(
|
||||
location=(0.0, 0.0, 0.0),
|
||||
length: float = 1.0,
|
||||
level: int = 1,
|
||||
sides: int = 4,
|
||||
) -> list[tuple[Vec3, float]]:
|
||||
"""Build a Sierpinski pyramid.
|
||||
|
||||
Args:
|
||||
location: base center point of the pyramid
|
||||
length: base length of the pyramid
|
||||
level: recursive building levels, has to 1 or bigger
|
||||
sides: 3 or 4 sided pyramids supported
|
||||
|
||||
Returns: list of pyramid vertices
|
||||
|
||||
"""
|
||||
location = Vec3(location)
|
||||
level = int(level)
|
||||
if level < 1:
|
||||
raise ValueError("level has to be 1 or bigger.")
|
||||
pyramids = _sierpinsky_pyramid(location, length, sides)
|
||||
for _ in range(level - 1):
|
||||
next_level_pyramids = []
|
||||
for location, length in pyramids:
|
||||
next_level_pyramids.extend(
|
||||
_sierpinsky_pyramid(location, length, sides)
|
||||
)
|
||||
pyramids = next_level_pyramids
|
||||
return pyramids
|
||||
|
||||
|
||||
def _sierpinsky_pyramid(
|
||||
location: Vec3, length: float = 1.0, sides: int = 4
|
||||
) -> list[tuple[Vec3, float]]:
|
||||
if sides == 3:
|
||||
return sierpinsky_pyramid_3(location, length)
|
||||
elif sides == 4:
|
||||
return sierpinsky_pyramid_4(location, length)
|
||||
else:
|
||||
raise ValueError("sides has to be 3 or 4.")
|
||||
|
||||
|
||||
def sierpinsky_pyramid_4(
|
||||
location: Vec3, length: float = 1.0
|
||||
) -> list[tuple[Vec3, float]]:
|
||||
"""Build a 4-sided Sierpinski pyramid. Pyramid height = length of the base
|
||||
square!
|
||||
|
||||
Args:
|
||||
location: base center point of the pyramid
|
||||
length: base length of the pyramid
|
||||
|
||||
Returns: list of (location, length) tuples, representing the sierpinski pyramid
|
||||
|
||||
"""
|
||||
len2 = length / 2
|
||||
len4 = length / 4
|
||||
x, y, z = location
|
||||
return [
|
||||
(Vec3(x - len4, y - len4, z), len2),
|
||||
(Vec3(x + len4, y - len4, z), len2),
|
||||
(Vec3(x - len4, y + len4, z), len2),
|
||||
(Vec3(x + len4, y + len4, z), len2),
|
||||
(Vec3(x, y, z + len2 * HEIGHT4), len2),
|
||||
]
|
||||
|
||||
|
||||
def sierpinsky_pyramid_3(
|
||||
location: Vec3, length: float = 1.0
|
||||
) -> list[tuple[Vec3, float]]:
|
||||
"""Build a 3-sided Sierpinski pyramid (tetraeder).
|
||||
|
||||
Args:
|
||||
location: base center point of the pyramid
|
||||
length: base length of the pyramid
|
||||
|
||||
Returns: list of (location, length) tuples, representing the sierpinski pyramid
|
||||
|
||||
"""
|
||||
dy1 = length * DY1_FACTOR * 0.5
|
||||
dy2 = length * DY2_FACTOR * 0.5
|
||||
len2 = length / 2
|
||||
len4 = length / 4
|
||||
x, y, z = location
|
||||
return [
|
||||
(Vec3(x - len4, y - dy1, z), len2),
|
||||
(Vec3(x + len4, y - dy1, z), len2),
|
||||
(Vec3(x, y + dy2, z), len2),
|
||||
(Vec3(x, y, z + len2 * HEIGHT3), len2),
|
||||
]
|
||||
Reference in New Issue
Block a user