Skip to content

Instantly share code, notes, and snippets.

@marmakoide
Last active December 19, 2022 10:57
Show Gist options
  • Save marmakoide/26f42810d2e81de2374c56ab8b3d2764 to your computer and use it in GitHub Desktop.
Save marmakoide/26f42810d2e81de2374c56ab8b3d2764 to your computer and use it in GitHub Desktop.
Returns N points spread over a torus. Returns normals, handle self-intersections.

Golden dot spiral on a torus

This code sample demonstrates how to generates a set of points that covers a torus, for any number of points. The trick is to use a spiral and the golden angle.

42 points 256 points 999 points
dot spiral, 42 points dot spiral, 256 points dot spiral, 999 points

Such points sets are useful for anything that requires sampling a torus.

import numpy
def norm2(X):
return numpy.sqrt(numpy.sum(X ** 2, axis = -1))
golden_angle = numpy.pi * (3 - numpy.sqrt(5))
def get_spiral_torus(r_major, r_minor, N, return_normals = False):
# Generate the surface samples
theta = golden_angle * numpy.arange(N)
alpha = numpy.linspace(0., 2 * numpy.pi, N)
cos_theta, sin_theta = numpy.cos(theta), numpy.sin(theta)
cos_alpha, sin_alpha = numpy.cos(alpha), numpy.sin(alpha)
Q = r_major + r_minor * cos_theta
XYZ = numpy.stack([Q * cos_alpha, Q * sin_alpha, r_minor * sin_theta], axis = 1)
if return_normals:
UVW = numpy.stack([cos_alpha * cos_theta, sin_alpha * cos_theta, sin_theta], axis = 1)
# Handle self-intersecting torus case
if r_major < r_minor:
outside = (norm2(XYZ[:, :2]) - r_major) ** 2 + XYZ[:, 2] ** 2 >= r_minor ** 2
XYZ = XYZ[outside].copy()
if returns_normals:
UVW = UVW[outside].copy()
# Job done
if return_normals:
return XYZ, UVW
else:
return XYZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment