• Models
  • Contests
  • Slicer
  • Login
  • Start Here
    thingiverse-iconprintables-iconcults3d-iconmakerworld-iconmyminifactory-icon

    3D GO

    3D ModelsContestsCollectionsSaved ModelsOn a mobile device?

3D GO

Privacy Policy
E8 Lie group or E8 lattice 3D Printer File Image 1
E8 Lie group or E8 lattice 3D Printer File Image 2
E8 Lie group or E8 lattice 3D Printer File Thumbnail 1
E8 Lie group or E8 lattice 3D Printer File Thumbnail 2

E8 Lie group or E8 lattice

Peter Farell avatarPeter Farell

July 26, 2025

printables-icon
DescriptionCommentsTags

Description

E8 Lie group or E8 lattice (go with E8 Thick)

E8 root system projected onto its first three basis vectors.

Below is some code I generated in Gemini.

A simple game to learn the basics of E8. (some of the edu diags are sketch)

Below is a phyton script for blender. cut and paste it into the scripting window. hit play

# E8 Lattice Generation Script for Blender (Final Correction)
#
# Fixes a bug in edge generation where only the first edge was correctly placed.
# This version now correctly connects all vertices.

import bpy
import bmesh
import random
from mathutils import Vector, Matrix

# --- Configuration ---
# Set the fraction of vertices to generate (1.0 = all, 0.25 = 25% random sample)
SAMPLING_FRACTION = 1.0

VERT_RADIUS = 0.08      # Radius of the spheres representing vertices
EDGE_RADIUS = 0.02      # Radius of the cylinders representing edges
COLLECTION_NAME = "E8_Lattice" # Name for the new collection

# --- Helper Functions ---

def create_collection(name):
    """Creates a new collection or gets it if it already exists."""
    if name in bpy.data.collections:
        return bpy.data.collections[name]
    else:
        new_collection = bpy.data.collections.new(name)
        bpy.context.scene.collection.children.link(new_collection)
        return new_collection

def get_e8_root_vectors():
    """Generates the 240 root vectors of the E8 lattice."""
    roots = set()
    # Type 1: (±1, ±1, 0, ..., 0) permutations. (112 vectors)
    for i in range(8):
        for j in range(i + 1, 8):
            for s1 in [-1, 1]:
                for s2 in [-1, 1]:
                    v = [0] * 8
                    v[i] = s1
                    v[j] = s2
                    roots.add(tuple(v))

    # Type 2: (±½, ±½, ..., ±½) with an even number of minus signs. (128 vectors)
    for i in range(2**8):
        v = []
        neg_count = 0
        for k in range(8):
            if (i >> k) & 1:
                v.append(0.5)
            else:
                v.append(-0.5)
                neg_count += 1
        if neg_count % 2 == 0:
            roots.add(tuple(v))
            
    # Scale roots by a factor of 2 for better visualization
    return [Vector(r) * 2 for r in roots]

def create_mesh_object(name, collection, verts, faces, edges=None):
    """Creates a single mesh object from vertex, face, and edge data."""
    if edges is None:
        edges = []
    mesh = bpy.data.meshes.new(name)
    mesh.from_pydata(verts, edges, faces)
    mesh.update()
    obj = bpy.data.objects.new(name, mesh)
    collection.objects.link(obj)
    return obj

# --- Core BMesh Generation Functions ---

def generate_vertices_mesh(name, vectors, radius, collection):
    """Generates a single object containing spheres for all vertices."""
    print(f"Generating mesh for {len(vectors)} vertices...")
    if not vectors: return None
    
    bm = bmesh.new()
    
    for vec in vectors:
        loc_3d = Vector((vec[0], vec[1], vec[2]))
        bmesh.ops.create_icosphere(bm, subdivisions=2, radius=radius, matrix=Matrix.Translation(loc_3d))

    obj = create_mesh_object(name, collection, [v.co for v in bm.verts], [[v.index for v in f.verts] for f in bm.faces])
    bm.free()
    
    obj.data.polygons.foreach_set('use_smooth', [True] * len(obj.data.polygons))
    obj.data.update()
    
    print("Vertex mesh created.")
    return obj

def generate_edges_mesh(name, vectors, radius, collection):
    """Generates a single object containing cylinders for all edges."""
    if not vectors or len(vectors) < 2: return None, 0
    print("Calculating and generating edge mesh... (this is the slow part)")

    bm = bmesh.new()
    edge_count = 0
    segments = 12

    for i in range(len(vectors)):
        for j in range(i + 1, len(vectors)):
            v1 = vectors[i]
            v2 = vectors[j]

            # Check for connectivity (squared distance is 8.0 after scaling)
            if abs((v1 - v2).length_squared - 8.0) < 0.001:
                p1 = Vector((v1[0], v1[1], v1[2]))
                p2 = Vector((v2[0], v2[1], v2[2]))
                
                # --- BUG FIX AREA ---
                # Robustly get the new cylinder's vertices by checking the mesh
                # state before and after the operator.
                verts_before = set(bm.verts)

                bmesh.ops.create_cone(
                    bm,
                    cap_ends=True,
                    segments=segments,
                    radius1=radius,
                    radius2=radius,
                    depth=(p1 - p2).length
                )
                
                new_verts = list(set(bm.verts) - verts_before)
                # --- END FIX ---
                
                # Calculate rotation and translation to position the cylinder
                direction = p2 - p1
                if direction.length > 0: # Avoid issues with zero-length vectors
                    location = p1 + direction / 2.0
                    rotation_quat = direction.to_track_quat('Z', 'Y')
                    
                    # Apply the transformation to ONLY the new vertices
                    bmesh.ops.rotate(bm, verts=new_verts, cent=Vector((0,0,0)), matrix=rotation_quat.to_matrix().to_4x4())
                    bmesh.ops.translate(bm, verts=new_verts, vec=location)
                
                edge_count += 1
                if edge_count % 500 == 0:
                    print(f"  ...processed {edge_count} edges...")

    obj = create_mesh_object(name, collection, [v.co for v in bm.verts], [[v.index for v in f.verts] for f in bm.faces])
    bm.free()
    
    obj.data.polygons.foreach_set('use_smooth', [True] * len(obj.data.polygons))
    obj.data.update()
    
    print(f"Edge mesh with {edge_count} edges created.")
    return obj, edge_count

# --- Main Execution ---

def main():
    """Main function to generate the E8 lattice."""
    e8_collection = create_collection(COLLECTION_NAME)
    
    for obj in e8_collection.objects:
        bpy.data.objects.remove(obj, do_unlink=True)

    print("Generating 240 E8 root vectors...")
    root_vectors = get_e8_root_vectors()

    if SAMPLING_FRACTION < 1.0:
        num_to_sample = int(len(root_vectors) * SAMPLING_FRACTION)
        sampled_vectors = random.sample(root_vectors, num_to_sample)
        print(f"Sampling {num_to_sample} of {len(root_vectors)} vertices ({SAMPLING_FRACTION * 100:.0f}%).")
    else:
        sampled_vectors = root_vectors
        print("Using all 240 vertices.")

    generate_vertices_mesh("E8_Vertices", sampled_vectors, VERT_RADIUS, e8_collection)
    generate_edges_mesh("E8_Edges", sampled_vectors, EDGE_RADIUS, e8_collection)
    
    print("\n✅ Finished! E8 lattice generated successfully.")

# --- Run the Script ---
if __name__ == "__main__":
    main()

License:

Creative Commons — Attribution — Noncommercial

Related Models

#3DBenchy - The jolly 3D printing torture-test by CreativeTools.se preview image

#3DBenchy - The jolly 3D printing torture-test by CreativeTools.se

CreativeTools profile image

CreativeTools

90,988

Flying Night Dragon preview image

Flying Night Dragon

Sevro profile image

Sevro

8,770

Chunky toddler beads  preview image

Chunky toddler beads

xtract profile image

xtract

970

The T-Rex Skull preview image

The T-Rex Skull

MakerBot profile image

MakerBot

39,870

Stable Flyer VI - Small Toy Glider preview image

Stable Flyer VI - Small Toy Glider

João Hackbart profile image

João Hackbart

3,762

Baby Educational Shape Toy preview image

Baby Educational Shape Toy

Daniel Nowill profile image

Daniel Nowill

1,386

Plantygon - Modular Geometric Stacking Planter for Succulents preview image

Plantygon - Modular Geometric Stacking Planter for Succulents

Printfutura profile image

Printfutura

28,553

Upcycled ATX Lab Bench Power Supply preview image

Upcycled ATX Lab Bench Power Supply

Caelestis Workshop profile image

Caelestis Workshop

1,523