Published
Edited
Oct 9, 2020
2 forks
25 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
renderer = {
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
renderer.setPixelRatio(devicePixelRatio);
return renderer;
}
Insert cell
function breather(u_, v_, target) {
const a = 0.4;
const w = 20;
const u = -13.2 + u_ * 26.4;
const v = -37.4 + v_ * 2 * 37.4;

const r = 1 - a ** 2;
const l = Math.sqrt(r);
const d = a * ((l * Math.cosh(a * u)) ** 2 + (a * Math.sin(l * v)) ** 2);
const x = -u + (2 * r * Math.cosh(a * u) * Math.sinh(a * u)) / d;
const y =
(2 *
l *
Math.cosh(a * u) *
(-(l * Math.cos(v) * Math.cos(l * v)) - Math.sin(v) * Math.sin(l * v))) /
d;
const z =
(2 *
l *
Math.cosh(a * u) *
(-(l * Math.sin(v) * Math.cos(l * v)) + Math.cos(v) * Math.sin(l * v))) /
d;

target.set(x * w, z * w, y * w);
}
Insert cell
function bonanJeenerKlein(u_, v_, target) {
const u = 2 * Math.PI * u_;
const v = 2 * Math.PI * v_;

const w = 15;
const t = 2;

const k = Math.sin((a - 1) * u) + t;
const x =
a * Math.cos(u) -
Math.cos(a * u) -
((a - 1) / a) * k * Math.sin(((a + 1) * u) / 2) * Math.cos(v);
const y = k * Math.sin(v);
const z =
a * Math.sin(u) -
Math.sin(a * u) +
((a - 1) / a) * k * Math.cos(((a + 1) * u) / 2) * Math.cos(v);

target.set(x * w, y * w, z * w);
}
Insert cell
function triaxialHexatorus(u_, v_, target) {
const w = 100;
const u = 2 * Math.PI * u_;
const v = 2 * Math.PI * v_;

const x = Math.sin(u) / (Math.sqrt(2) + Math.cos(v));
const y =
Math.sin(u + (2 * Math.PI) / 3) /
(Math.sqrt(2) + Math.cos(v + (2 * Math.PI) / 3));
const z =
Math.cos(u - (2 * Math.PI) / 3) /
(Math.sqrt(2) + Math.cos(v - (2 * Math.PI) / 3));

target.set(x * w, y * w, z * w);
}
Insert cell
function kleinCycloid(u_, v_, target) {
const w = 10;
const c = 2;
const b = 5;
const u = u_ * 2 * b * c * Math.PI;
const v = v_ * 4 * Math.PI;

const x =
Math.cos(u / c) * Math.cos(u / b) * (a + Math.cos(v)) +
Math.sin(u / b) * Math.sin(v) * Math.cos(v);
const y =
Math.sin(u / c) * Math.cos(u / b) * (a + Math.cos(v)) +
Math.sin(u / b) * Math.sin(v) * Math.cos(v);
const z =
-Math.sin(u / b) * (a + Math.cos(v)) +
Math.cos(u / b) * Math.sin(v) * Math.cos(v);

target.set(x * w, z * w, y * w);
}
Insert cell
function braidedTorus(u_, v_, target) {
const w = 50;
const u = u_ * 8 * Math.PI;
const v = v_ * 2 * Math.PI;

const r = a / 50;
const R = b / 10;
const n = c / 10;

const x =
r * Math.cos(v) * Math.cos(u) +
R * Math.cos(u) * (1 + (1 / 2) * Math.cos(n * u));
const y = 2.5 * (r * Math.sin(v) + (1 / 2) * Math.sin(n * u));
const z =
r * Math.cos(v) * Math.sin(u) +
R * Math.sin(u) * (1 + (1 / 2) * Math.cos(n * u));

target.set(x * w, y * w, z * w);
}
Insert cell
function tranguloidTrefoil(u_, v_, target) {
const w = 30;
const u = -Math.PI + u_ * 2 * Math.PI;
const v = -Math.PI + v_ * 2 * Math.PI;

const x = (2 * Math.sin(3 * u)) / (2 + Math.cos(v));
const y =
(2 * (Math.sin(u) + 2 * Math.sin(2 * u))) /
(2 + Math.cos(v + (2 * Math.PI) / 3));
const z =
((Math.cos(u) - 2 * Math.cos(2 * u)) *
(2 + Math.cos(v)) *
(2 + Math.cos(v + (2 * Math.PI) / 3))) /
4;

target.set(x * w, z * w, y * w);
}
Insert cell
function hyperbolicHelicoid(u_, v_, target) {
const w = 150;
const u = -4 + u_ * 8;
const v = -4 + v_ * 8;
const k = 3 + a / 20;

const x =
(Math.sinh(v) * Math.cos(k * u)) / (1 + Math.cosh(u) * Math.cosh(v));
const y =
(Math.sinh(v) * Math.sin(k * u)) / (1 + Math.cosh(u) * Math.cosh(v));
const z = (Math.cosh(v) * Math.sinh(u)) / (1 + Math.cosh(u) * Math.cosh(v));

target.set(x * w, z * w, y * w);
}
Insert cell
function monkeySaddle(u_, v_, target) {
const w = 150;
const u = -1 + u_ * 2;
const v = -1 + v_ * 2;

const x = u;
const y = v;
const z = u ** 3 - 3 * u * v ** 2;

target.set(x * w, z * w, y * w);
}
Insert cell
function snail(u_, v_, target) {
const w = 10;
const u = u_ * 6 * Math.PI;
const v = v_ * 2 * Math.PI;

const d = b / 15;

const h = Math.E ** (u / (6 * Math.PI));
const x =
a * (1 - h) * Math.cos(u) * Math.cos((1 / 2) * v) * Math.cos((1 / 2) * v);
const y = 1 - Math.E ** (u / (d * Math.PI) - Math.sin(v) + h * Math.sin(v));
const z =
a * (h - 1) * Math.sin(u) * Math.cos((1 / 2) * v) * Math.cos((1 / 2) * v);

target.set(x * w, -200 - y * w, z * w);
}
Insert cell
function sievert(u_, v_, target) {
const w = 60;
const u = -Math.PI / 2 + u_ * (Math.PI / (100 - a * 2));
const v = 0.105 + v_ * 1;
const k = 0.5;

const p = -u / Math.sqrt(k + 1) + Math.atan(tan(u) * Math.sqrt(k + 1));
const l = 2 / (k + 1 - k * sin(v) * sin(v) * cos(u) * cos(u));
const r =
(l * Math.sqrt((k + 1) * (1 + k * sin(u) * sin(u))) * sin(v)) /
Math.sqrt(k);

const x = r * cos(p);
const y = r * sin(p);
const z = (Math.log(tan(v / 2)) + l * (k + 1) * cos(v)) / Math.sqrt(k);

target.set(x * w, z * w, y * w);
}
Insert cell
function roman(u, v, target) {
const a = 20
const x = (a ** 2 / 4) * sin(2 * u) * cos(v) ** 2;
const y = (a ** 2 / 4) * sin(u) * sin(2 * v);
const z = (a ** 2 / 4) * cos(u) * sin(2 * v);

target.set(x, z, y);
}
Insert cell
function richmond(u, v, target) {
const w = 500;
const r = u;
const theta = v * 2 * Math.PI;

const n = a;
const t = b;

const x =
-Math.cos(t + theta) / (2 * r) -
(r ** (2 * n + 1) * Math.cos(t - (2 * n + 1) * theta)) / (4 * n + 2);
const y =
-Math.sin(t + theta) / (2 * r) +
(r ** (2 * n + 1) * Math.sin(b - (2 * n + 1) * theta)) / (4 * n + 2);
const z = (r ** n * Math.cos(b - n * theta)) / n;

target.set(x * w, z * w, y * w);
}
Insert cell
function pseudosphere(u, v, target) {
const w = 10;

const x = a * cos(u) * sin(v) * w;
const y = a * sin(u) * sin(v) * w;
const z = a * (cos(v) + Math.log(tan(v / 2))) * w;

target.set(x, z, y);
}
Insert cell
function helicoid(u, v, target) {
const w = 50;
const x = (a / 5) * v * cos(u) * w;
const y = (a / 5) * v * sin(u) * w;
const z = (b / 2) * (-w / 2 + u * w);

target.set(x, z, y);
}
Insert cell
function plucker(u, v, target) {
const w = 150;
const x = u * cos(v) * w;
const y = u * sin(v) * w;
const z = sin((a / 5) * v) * w;

target.set(x, z, y);
}
Insert cell
function heart(u, v, target) {
const w = 3;
const x = a * cos(u) * (1.2 + cos(v)) * sin(v) * w;
const y = a * (1 + cos(v)) * sin(u) * sin(v) * w;
const z = 50 + -a * cos(v) * (1 / 2 + cos(v)) * w;

target.set(x, z, y);
}
Insert cell
function experiment(u, v, target) {
const w = 5;
const x = 2 * a * cos(u) * (1 + cos(v)) * sin(v) * w;
const y = 2 * a * (1 + cos(v)) * sin(u) * sin(v) * w;
const z = -2 * a * cos(v) * (1 + cos(2 * v)) * w;

target.set(x, z, y);
}
Insert cell
function octahedron(u, v, target) {
const w = n ** (n / 10) * 10;
const x =
a * cos(u) * cos(v) * Math.sqrt(cos(u) ** 2 * cos(v) ** 2) ** (n - 1) * w;
const y =
a * sin(u) * cos(v) * Math.sqrt(sin(u) ** 2 * cos(v) ** 2) ** (n - 1) * w;
const z = a * sin(v) * Math.sqrt(sin(v) ** 2) ** (n - 1) * w;

target.set(x, z, y);
}
Insert cell
function hyperbolicParaboloid(u_, v_, target) {
const w = 20;
const u = -w + u_ * 2 * w;
const v = -w + v_ * 2 * w;

const x = a * u;
const y = b * v;
// scaled down
const z = (1 / 3) * (u ** 2 - 2 * u * v);

target.set(x, z, y);
}
Insert cell
function enneper(u_, v_, target) {
const w = 15;
const u = u_ * 2 * Math.PI;
const v = v_ * 2.5;

const s = v * Math.cos(u);
const t = v * Math.sin(u);

const x = s * (1 - (1 / 3) * s ** 2 + t ** 2) * w;
const y = t * (1 - (1 / 3) * t ** 2 + s ** 2) * w;
const z = (s ** 2 - t ** 2) * w;

target.set(x, z, y);
}
Insert cell
function cyclideOfDupin(u, v, target) {
if (a === b) return;

const w = 8;
const k = c / Math.PI;
const x =
((b * (k - b * cos(u)) + a * cos(u) * (a - k * cos(v))) /
(a - b * cos(u) * cos(v))) *
w;
const y =
((Math.sqrt(a ** 2 - b ** 2) * (a - k * cos(v)) * sin(u)) /
(a - b * cos(u) * cos(v))) *
w;
const z =
((Math.sqrt(a ** 2 - b ** 2) * (k - b * cos(u)) * sin(v)) /
(a - b * cos(u) * cos(v))) *
w;

target.set(x, z, y);
}
Insert cell
function eight(u, v_, target) {
const v = -Math.PI / 2 + v_ * Math.PI;
const w = 150;
const x = cos(u) * Math.sin(2 * v) * w;
const y = sin(u) * Math.sin(2 * v) * w;
const z = Math.sin(v) * w;

target.set(x, z, y);
}
Insert cell
function dinit(u_, v_, target) {
const u = u_ * Math.PI * 4;
const v = v_ * 1;
const w = 10;

const x = w * a * Math.cos(u) * Math.sin(v);
const y = w * a * Math.sin(u) * Math.sin(v);
const z = w * a * (Math.cos(u) + Math.log(Math.tan(v / 2))) + b * u;

target.set(x, z, y);
}
Insert cell
function catenoid(u, v, target) {
const r = 250;
const t = -40 + v * 80;
const x = a * Math.cos(-Math.PI + u * 2 * Math.PI) * Math.cosh(t / a);
const y = a * Math.sin(-Math.PI + u * 2 * Math.PI) * Math.cosh(t / a);
const z = -r / 2 + v * r;

target.set(x, z, y);
}
Insert cell
function catalan(u_, v_, target) {
const w = 10;
const u = -2 * Math.PI + u_ * 4 * Math.PI;
const v = -3 + v_ * 6;

const x = 4 * u - Math.cosh(v) * Math.sin(u);
const y = 10 - Math.cos(u) * Math.cosh(v);
const z = -6 * Math.sin(u / 2) * Math.sinh(v / 2);

target.set(x * w, z * w, y * w);
}
Insert cell
function boy(u, v, target) {
const r = 110;
const c = new Complex(u * cos(v), u * sin(v));

const g1 =
-(3 / 2) *
new Complex(
c.mul(new Complex(1, 0).sub(c.pow(4))).mul(
c
.pow(6)
.add(c.pow(3).mul(Math.sqrt(5)))
.sub(1)
.inverse()
)
).im;

const g2 =
-(3 / 2) *
new Complex(
c.mul(new Complex(1, 0).add(c.pow(4))).mul(
c
.pow(6)
.add(c.pow(3).mul(Math.sqrt(5)))
.sub(1)
.inverse()
)
).re;

const g3 =
-1 / 2 +
new Complex(
new Complex(1, 0).add(c.pow(6)).mul(
c
.pow(6)
.add(c.pow(3).mul(Math.sqrt(5)))
.sub(1)
.inverse()
)
).im;

const x = (1 / (g1 ** 2 + g2 ** 2 + g3 ** 2)) * g1 * r;
const y = (1 / (g1 ** 2 + g2 ** 2 + g3 ** 2)) * g2 * r;
const z = (1 / (g1 ** 2 + g2 ** 2 + g3 ** 2)) * g3 * r;

target.set(x, z, y);
}
Insert cell
function bour(u, v, target) {
const r = u * 15;
const theta = 4 * Math.PI * v;

const x = r * Math.cos(theta) - (1 / 2) * r ** 2 * Math.cos(2 * theta);
const y = -r * Math.sin(theta) * (r * Math.cos(theta) + 1);
const z = (4 / 3) * r ** (3 / 2) * Math.cos((3 * theta) / 2);

target.set(x, z, y);
}
Insert cell
function bohdom(u, v, target) {
const w = 10;
const x = a * cos(u) * w;
const y = (a * sin(u) + b * cos(v)) * w;
const z = c * sin(v) * w;

target.set(x, z, y);
}
Insert cell
function astell(u, v, target) {
const w = 5;
const x = a * cos(u) * cos(v) * w;
const y = b * sin(u) * cos(v) * w;
const z = c * sin(v) ** 3 * w;

target.set(x, z, y);
}
Insert cell
function agnesirev(u, v, target) {
const w = 4;
const x = -2 * a * cos(u) * cos(v) ** 2 * w;
const y = -2 * a * cos(v) ** 2 * sin(u) * w;
const z = 2 * a * tan(v) * w;

target.set(x, z, y);
}
Insert cell
function hyperboloid(u, v, target) {
const x = a * cosh(-1 / 2 + v) * cos(-1 / 2 + u);
const y = a * cosh(-1 / 2 + v) * sin(-1 / 2 + u);
const z = b * sinh(-1 / 2 + v);

target.set(x, z, y);
}
Insert cell
parametricObj = {
const geometry = new THREE.ParametricBufferGeometry(
equations[parseInt(eq)],
slices,
slices
);
const material = new THREE.MeshNormalMaterial({
side: THREE.DoubleSide,
wireframe
// color: 0x000
});
return new THREE.Mesh(geometry, material);
}
Insert cell
scene = {
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
scene.add(parametricObj);
axis(scene);
return scene;
}
Insert cell
function line([x1, y1, z1], [x2, y2, z2], color = 0x000000) {
const geometry = new THREE.Geometry();
geometry.vertices.push(new THREE.Vector3(x1, y1, z1));
geometry.vertices.push(new THREE.Vector3(x2, y2, z2));
const material = new THREE.LineBasicMaterial({ color });
return new THREE.Line(geometry, material);
}
Insert cell
function arrow([x, y, z], [rx, ry, rz]) {
const geometry = new THREE.ConeBufferGeometry(5, 25, 25);
const material = new THREE.MeshBasicMaterial({ color: 0x000000 });
const cone = new THREE.Mesh(geometry, material);
cone.position.set(x, y, z);
cone.rotation.set(rx,ry,rz)
return cone;
}
Insert cell
function axis(scene) {
const w = 300;
const axis = [
[
[-w, 0, 0],
[w, 0, 0],
[(1 / 2) * Math.PI, 0, (1 / 2) * Math.PI],
[-(1 / 2) * Math.PI, 0, -(1 / 2) * Math.PI]
],
[[0, -w, 0], [0, w, 0], [Math.PI, 0, 0], [0, -Math.PI, 0]],
[
[0, 0, -w],
[0, 0, w],
[(1 / 2) * Math.PI, 0, Math.PI],
[-(1 / 2) * Math.PI, 0, Math.PI]
]
].map(([from, to, rotFrom, rotTo]) => {
scene.add(arrow(from, rotFrom));
scene.add(arrow(to, rotTo));
scene.add(line(from, to));
});
}
Insert cell
eqData = [
{ name: "hyperbolicHelicoid", params: [26] },
{ name: "tranguloidTrefoil", params: [] },
{ name: "breather", params: [] },
{ name: "kleinCycloid", params: [21] },
{ name: "trialxialHexatorus", params: [] },
{ name: "monkeySaddle", params: [] },
{ name: "boy", params: [] },
{ name: "braidedTorus", params: [11, 22, 15] },
{ name: "roman", params: [] },
{ name: "bonanJeenerKlein", params: [6] },
{ name: "snail", params: [14, 13] },
{ name: "helicoid", params: [21, 21] },
{ name: "hyperboloid", params: [17, 21] },
{ name: "cyclideOfDupin", params: [15, 4, 15] },
{ name: "eight", params: [] },
{ name: "dinit", params: [7, 21] },
{ name: "catenoid", params: [12] },
{ name: "richmond", params: [7, 10] },
{ name: "bour", params: [] },
{ name: "bohdom", params: [5, 10, 7] },
{ name: "astell", params: [21, 21, 21] },
{ name: "agnesirev", params: [13] },
{ name: "enneper", params: [] },
{ name: "hyperbolicParaboloid", params: [8, 8] },
{ name: "octahedron", params: [16, 15, 12, 3] },
{ name: "experiment", params: [13] },
{ name: "sievert", params: [40] },
{ name: "heart", params: [21] },
{ name: "plucker", params: [20] },
{ name: "pseudosphere", params: [11] },
{ name: "catalan", params: [] }
]
Insert cell
equations = [
hyperbolicHelicoid,
tranguloidTrefoil,
breather,
kleinCycloid,
triaxialHexatorus,
monkeySaddle,
boy,
braidedTorus,
roman,
bonanJeenerKlein,
snail,
helicoid,
hyperboloid,
cyclideOfDupin,
eight,
dinit,
catenoid,
richmond,
bour,
bohdom,
astell,
agnesirev,
enneper,
hyperbolicParaboloid,
octahedron,
experiment,
sievert,
heart,
plucker,
pseudosphere,
catalan
]
Insert cell
camera = {
const fov = 45;
const aspect = width / height;
const near = 0.01;
const far = 100000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.lookAt(scene.position);
camera.position.set(200, 400, -700);
return camera;
}
Insert cell
height = width
Insert cell
cos = t => Math.cos(2 * Math.PI * t)
Insert cell
cosh = t => Math.cosh(2 * Math.PI * t)
Insert cell
sin = t => Math.sin(2 * Math.PI * t)
Insert cell
sinh = t => Math.sinh(2 * Math.PI * t)
Insert cell
tan = t => Math.tan(2 * Math.PI * t)
Insert cell
tanh = t => Math.tanh(2 * Math.PI * t)
Insert cell
a = values[0].length > 0 && values[0][0]
Insert cell
b = values[0].length > 1 && values[0][1]
Insert cell
c = values[0].length > 2 && values[0][2]
Insert cell
n = values[0].length > 3 && values[0][3]
Insert cell
Insert cell
import { slider } from '@jashkenas/inputs'
Insert cell
import { inputsGroup } from '@bumbeishvili/input-groups'
Insert cell
Complex = require('complex.js@2.0.11/complex.js')
Insert cell
THREE = {
const THREE = (window.THREE = await require("three@0.99.0/build/three.min.js"));
await require("three@0.99.0/examples/js/controls/OrbitControls.js").catch(
() => {}
);
return THREE;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more