class Grid(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Grid' def __init__(self): super(Grid, self).__init__() params = [{'name': 'Size', 'type': 'vector2', 'value': [10, 10]}, {'name': 'Resolution', 'type': 'vector2i', 'value': [10, 10]}] self.set_parameters(params) self.cook() def run(self): size = self.get_property("Size") resolution = self.get_property("Resolution") x = size[0] * 0.5 z = size[1] * 0.5 fx = resolution[0] fz = resolution[1] if fx < 2 or fz < 2: self.geo = None return x_range = np.linspace(-x, x, fx) z_range = np.linspace(-z, z, fz) vertices = np.dstack(np.meshgrid(x_range, z_range, np.array([0.0]))).reshape(-1, 3) a = np.add.outer(np.array(range(fx - 1)), fx * np.array(range(fz - 1))) faces = np.dstack([a, a + 1, a + fx + 1, a + fx]).reshape(-1, 4) nms = np.zeros((vertices.shape[0], 3), dtype=float) nms[..., 1] = 1 self.geo = Mesh() self.geo.addVertices(vertices[:, [0, 2, 1]]) self.geo.addFaces(faces) self.geo.setVertexAttribData('normal', nms, attribType='vector3', defaultValue=[0, 0, 0])
class Tube(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Tube' def __init__(self): super(Tube, self).__init__() params = [{'name': 'Bottom center', 'type': 'vector3', 'value': [0, 0, 0]}, {'name': 'Top center', 'type': 'vector3', 'value': [0, 1, 0]}, {'name': 'Outer radius', 'type': 'vector2', 'value': [0.5, 0.5]}, {'name': 'Inner radius', 'type': 'vector2', 'value': [0.3, 0.3]}, {'name': 'Segments', 'type': 'int', 'value': 10, 'limits': (3, 30)}, {'name': 'Quad', 'type': 'bool', 'value': True}] self.set_parameters(params) self.cook() def run(self): outer = self.get_property("Outer radius") inner = self.get_property("Inner radius") s = self.get_property("Segments") if s < 3: self.geo = None return vertices, faces = generate_tube(self.get_property("Bottom center"), self.get_property("Top center"), outer[0], outer[1], inner[0], inner[1], s, self.get_property("Quad")) self.geo = Mesh() self.geo.addVertices(vertices) self.geo.addFaces(faces)
class Sphere(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Sphere' def __init__(self): super(Sphere, self).__init__() params = [{'name': 'Radius', 'type': 'float', 'value': 1.0}, {'name': 'Resolution', 'type': 'int', 'value': 20, 'limits': (2, 50)}] self.set_parameters(params) self.cook() def run(self): rad = self.get_property("Radius") if rad == 0: rad = 0.0001 s = self.get_property("Resolution") if s < 2: self.geo = None return tri, quad, vt = generate_sphere(rad, s) self.geo = Mesh() self.geo.addVertices(vt) self.geo.addFaces(tri) self.geo.addFaces(quad)
class Torus(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Torus' def __init__(self): super(Torus, self).__init__() params = [{'name': 'Radius', 'type': 'vector2', 'value': [1, 0.5]}, {'name': 'Radial resolution', 'type': 'int', 'value': 20, 'limits': (3, 50)}, {'name': 'Tubular resolution', 'type': 'int', 'value': 20, 'limits': (3, 50)}] self.set_parameters(params) self.cook() def run(self): rad = self.get_property("Radius") if rad[0] == 0: rad[0] = 0.0001 if rad[1] == 0: rad[1] = 0.0001 r1 = self.get_property("Radial resolution") r2 = self.get_property("Tubular resolution") if r1 < 3 or r2 < 3: self.geo = None return faces, vertices = generate_torus(rad[0], rad[1], r1, r2) self.geo = Mesh() self.geo.addVertices(vertices) self.geo.addFaces(faces)
class Moebius(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Moebius' def __init__(self): super(Moebius, self).__init__() params = [{'name': 'Length Split', 'type': 'int', 'value': 70, 'limits': (1, 100)}, {'name': 'Width Split', 'type': 'int', 'value': 15, 'limits': (1, 100)}, {'name': 'Twists', 'type': 'int', 'value': 1, 'limits': (0, 10)}, {'name': 'Raidus', 'type': 'float', 'value': 1, 'limits': (0, 10)}, {'name': 'Flatness', 'type': 'float', 'value': 1, 'limits': (0, 30)}, {'name': 'Width', 'type': 'float', 'value': 1, 'limits': (0, 10)}, {'name': 'Scale', 'type': 'float', 'value': 1, 'limits': (0, 30)}] self.set_parameters(params) self.cook() def run(self): tri = o3d.geometry.TriangleMesh.create_moebius(self.get_property('Length Split'), self.get_property('Width Split'), self.get_property("Twists"), self.get_property("Raidus"), self.get_property("Flatness"), self.get_property("Width"), self.get_property("Scale")) self.geo = Mesh() self.geo.addVertices(np.array(tri.vertices)[:, [0, 2, 1]]) self.geo.addFaces(np.array(tri.triangles))
class Cylinder(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Cylinder' def __init__(self): super(Cylinder, self).__init__() params = [{'name': 'Radius', 'type': 'float', 'value': 1.0}, {'name': 'Height', 'type': 'float', 'value': 2.0}, {'name': 'Split', 'type': 'int', 'value': 4, 'limits': (1, 10)}, {'name': 'Resolution', 'type': 'int', 'value': 20, 'limits': (3, 30)}, {'name': 'Cap', 'type': 'bool', 'value': True}] self.set_parameters(params) self.cook() def run(self): s = self.get_property("Resolution") if s < 3: self.geo = None return tri, quad, vt = generate_cylinder(self.get_property("Radius"), self.get_property("Height"), s, self.get_property("Split")) self.geo = Mesh() self.geo.addVertices(vt) self.geo.addFaces(quad) if self.get_property("Cap"): self.geo.addFaces(tri) else: self.geo.removeVertices([0, 1])
class Arrow(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Arrow' def __init__(self): super(Arrow, self).__init__() params = [{'name': 'Radius', 'type': 'vector2', 'value': [1, 1.5]}, {'name': 'Height', 'type': 'vector2', 'value': [2, 4]}, {'name': 'Cylinder split', 'type': 'int', 'value': 1, 'limits': (1, 10)}, {'name': 'Cone split', 'type': 'int', 'value': 1, 'limits': (1, 10)}, {'name': 'Resolution', 'type': 'int', 'value': 20, 'limits': (3, 30)}] self.set_parameters(params) self.cook() def run(self): radius = self.get_property("Radius") height = self.get_property("Height") tri = o3d.geometry.TriangleMesh.create_arrow(radius[0], radius[1], height[0], height[1], self.get_property("Resolution"), self.get_property("Cylinder split"), self.get_property("Cone split")) self.geo = Mesh() self.geo.addVertices(np.array(tri.vertices)[:, [0, 2, 1]]) self.geo.addFaces(np.array(tri.triangles))
class Tetrahedron(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Tetrahedron' def __init__(self): super(Tetrahedron, self).__init__() params = [{'name': 'Radius', 'type': 'float', 'value': 1.0}] self.set_parameters(params) self.cook() def run(self): rad = self.get_property("Radius") if rad == 0: rad = 0.0001 tri = o3d.geometry.TriangleMesh.create_tetrahedron(rad) self.geo = Mesh() self.geo.addVertices(np.array(tri.vertices)[:, [0, 2, 1]]) self.geo.addFaces(np.array(tri.triangles))
class CoordinateFrame(GeometryNode): __identifier__ = 'Primitives' NODE_NAME = 'Coordinate Frame' def __init__(self): super(CoordinateFrame, self).__init__() params = [{'name': 'Size', 'type': 'float', 'value': 1.0}, {'name': 'Origin', 'type': 'vector3', 'value': [0, 0, 0]}] self.set_parameters(params) self.cook() def run(self): size = self.get_property("Size") if size == 0: size = 0.0001 tri = o3d.geometry.TriangleMesh.create_coordinate_frame(size, self.get_property("Origin")) self.geo = Mesh() self.geo.addVertices(np.array(tri.vertices)[:, [0, 2, 1]]) self.geo.addFaces(np.array(tri.triangles))
class ConvexHull(GeometryNode): __identifier__ = 'Utility' NODE_NAME = 'ConvexHull' def __init__(self): super(ConvexHull, self).__init__() self.add_input("geo") def run(self): self.geo = None geo = self.get_input_geometry_ref(0) if geo is None: return if geo.getNumVertexes() == 0: return pts = [Point_3(*i) for i in geo.getVertexes()] res = Polyhedron_3() CGAL_Convex_hull_3.convex_hull_3(pts, res) pts = {} [pts.update({v: idx}) for idx, v in enumerate(res.vertices())] ff = [] for f in res.facets(): he = f.halfedge() done = he faces = [] while True: faces.append(pts[he.vertex()]) he = he.next() if he == done: break ff.append(faces) self.geo = Mesh() self.geo.addVertices([[i.x(), i.y(), i.z()] for i in res.points()]) self.geo.addFaces(ff)
class Subdivide(GeometryNode): __identifier__ = 'Geometry' NODE_NAME = 'Subdivide' def __init__(self): super(Subdivide, self).__init__() self.add_combo_menu("Method", "Method", items=["Upsample", "Loop"]) self.add_int_input("Iteration", "Iteration", 1, range=(0, 10)) self.add_input("geo") def run(self): geo = self.get_input_geometry_ref(0) if geo is None: return if geo.getNumFaces() == 0 or geo.getNumVertexes() == 0: return itera = self.get_property("Iteration") if itera == 0: return mesh = geo.getTriangulateMesh() v = mesh.points() f = mesh.face_vertex_indices() mt = self.get_property("Method") if mt == "Upsample": for i in range(itera): v, f = igl.upsample(v, f) elif mt == "Loop": for i in range(itera): v, f = igl.loop(v, f) self.geo = Mesh() self.geo.addVertices(v) self.geo.addFaces(f)