3-D harmonic geometry#

Phase 7 of harmonic_geometry adds 3-D generators: harmonic knots, Lissajous tubes, harmonic surfaces (sphere, torus, Klein), point clouds, 3-D L-systems, and recursive polyhedra. All return a GeometryData whose plotting.plot_geometry() does the right thing — wireframes, mesh, or 3-D scatter — with no extra arguments.

import warnings
from fractions import Fraction

import numpy as np
import matplotlib.pyplot as plt

from biotuner.harmonic_geometry import HarmonicInput, plotting

warnings.filterwarnings("ignore")
plt.rcParams["figure.dpi"] = 110
from biotuner.harmonic_geometry import (
    harmonic_knot, harmonic_point_cloud, harmonic_surface, lissajous_tube,
    lsystem_3d, recursive_polyhedron,
)

CHORDS = {
    "Major": HarmonicInput(ratios=[Fraction(1), Fraction(5, 4), Fraction(3, 2)]),
    "Sus4":  HarmonicInput(ratios=[Fraction(1), Fraction(4, 3), Fraction(3, 2)]),
    "Dom7":  HarmonicInput(ratios=[Fraction(1), Fraction(5, 4), Fraction(3, 2),
                                    Fraction(7, 4)]),
    "Dim7":  HarmonicInput(ratios=[Fraction(1), Fraction(6, 5),
                                    Fraction(7, 5), Fraction(12, 7)]),
}

Harmonic knots — 3 coprime frequencies weave a closed curve#

geoms = [harmonic_knot(CHORDS[n], n_points=300, n_sides=10) for n in CHORDS]
plotting.gallery(geoms, titles=list(CHORDS.keys()), n_cols=4,
                 suptitle="harmonic_knot — 4 chords");
../../_images/ddc94d80133c49073b7ed55351550c8e983c39a961537159b8065c2ef9e60c9d.png

Lissajous tubes — extruded 3-D Lissajous curves#

geoms = [lissajous_tube(CHORDS[n], n_points=400, n_sides=10) for n in CHORDS]
plotting.gallery(geoms, titles=list(CHORDS.keys()), n_cols=4,
                 suptitle="lissajous_tube — 4 chords");
../../_images/7b28030558a9bcaad3f2fe48cdb549d3592bdb9a9c003bb54a96871410faf52d.png

Rotating a single knot#

rotation_strip is a convenience that renders the same 3-D geometry at several azimuths in a single horizontal strip — useful when a static notebook can’t capture a 3-D shape from one viewpoint alone.

g = harmonic_knot(CHORDS["Dom7"], n_points=400, n_sides=14)
plotting.rotation_strip(g, n_strip=5,
                        suptitle="harmonic_knot Dom7 — rotation strip");
../../_images/aa4194281b895e6a384f826d3fbbe8229f305107a58a7e918d73f4ff27dff9fa.png

Harmonic surfaces — sphere, torus, cylinder#

surfaces = ["sphere", "torus", "cylinder"]
geoms  = [harmonic_surface(CHORDS["Dom7"], mode=s, resolution=40)
          for s in surfaces]
plotting.gallery(geoms, titles=surfaces, n_cols=3,
                 suptitle="harmonic_surface (Dom7) — three modes");
../../_images/3c90f75435322668401e1beffe1090fdeb23407b344ea5d03cd1094f367c853e.png

Harmonic point clouds#

geoms = [harmonic_point_cloud(CHORDS[n], n_points=2000) for n in CHORDS]
plotting.gallery(geoms, titles=list(CHORDS.keys()), n_cols=4,
                 suptitle="harmonic_point_cloud — 4 chords");
../../_images/8578794011bdaf1b8582cd59aa22bc5ed4bf6f9c60d842f8c71be8863e4a316c.png

3-D L-systems and recursive polyhedra#

geoms = [lsystem_3d(CHORDS[n], depth=3) for n in CHORDS]
plotting.gallery(geoms, titles=list(CHORDS.keys()), n_cols=4,
                 suptitle="lsystem_3d (depth 3)");
../../_images/63ed7a67a011e3b245889e70a1f0a73885799b9df2e5c4136f1d0735f352faab.png
geoms = [recursive_polyhedron(CHORDS[n], depth=2) for n in CHORDS]
plotting.gallery(geoms, titles=list(CHORDS.keys()), n_cols=4,
                 suptitle="recursive_polyhedron (depth 2)");
../../_images/6809efc74ac5c2f9254238803a0f4eba85ff85062e8e48787b3ba5a69a8c0184.png