Py.Cafe

jackparmer/

dash-menger-sponge-visualization

3D Menger Sponge Visualization

DocsPricing
  • app.py
  • requirements.txt
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
import numpy as np

# Initialize the app
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])

def menger_sponge(level, x0, y0, z0, size):
    if level == 0:
        return [(x0, y0, z0, size)]
    new_size = size / 3
    cubes = []
    for dx in range(3):
        for dy in range(3):
            for dz in range(3):
                if (dx != 1 or dy != 1) and (dx != 1 or dz != 1) and (dy != 1 or dz != 1):
                    cubes += menger_sponge(level - 1, x0 + dx * new_size, y0 + dy * new_size, z0 + dz * new_size, new_size)
    return cubes

def generate_menger_data(level):
    cubes = menger_sponge(level, -1, -1, -1, 2)
    vertices = []
    faces = []
    for i, (x, y, z, s) in enumerate(cubes):
        idx = len(vertices)
        vertices.extend([
            [x, y, z],
            [x + s, y, z],
            [x + s, y + s, z],
            [x, y + s, z],
            [x, y, z + s],
            [x + s, y, z + s],
            [x + s, y + s, z + s],
            [x, y + s, z + s]
        ])
        faces.extend([
            [idx, idx + 1, idx + 2], [idx, idx + 2, idx + 3],  # Bottom face
            [idx + 4, idx + 5, idx + 6], [idx + 4, idx + 6, idx + 7],  # Top face
            [idx, idx + 1, idx + 5], [idx, idx + 5, idx + 4],  # Front face
            [idx + 1, idx + 2, idx + 6], [idx + 1, idx + 6, idx + 5],  # Right face
            [idx + 2, idx + 3, idx + 7], [idx + 2, idx + 7, idx + 6],  # Back face
            [idx + 3, idx, idx + 4], [idx + 3, idx + 4, idx + 7],  # Left face
        ])

    vertices = np.array(vertices)
    faces = np.array(faces)
    return vertices, faces

# Define the layout
app.layout = dbc.Container(
    [
        dbc.Row(
            dbc.Col(html.H1("3D Menger Sponge Visualization"), className="text-center")
        ),
        dbc.Row(
            dbc.Col(
                dcc.Graph(id='menger-sponge-graph', style={"height": "600px"}),
                width=12,
            )
        ),
        dbc.Row(
            dbc.Col(
                dcc.Slider(
                    id='level-slider',
                    min=0,
                    max=4,
                    step=1,
                    value=2,
                    marks={i: str(i) for i in range(5)},
                ),
                width=12,
            )
        ),
    ],
    fluid=True,
)

@app.callback(
    Output('menger-sponge-graph', 'figure'),
    [Input('level-slider', 'value')]
)
def update_menger_sponge_graph(level):
    vertices, faces = generate_menger_data(level)
    x, y, z = vertices.T
    I, J, K = faces.T

    mesh_trace = go.Mesh3d(
        x=x,
        y=y,
        z=z,
        i=I,
        j=J,
        k=K,
        color='lightblue',
        opacity=1,
        intensity=z,
        lighting=dict(ambient=0.5, diffuse=0.5, roughness=0.5, specular=0.7),
        lightposition=dict(x=10, y=10, z=10)
    )

    layout = go.Layout(
        scene=dict(
            xaxis=dict(title='X', showgrid=False, zeroline=False),
            yaxis=dict(title='Y', showgrid=False, zeroline=False),
            zaxis=dict(title='Z', showgrid=False, zeroline=False),
            aspectmode='data'
        ),
        margin=dict(l=0, r=0, b=0, t=0)
    )

    return go.Figure(data=[mesh_trace], layout=layout)

# Run the app
if __name__ == "__main__":
    app.run_server(debug=True)