Exemplo n.º 1
0
 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
Exemplo n.º 2
0
def cube(center: bool = True) -> MeshTransformer:
    """
    Create a `cube <https://en.wikipedia.org/wiki/Cube>`_ as :class:`~ezdxf.render.MeshTransformer` object.

    Args:
        center: 'mass' center of cube, ``(0, 0, 0)`` if ``True``, else first corner at ``(0, 0, 0)``

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """
    mesh = MeshTransformer()
    vectices = _cube0_vertices if center else _cube_vertices
    mesh.add_mesh(vertices=vectices, faces=cube_faces)
    return mesh
Exemplo n.º 3
0
 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)  # type: ignore
     return MeshTransformer.from_builder(mesh)
Exemplo n.º 4
0
def cone(count: int = 16, radius: float = 1.0, apex: 'Vertex' = (0, 0, 1), caps=True, ngons=True) -> MeshTransformer:
    """
    Create a `cone <https://en.wikipedia.org/wiki/Cone>`_ as :class:`~ezdxf.render.MeshTransformer` object, the base
    center is fixed in the origin (0, 0, 0).

    Args:
        count: edge count of basis_vector
        radius: radius of basis_vector
        apex: tip of the cone
        caps: add a bottom face if ``True``
        ngons: use ngons for caps if ``True`` else subdivide caps into triangles

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """
    mesh = MeshVertexMerger()
    base_circle = list(circle(count, radius, close=True))
    for p1, p2 in zip(base_circle, base_circle[1:]):
        mesh.add_face([p1, p2, apex])
    if caps:
        base_circle = reversed(base_circle)  # for correct outside pointing normals
        if ngons:
            mesh.add_face(base_circle)
        else:
            for face in ngon_to_triangles(base_circle):
                mesh.add_face(face)

    return MeshTransformer.from_builder(mesh)
Exemplo n.º 5
0
def from_profiles_linear(profiles: Iterable[Iterable['Vertex']],
                         close: bool = True,
                         caps: bool = False) -> MeshTransformer:
    """
    Create MESH entity by linear connected `profiles`.

    Args:
        profiles: list of profiles
        close: close profile polygon if ``True``
        caps: close hull with bottom cap and top cap (as N-gons)

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """
    mesh = MeshVertexMerger()
    profiles = list(profiles)  # generator -> list
    if close:
        profiles = [close_polygon(p) for p in profiles]
    if caps:
        mesh.add_face(profiles[0])
        mesh.add_face(profiles[-1])

    for profile1, profile2 in zip(profiles, profiles[1:]):
        prev_v1, prev_v2 = None, None
        for v1, v2 in zip(profile1, profile2):
            if prev_v1 is not None:
                mesh.add_face([prev_v1, v1, v2, prev_v2])
            prev_v1 = v1
            prev_v2 = v2

    return MeshTransformer.from_builder(mesh)
Exemplo n.º 6
0
 def cubes(self) -> Iterable[MeshTransformer]:
     """ Yields all cubes of the menger sponge as individual :class:`MeshTransformer` objects.
     """
     faces = self.faces()
     for vertices in self:
         mesh = MeshVertexMerger()
         mesh.add_mesh(vertices=vertices, faces=faces)
         yield MeshTransformer.from_builder(mesh)
Exemplo n.º 7
0
def test_render_polyface(cube_polyface, msp):
    t = MeshTransformer.from_polyface(cube_polyface)
    assert len(t.vertices) == 24  # unoptimized mesh builder
    assert len(t.faces) == 6
    t.render_polyface(msp)
    new_polyface = msp[-1]
    assert new_polyface.dxftype() == "POLYLINE"
    assert new_polyface.is_poly_face_mesh is True
    assert len(new_polyface.vertices) == 8 + 6
    assert new_polyface.vertices[0] is not cube_polyface.vertices[0]
Exemplo n.º 8
0
def cone_2p(
    count: int = 16,
    radius: float = 1.0,
    base_center=(0, 0, 0),
    apex=(0, 0, 1)) -> MeshTransformer:
    """
    Create a `cone <https://en.wikipedia.org/wiki/Cone>`_ as :class:`~ezdxf.render.MeshTransformer` object from
    two points, `base_center` is the center of the base circle and `apex` as the tip of the cone.

    Args:
        count: edge count of basis
        radius: radius of basis
        base_center: center point of base circle
        apex: tip of the cone

    Returns: :class:`~ezdxf.render.MeshTransformer`

    .. versionadded:: 0.11

    """
    # Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.
    # Python port Copyright (c) 2012 Tim Knip (http://www.floorplanner.com), under the MIT license.
    # Additions by Alex Pletzer (Pennsylvania State University)
    # Adaptation for ezdxf, Copyright (c) 2020, Manfred Moitzi, MIT License.
    start = Vector(base_center)
    end = Vector(apex)
    slices = int(count)
    ray = end - start
    z_axis = ray.normalize()
    is_y = (fabs(z_axis.y) > 0.5)
    x_axis = Vector(float(is_y), float(not is_y), 0).cross(z_axis).normalize()
    y_axis = x_axis.cross(z_axis).normalize()
    mesh = MeshVertexMerger()

    def vertex(angle) -> Vector:
        # radial direction pointing out
        out = x_axis * cos(angle) + y_axis * sin(angle)
        return start + out * radius

    dt = pi * 2.0 / slices
    for i in range(0, slices):
        t0 = i * dt
        i1 = (i + 1) % slices
        t1 = i1 * dt
        # coordinates and associated normal pointing outwards of the cone's
        # side
        p0 = vertex(t0)
        p1 = vertex(t1)
        # polygon on the low side (disk sector)
        mesh.add_face([start, p0, p1])
        # polygon extending from the low side to the tip
        mesh.add_face([p0, end, p1])

    return MeshTransformer.from_builder(mesh)
Exemplo n.º 9
0
def cylinder_2p(
        count: int = 16,
        radius: float = 1,
        base_center=(0, 0, 0),
        top_center=(0, 0, 1),
) -> MeshTransformer:
    """
    Create a `cylinder <https://en.wikipedia.org/wiki/Cylinder>`_ as :class:`~ezdxf.render.MeshTransformer` object from
    two points, `base_center` is the center of the base circle and, `top_center` the center of the top circle.

    Args:
        count: profiles edge count
        radius: radius for bottom profile
        base_center: center of base circle
        top_center: center of top circle

    Returns: :class:`~ezdxf.render.MeshTransformer`

    .. versionadded:: 0.11

    """
    # Copyright (c) 2011 Evan Wallace (http://madebyevan.com/), under the MIT license.
    # Python port Copyright (c) 2012 Tim Knip (http://www.floorplanner.com), under the MIT license.
    # Additions by Alex Pletzer (Pennsylvania State University)
    # Adaptation for ezdxf, Copyright (c) 2020, Manfred Moitzi, MIT License.
    start = Vector(base_center)
    end = Vector(top_center)
    radius = float(radius)
    slices = int(count)
    ray = end - start

    z_axis = ray.normalize()
    is_y = (fabs(z_axis.y) > 0.5)
    x_axis = Vector(float(is_y), float(not is_y), 0).cross(z_axis).normalize()
    y_axis = x_axis.cross(z_axis).normalize()
    mesh = MeshVertexMerger()

    def vertex(stack, angle):
        out = (x_axis * cos(angle)) + (y_axis * sin(angle))
        return start + (ray * stack) + (out * radius)

    dt = pi * 2 / float(slices)
    for i in range(0, slices):
        t0 = i * dt
        i1 = (i + 1) % slices
        t1 = i1 * dt
        mesh.add_face([start, vertex(0, t0), vertex(0, t1)])
        mesh.add_face(
            [vertex(0, t1),
             vertex(0, t0),
             vertex(1, t0),
             vertex(1, t1)])
        mesh.add_face([end, vertex(1, t1), vertex(1, t0)])
    return MeshTransformer.from_builder(mesh)
Exemplo n.º 10
0
def test_render_polyface(cube_polyface):
    doc = ezdxf.new()
    msp = doc.modelspace()
    t = MeshTransformer.from_polyface(cube_polyface)
    assert len(t.vertices) == 24  # unoptimized mesh builder
    assert len(t.faces) == 6
    t.render_polyface(msp)
    new_polyface = msp[-1]
    assert new_polyface.dxftype() == 'POLYLINE'
    assert new_polyface.is_poly_face_mesh is True
    assert len(new_polyface.vertices) == 8 + 6
    assert new_polyface.vertices[0] is not cube_polyface.vertices[0]
Exemplo n.º 11
0
def extrude(
    profile: Iterable["Vertex"], path: Iterable["Vertex"], close=True
) -> MeshTransformer:
    """Extrude a `profile` polygon along a `path` polyline, vertices of profile
    should be in counter clockwise order.

    Args:
        profile: sweeping profile as list of (x, y, z) tuples in counter
            clockwise order
        path:  extrusion path as list of (x, y, z) tuples
        close: close profile polygon if ``True``

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """

    def add_hull(bottom_profile, top_profile):
        prev_bottom = bottom_profile[0]
        prev_top = top_profile[0]
        for bottom, top in zip(bottom_profile[1:], top_profile[1:]):
            face = (
                prev_bottom,
                bottom,
                top,
                prev_top,
            )  # counter clock wise: normals outwards
            mesh.faces.append(face)
            prev_bottom = bottom
            prev_top = top

    mesh = MeshVertexMerger()
    profile = Vec3.list(profile)
    if close:
        profile = close_polygon(profile)
    path = Vec3.list(path)
    start_point = path[0]  # type: ignore
    bottom_indices = mesh.add_vertices(profile)  # base profile
    for target_point in path[1:]:  # type: ignore
        translation_vector = target_point - start_point
        # profile will just be translated
        profile = [vec + translation_vector for vec in profile]
        top_indices = mesh.add_vertices(profile)
        add_hull(bottom_indices, top_indices)
        bottom_indices = top_indices
        start_point = target_point
    return MeshTransformer.from_builder(mesh)
Exemplo n.º 12
0
def from_profiles_linear(profiles: Iterable[Iterable['Vertex']],
                         close=True,
                         caps=False,
                         ngons=True) -> MeshTransformer:
    """
    Create MESH entity by linear connected `profiles`.

    Args:
        profiles: list of profiles
        close: close profile polygon if ``True``
        caps: close hull with bottom cap and top cap
        ngons: use ngons for caps if ``True`` else subdivide caps into triangles

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """
    mesh = MeshVertexMerger()
    profiles = list(profiles)
    if close:
        profiles = [close_polygon(p) for p in profiles]
    if caps:
        base = reversed(profiles[0])  # for correct outside pointing normals
        top = profiles[-1]
        if ngons:
            mesh.add_face(base)
            mesh.add_face(top)
        else:
            for face in ngon_to_triangles(base):
                mesh.add_face(face)
            for face in ngon_to_triangles(top):
                mesh.add_face(face)

    for profile1, profile2 in zip(profiles, profiles[1:]):
        prev_v1, prev_v2 = None, None
        for v1, v2 in zip(profile1, profile2):
            if prev_v1 is not None:
                mesh.add_face([prev_v1, v1, v2, prev_v2])
            prev_v1 = v1
            prev_v2 = v2

    return MeshTransformer.from_builder(mesh)
Exemplo n.º 13
0
def cone(count: int = 16,
         radius: float = 1.0,
         apex: 'Vertex' = (0, 0, 1),
         caps: bool = True) -> MeshTransformer:
    """
    Create a `cone <https://en.wikipedia.org/wiki/Cone>`_ as :class:`~ezdxf.render.MeshTransformer` object, the base
    center is fixed in the origin (0, 0, 0).

    Args:
        count: edge count of basis
        radius: radius of basis
        apex: tip of the cone
        caps: add a bottom face if ``True``

    Returns: :class:`~ezdxf.render.MeshTransformer`

    """
    mesh = MeshVertexMerger()
    base_circle = list(circle(count, radius, close=True))
    for p1, p2 in zip(base_circle, base_circle[1:]):
        mesh.add_face([p1, p2, apex])
    if caps:
        mesh.add_face(base_circle)
    return MeshTransformer.from_builder(mesh)
Exemplo n.º 14
0
def sphere(count: int = 16, stacks: int = 8, radius: float = 1, quads=True) -> MeshTransformer:
    """
    Create a `sphere <https://en.wikipedia.org/wiki/Sphere>`_ as :class:`~ezdxf.render.MeshTransformer` object,
    center is fixed at origin (0, 0, 0).

    Args:
        count: longitudinal slices
        stacks: latitude slices
        radius: radius of sphere
        quads: use quads for body faces if ``True`` else triangles

    Returns: :class:`~ezdxf.render.MeshTransformer`

    .. versionadded:: 0.11

    """
    radius = float(radius)
    slices = int(count)
    stacks_2 = int(stacks) // 2  # stacks from -stack/2 to +stack/2
    delta_theta = pi * 2.0 / float(slices)
    delta_phi = pi / float(stacks)
    mesh = MeshVertexMerger()

    def radius_of_stack(stack: float) -> float:
        return radius * cos(delta_phi * stack)

    def vertex(slice_: float, r: float, z: float) -> Vector:
        actual_theta = delta_theta * slice_
        return Vector(cos(actual_theta) * r, sin(actual_theta) * r, z)

    def cap_triangles(stack, top=False):
        z = sin(stack * delta_phi) * radius
        cap_vertex = Vector(0, 0, radius) if top else Vector(0, 0, -radius)
        r1 = radius_of_stack(stack)
        for slice_ in range(slices):
            v1 = vertex(slice_, r1, z)
            v2 = vertex(slice_ + 1, r1, z)
            if top:
                mesh.add_face((v1, v2, cap_vertex))
            else:
                mesh.add_face((cap_vertex, v2, v1))

    # bottom triangle faces
    cap_triangles(-stacks_2 + 1, top=False)

    # add body faces
    for actual_stack in range(-stacks_2 + 1, stacks_2 - 1):
        next_stack = actual_stack + 1
        r1 = radius_of_stack(actual_stack)
        r2 = radius_of_stack(next_stack)
        z1 = sin(delta_phi * actual_stack) * radius
        z2 = sin(delta_phi * next_stack) * radius
        for i in range(slices):
            v1 = vertex(i, r1, z1)
            v2 = vertex(i + 1, r1, z1)
            v3 = vertex(i + 1, r2, z2)
            v4 = vertex(i, r2, z2)
            if quads:
                mesh.add_face([v1, v2, v3, v4])
            else:
                center = vertex(
                    i + 0.5,
                    radius_of_stack(actual_stack + 0.5),
                    sin(delta_phi * (actual_stack + 0.5)) * radius,
                )
                mesh.add_face([v1, v2, center])
                mesh.add_face([v2, v3, center])
                mesh.add_face([v3, v4, center])
                mesh.add_face([v4, v1, center])

    # top triangle faces
    cap_triangles(stacks_2 - 1, top=True)

    return MeshTransformer.from_builder(mesh)