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_vector radius: radius of basis_vector base_center: center point of base circle apex: tip of the cone Returns: :class:`~ezdxf.render.MeshTransformer` """ # 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 = Vec3(base_center) end = Vec3(apex) slices = int(count) ray = end - start z_axis = ray.normalize() is_y = (fabs(z_axis.y) > 0.5) x_axis = Vec3(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) -> Vec3: # 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)
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( # type: ignore 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)
def cone(count: int, radius: float, apex: 'Vertex' = (0, 0, 1), caps: bool = True) -> MeshVertexMerger: """ Create a `cone <https://en.wikipedia.org/wiki/Cone>`_ as :class:`~ezdxf.render.MeshVertexMerger` object. Args: count: edge count of basis radius: radius of basis apex: apex of the cone caps: add a bottom face if true """ 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 mesh
def cone(count: int, radius: float, apex: 'Vertex' = (0, 0, 1), caps: bool = True) -> MeshVertexMerger: """ Cone as Mesh. Args: count: edge count of basis radius: radius of basis apex: apex of the cone caps: add a bottom face if true Returns: MeshVertexMerger() """ 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 mesh
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)
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)
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)
def test_vertex_merger_indices(): merger = MeshVertexMerger() indices = merger.add_vertices([(1, 2, 3), (4, 5, 6)]) indices2 = merger.add_vertices([(1, 2, 3), (4, 5, 6)]) assert indices == indices2
def test_vertex_merger_vertices(): merger = MeshVertexMerger() merger.add_vertices([(1, 2, 3), (4, 5, 6)]) merger.add_vertices([(1, 2, 3), (4, 5, 6)]) assert merger.vertices == [(1, 2, 3), (4, 5, 6)]
def test_from_polyface_182_2(polyface_181_2): mesh = MeshVertexMerger.from_polyface(polyface_181_2) assert len(mesh.vertices) == 8