Skip to content

Commit

Permalink
Approximate area
Browse files Browse the repository at this point in the history
  • Loading branch information
drewyoungren committed Nov 21, 2023
1 parent 9455e53 commit 592ed7a
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 75 deletions.
161 changes: 88 additions & 73 deletions media/src/stories/SurfaceArea.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import { all, create } from 'mathjs';
import M from '../M.svelte';
import { ShardsEdgesGeometry, ShardsGeometry } from '../utils';
import {
ShardsEdgesGeometry,
ShardsGeometry,
// gaussLegendre,
} from '../utils';
import { onMount, onDestroy } from 'svelte';
// import { createEventDispatcher } from 'svelte';
Expand All @@ -27,7 +31,7 @@
}),
];
let exampleSurfaces = [
const standardExamples = [
{
uuid: 'area-story-example-001-',
kind: 'surface',
Expand All @@ -39,7 +43,7 @@
d: '2',
x: 'u v - 1',
y: 'u - v',
z: 'sin(u v) - u^2 / 20',
z: 'sin(u v) - (u - v)^2 / 20',
t0: '0',
t1: '1',
},
Expand All @@ -54,14 +58,35 @@
b: 'pi / 2',
c: '0',
d: 'pi',
x: 'sin(u) cos(v)',
y: 'sin(u) sin(v)',
x: 'sin(u) sin(v)',
y: 'sin(u) cos(v)',
z: 'cos(u)',
t0: '0',
t1: '1',
},
color: '#44CB44',
},
{
uuid: 'area-story-example-003-',
kind: 'surface',
title: 'Football',
params: {
a: '-pi / 2',
b: 'pi / 2',
c: '0',
d: '2*pi',
x: 'u',
y: 'cos(u) cos(v)',
z: 'cos(u) sin(v)',
t0: '0',
t1: '1',
},
color: '#44CB44',
},
];
let exampleSurfaces = [
...standardExamples,
...backupObjects.filter(
(obj) =>
obj.kind === 'surface' &&
Expand Down Expand Up @@ -110,8 +135,8 @@
const plusMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
side: THREE.DoubleSide,
roughness: 0.5,
metalness: 0.7,
roughness: 0.4,
metalness: 0.8,
});
// const plusMaterial = new THREE.MeshPhongMaterial({
Expand Down Expand Up @@ -143,6 +168,7 @@
let u0, u1, v0, v1;
const setRuv = (obj) => {
// const dt = 1e-4;
// const obj = exampleSurfaces.find((o) => o.uuid === uuid);
if (obj) {
const { x, y, z, a, b, c, d } = obj.params;
Expand All @@ -160,6 +186,16 @@
v0 = (u) => C.evaluate({ u });
v1 = (u) => D.evaluate({ u });
// const ru = new THREE.Vector3();
// const rv = new THREE.Vector3();
// totalArea = gaussLegendre(
// (x) => gaussLegendre((y) => x*y, v0(x), v1(x), 10),
// u0,
// u1,
// 10
// );
// // Match color to that of surface
// plusMaterial.color.set(obj.color);
// const hsl = {};
Expand All @@ -177,9 +213,13 @@
$: setRuv(currentSurface);
let approxArea = 0;
// let totalArea = 0;
const updateGeo = (N, r, A, B, C, D, samp) => {
geo?.dispose();
geo = new ShardsGeometry(r, A, B, C, D, N, samp);
approxArea = geo.area;
boxes.children[0].geometry = geo;
edgesUp?.dispose();
edgesUp = new ShardsEdgesGeometry(geo);
Expand All @@ -195,7 +235,9 @@
<div>
<p>
Let <M>{`\\mathbf r: D\\to \\Omega \\subset \\mathbb{R}^3`}</M> be a smooth
parametrization of a surface with $D\subset \RR^2$ a domain in $uv$-space.
parametrization of a surface with <M>{`D\\subset \\mathbb{R}^2`}</M> a domain
in
<M>uv</M>-space.
</p>
<p>
Expand All @@ -205,19 +247,14 @@
defined by
<M align>
{`\\vec r_u\\,\\Delta u &=
\\left\\langle x_u, y_u, z_u \\right\\rangle\\Delta u \\\\ \\vec
r_v\\,\\Delta v &= \\left\\langle x_v, y_v, z_v
{`\\mathbf r_u\\,\\Delta u &=
\\left\\langle \\frac{\\partial x}{\\partial u}, \\frac{\\partial y}{\\partial u}, \\frac{\\partial z}{\\partial u} \\right\\rangle\\Delta u \\\\ \\mathbf
r_v\\,\\Delta v &= \\left\\langle \\frac{\\partial x}{\\partial v}, \\frac{\\partial y}{\\partial v}, \\frac{\\partial z}{\\partial v}
\\right\\rangle\\Delta v \\\\
`}
</M>
</p>
<p>
We seek to visualize that integrand. Choose an example vector field and
parametric surface.
</p>
<div class="row">
<div class="col-auto">
<M>{'\\Omega:'}</M>
Expand All @@ -235,51 +272,17 @@
class=" bg-primary text-light"
on:click={() => {
exampleSurfaces = [
{
uuid: 'area-story-example-001-',
kind: 'surface',
title: 'Example 1',
params: {
a: '0',
b: '2',
c: '0',
d: '2',
x: 'u v - 1',
y: 'u - v',
z: 'sin(u v) - u^2 / 20',
t0: '0',
t1: '1',
},
color: '#44CB44',
},
{
uuid: 'area-story-example-002-',
kind: 'surface',
title: 'Dome',
params: {
a: '0',
b: 'pi / 2',
c: '0',
d: 'pi',
x: 'sin(u) cos(v)',
y: 'sin(u) sin(v)',
z: 'cos(u)',
t0: '0',
t1: '1',
},
color: '#44CB44',
},
...standardExamples,
...objects.filter(
(obj) =>
obj.kind === 'surface' &&
obj.uuid.slice(0, 18) !== 'area-story-example'
),
];
setRuv(
objects.find(
(o) => o.kind === 'surface' || exampleSurfaces[0]
)
);
currentSurface =
objects.find((o) => o.kind === 'surface') ||
exampleSurfaces[0];
setRuv(currentSurface);
}}
>
<i class="bi bi-arrow-clockwise" />
Expand All @@ -298,7 +301,7 @@
><input
type="range"
min="1"
max="20"
max="35"
step="1"
bind:value={nBoxes}
/></span
Expand All @@ -316,27 +319,39 @@
<span class="slider round" />
</label>
</div>
</div>
<div class="col-auto">
center
<label class="switch box box-3">
<input
type="checkbox"
checked={false}
on:change={(e) => {
if (e.target.checked) {
sampleParam = 0.5;
} else {
sampleParam = 0;
}
}}
/>
<span class="slider round" />
</label>
<div class="col-auto">
center
<label class="switch box box-3">
<input
type="checkbox"
checked={false}
on:change={(e) => {
if (e.target.checked) {
sampleParam = 0.5;
} else {
sampleParam = 0;
}
}}
/>
<span class="slider round" />
</label>
</div>
</div>
</div>
<p>
Adding each area gives <M>
{`\\sum \\Delta S = \\sum |\\mathbf r_u \\times \\mathbf r_v|\\,\\Delta u \\,\\Delta v \\approx ${approxArea}`}.
</M>
</p>
<p>
As the number of subdivisions heads to <M>\infty</M>, we get <M display>
{`\\text{SA} = \\int\\limits_\\Omega dS = \\int\\limits_D |\\mathbf r_u \\times \\mathbf r_v|\\,du\\,dv `}.
</M>
</p>
<style>
.demos-obj-select {
border-bottom-right-radius: 0;
Expand Down
18 changes: 16 additions & 2 deletions media/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -1283,10 +1283,18 @@ function labelAxes({
return [axesText, font];
}

// Gauss-Legendre quadrature via https://rosettacode.org/wiki/Numerical_integration/Gauss-Legendre_Quadrature#JavaScript

const factorial = (n) => (n <= 1 ? 1 : n * factorial(n - 1));
const M = (n) => (n - (n % 2 !== 0)) / 2;

/**
* Gauss-Legendre quadrature via https://rosettacode.org/wiki/Numerical_integration/Gauss-Legendre_Quadrature#JavaScript
* @param {function} fn function to integrate
* @param {number} a lower bound
* @param {number} b upper bound
* @param {number} n number of sample points
* @returns
*/
const gaussLegendre = (fn, a, b, n) => {
// coefficients of the Legendre polynomial
const coef = [...Array(M(n) + 1)].map(
Expand Down Expand Up @@ -2635,6 +2643,8 @@ class ShardsGeometry extends THREE.BufferGeometry {
constructor(r, a, b, c, d, N = 10, s = 0.5) {
super();

this.area = 0;

const dt = 1e-4; // for computing diffs
const dt2 = dt / 2;

Expand All @@ -2659,7 +2669,11 @@ class ShardsGeometry extends THREE.BufferGeometry {
const [xv0, yv0, zv0] = r(u, v - dt2);
const rv = new THREE.Vector3((xv1 - xv0) / dt, (yv1 - yv0) / dt, (zv1 - zv0) / dt);

normal.copy(ru.clone().cross(rv).normalize());
normal.copy(ru.clone().cross(rv));
this.area += normal.length() * du * dv;
normal.normalize();

// const tol = 1e-3; // perturb position for z-fighting

// adjust for sample point
x -= (du * ru.x + dv * rv.x) * s;
Expand Down

0 comments on commit 592ed7a

Please sign in to comment.