Skip to content

Commit 22ec94e

Browse files
committed
Allow nonconstant boundaries in integration
1 parent 985663e commit 22ec94e

File tree

3 files changed

+212
-104
lines changed

3 files changed

+212
-104
lines changed

media/mathplayground/global.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ body,
3232
grid-column-end: 4;
3333
}
3434

35+
.box-all {
36+
grid-column-start: 1;
37+
grid-column-end: 4;
38+
}
39+
3540
.box-3 {
3641
color: white;
3742
vertical-align: middle;

media/src/objects/Function.svelte

Lines changed: 96 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
ArrowBufferGeometry,
3737
blockGeometry,
3838
checksum,
39+
gaussLegendre,
3940
} from '../utils.js';
4041
4142
import { mathToJSFunction } from './mathutils';
@@ -125,6 +126,8 @@
125126
});
126127
127128
let minimize = $state(false);
129+
let approxVol = $state();
130+
let volumeInt = $state();
128131
129132
const colorMaterial = new THREE.MeshPhongMaterial({
130133
color: 0xffffff,
@@ -218,6 +221,10 @@
218221
// return (x, y, t) => z.evaluate({ x, y, t });
219222
// });
220223
224+
let A = $derived(math.evaluate(params.a));
225+
let B = $derived(math.evaluate(params.b));
226+
let C = $derived(mathToJSFunction(params.c, ['x']));
227+
let D = $derived(mathToJSFunction(params.d, ['x']));
221228
let func = $derived(mathToJSFunction(params.z, ['x', 'y', 't']));
222229
223230
const tangentVectors = function () {
@@ -334,18 +341,18 @@
334341
$effect(() => (surfaceMesh.visible = graphVisible));
335342
336343
const updateSurface = function () {
337-
const { a, b, c, d } = params;
338-
const A = math.parse(a).evaluate();
339-
const B = math.parse(b).evaluate();
344+
// const { a, b, c, d } = params;
345+
// const A = math.parse(a).evaluate();
346+
// const B = math.parse(b).evaluate();
340347
341-
const C = math.parse(c);
342-
const D = math.parse(d);
348+
// const C = math.parse(c);
349+
// const D = math.parse(d);
343350
344351
const geometry = new ParametricGeometry(
345352
(u, v, vec) => {
346353
const U = A + (B - A) * u;
347-
const cU = C.evaluate({ x: U });
348-
const dU = D.evaluate({ x: U });
354+
const cU = C(U);
355+
const dU = D(U);
349356
350357
const V = (1 - v) * cU + v * dU;
351358
@@ -354,7 +361,7 @@
354361
data.nX,
355362
data.nX,
356363
);
357-
const meshGeometry = meshLines(params, data.rNum, data.cNum, data.nX);
364+
const meshGeometry = meshLines(data.rNum, data.cNum, data.nX);
358365
if (!meshGeometry) {
359366
// Geometry calculation failed, there must have been an
360367
// input error.
@@ -403,24 +410,26 @@
403410
updateBoxes();
404411
}
405412
413+
volumeInt = integrateSurface();
414+
406415
render();
407416
};
408417
409-
const meshLines = function (rData, rNum = 10, cNum = 10, nX = 30) {
410-
let { a, b, c, d, t0, t1 } = rData;
418+
const meshLines = function (rNum = 10, cNum = 10, nX = 50) {
419+
// let { a, b, c, d, t0, t1 } = rData;
411420
412-
const A = math.parse(a).evaluate();
413-
const B = math.parse(b).evaluate();
414-
const C = math.parse(c).compile();
415-
const D = math.parse(d).compile();
421+
// const A = math.parse(a).evaluate();
422+
// const B = math.parse(b).evaluate();
423+
// const C = math.parse(c).compile();
424+
// const D = math.parse(d).compile();
416425
417426
const du = (B - A) / rNum;
418427
const dx = (B - A) / lcm(nX, cNum);
419428
const points = [];
420429
421430
for (let u = A; u <= B; u += du) {
422-
const cU = C.evaluate({ x: u });
423-
const dU = D.evaluate({ x: u });
431+
const cU = C(u);
432+
const dU = D(u);
424433
425434
const dy = (dU - cU) / lcm(nX, rNum);
426435
// args.x = u;
@@ -438,17 +447,17 @@
438447
439448
// v-Meshes
440449
// args.x = A;
441-
cMin = C.evaluate({ x: A });
442-
dMax = D.evaluate({ x: A });
450+
cMin = C(A);
451+
dMax = D(A);
443452
for (let u = A + dx; u <= B; u += dx) {
444453
// args.x = u;
445-
cMin = Math.min(cMin, C.evaluate({ x: u }));
446-
dMax = Math.max(dMax, D.evaluate({ x: u }));
454+
cMin = Math.min(cMin, C(u));
455+
dMax = Math.max(dMax, D(u));
447456
}
448457
449458
for (let v = cMin; v <= dMax; v += (dMax - cMin) / cNum) {
450459
const zs = marchingSegments(
451-
(x) => (C.evaluate({ x: x }) - v) * (v - D.evaluate({ x: x })),
460+
(x) => (C(x) - v) * (v - D(x)),
452461
A,
453462
B,
454463
nX,
@@ -457,7 +466,7 @@
457466
let nextZero = zs.shift();
458467
for (let u = A; u <= B - dx + tol; u += dx) {
459468
// args.x = u;
460-
if (C.evaluate({ x: u }) <= v && v <= D.evaluate({ x: u })) {
469+
if (C(u) <= v && v <= D(u)) {
461470
points.push(new THREE.Vector3(u, v, func(u, v, tVal)));
462471
if (nextZero < u + dx) {
463472
// args.x = nextZero;
@@ -499,8 +508,21 @@
499508
return geometry;
500509
};
501510
511+
function integrateSurface(n = 20) {
512+
return gaussLegendre(
513+
(x) => gaussLegendre((y) => func(x, y, tVal), C(x), D(x), n),
514+
A,
515+
B,
516+
n,
517+
);
518+
}
519+
502520
const evolveSurface = function (t) {
503-
boxMeshVisible = false;
521+
if (boxMeshVisible) {
522+
volumeInt = integrateSurface();
523+
updateBoxes();
524+
}
525+
// boxMeshVisible = false;
504526
505527
// the front and back surfaces share a geometry. The meshlines are separate
506528
for (let j = 0; j < 3; j += 2) {
@@ -709,28 +731,22 @@
709731
element.geometry.dispose();
710732
levelHolder.remove(element);
711733
}
712-
const { a, b, c, d } = params;
734+
// const { a, b, c, d } = params;
713735
// const t0 = math.parse(params.t0).evaluate();
714736
// const t1 = math.parse(params.t1).evaluate();
715737
// const t = t0 + tau * (t1 - t0);
716-
let C = 0,
717-
D = 0,
718-
zMin = 0,
738+
let yMin = C(A),
739+
yMax = D(A);
740+
let zMin = 0,
719741
zMax = 0;
720-
const [A, B] = [math.evaluate(a), math.evaluate(b)];
742+
// const [A, B] = [math.evaluate(a), math.evaluate(b)];
721743
for (let i = 0; i <= data.nL; i++) {
722-
C = Math.min(
723-
C,
724-
math.evaluate(c, { x: A + ((B - A) * i) / data.nL }),
725-
);
726-
D = Math.max(
727-
D,
728-
math.evaluate(d, { x: A + ((B - A) * i) / data.nL }),
729-
);
744+
yMin = Math.min(yMin, C(A + ((B - A) * i) / data.nL));
745+
yMax = Math.max(yMax, D(A + ((B - A) * i) / data.nL));
730746
for (let j = 0; j <= data.nL; j++) {
731747
const Z = func(
732748
A + ((B - A) * i) / data.nL,
733-
C + ((D - C) * j) / data.nL,
749+
yMin + ((yMax - yMin) * j) / data.nL,
734750
tVal,
735751
);
736752
zMin = Math.min(zMin, Z);
@@ -749,8 +765,8 @@
749765
},
750766
xmin: A,
751767
xmax: B,
752-
ymin: C,
753-
ymax: D,
768+
ymin: yMin,
769+
ymax: yMax,
754770
level: lev,
755771
zLevel: 0,
756772
nX: 200,
@@ -816,7 +832,12 @@
816832
boxMesh.material = colorMaterial;
817833
818834
let boxMeshVisible = $state(false);
819-
$effect(() => (boxMesh.visible = boxMeshVisible));
835+
$effect(() => {
836+
boxMesh.visible = boxMeshVisible;
837+
untrack(() => {
838+
volumeInt = integrateSurface();
839+
});
840+
});
820841
821842
scene.add(boxMesh);
822843
const boxMeshEdges = new THREE.LineSegments(
@@ -826,25 +847,25 @@
826847
boxMesh.add(boxMeshEdges);
827848
828849
const updateBoxes = function () {
829-
const { a, b, c, d } = params;
830-
try {
831-
[
832-
math.evaluate(a),
833-
math.evaluate(b),
834-
math.evaluate(c),
835-
math.evaluate(d),
836-
];
837-
} catch (e) {
838-
console.error("Can't show integral boxes on nonconstant bounds", e);
839-
return;
840-
}
841-
842-
const [A, B, C, D] = [
843-
math.evaluate(a),
844-
math.evaluate(b),
845-
math.evaluate(c),
846-
math.evaluate(d),
847-
];
850+
// const { a, b, c, d } = params;
851+
// try {
852+
// [
853+
// math.evaluate(a),
854+
// math.evaluate(b),
855+
// math.evaluate(c),
856+
// math.evaluate(d),
857+
// ];
858+
// } catch (e) {
859+
// console.error("Can't show integral boxes on nonconstant bounds", e);
860+
// return;
861+
// }
862+
863+
// const [A, B, C, D] = [
864+
// math.evaluate(a),
865+
// math.evaluate(b),
866+
// math.evaluate(c),
867+
// math.evaluate(d),
868+
// ];
848869
849870
// const t = T0 + tau * (T1 - T0);
850871
@@ -865,6 +886,9 @@
865886
data.s,
866887
data.t,
867888
);
889+
890+
approxVol = boxMesh.geometry.volume;
891+
868892
boxMeshEdges.geometry = new THREE.EdgesGeometry(boxMesh.geometry);
869893
};
870894
@@ -1324,6 +1348,19 @@
13241348
}}
13251349
class="box box-2"
13261350
/>
1351+
<p class="box-all">
1352+
<M
1353+
s={`\\sum_{i =1}^N\\sum_{j=1}^N f\\,\\Delta A = ${approxVol.toFixed(3)}`}
1354+
display
1355+
/>
1356+
</p>
1357+
<p class="box-all">
1358+
A more accurate estimation:
1359+
<M
1360+
s={`\\iint\\limits_{\\mathcal R} f\\,dA \\approx ${volumeInt.toFixed(3)}`}
1361+
display
1362+
/>
1363+
</p>
13271364
{/if}
13281365
</div>
13291366
</div>

0 commit comments

Comments
 (0)