Given a spatial curve represented by a parametric equation, is it possible in Mathematica 9 to calculate symbolically (or at least numerically) the volume of its convex hull?
-
2$\begingroup$ Can you give s a hint about the kind of parametric curve you want to look at, and perhaps some code to work with? $\endgroup$– bill sCommented May 24, 2013 at 16:59
-
1$\begingroup$ duplicate : mathematica.stackexchange.com/q/6908/5467 $\endgroup$– andre314Commented May 24, 2013 at 17:01
-
2$\begingroup$ That doesn't quite seem to be a duplicate, @andre, because there the data are given in a different form. In principle there should be a formula for computing the volume in terms of a suitable integrals over the curve. $\endgroup$– whuberCommented May 24, 2013 at 17:07
-
$\begingroup$ @whuber sorry. Also : related question $\endgroup$– andre314Commented May 24, 2013 at 17:44
-
2$\begingroup$ It does provide a feasible numerical solution though. $\endgroup$– SzabolcsCommented May 24, 2013 at 18:48
4 Answers
Here is a way to do it numerically:
Reap the points from a parametric plot:
pf = {Cos[u], Sin[u] + Cos[v], Sin[v]};
data = Reap[
ParametricPlot3D[
Sow[pf], {u, 0, 2 \[Pi]}, {v, -\[Pi], \[Pi]}]][[2, 1]];
Get all the numeric values, pack the data and delete the duplicates:
pts = Cases[data, {_?NumericQ, _?NumericQ, _?NumericQ}];
pts = DeleteDuplicates[Developer`ToPackedArray@N[pts]];
To look at the points:
Graphics3D[Point[pts], Boxed -> False]
Load TetGenLink and compute and visualize the convex hull:
<<TetGenLink`
ch = TetGenConvexHull[pts];
Graphics3D[GraphicsComplex[ch[[1]], Polygon[ch[[2]]]], Boxed -> False]
Compute the delaunay mesh of the convex hull, write a function to compute the volume of a tetrahedron, apply it and total the volume of the tetrahedra:
dt = TetGenDelaunay[pts];
tetVol = Compile[{{coords, _Real, 2}, {incidents, _Integer, 1}},
Block[{a, b, c, d},
{a, b, c, d} = coords[[incidents]];
1/6*Det[Transpose[{a, c, b}] - d]
], RuntimeAttributes -> Listable];
Total[tetVol @@ dt]
(* 12.5 *)
Sanity check: for a sphere we get:
pf = {Sin[u]*Sin[v], Cos[u]*Sin[v], Cos[v]};
4.138` - 4./3*\[Pi]*1^3
(*-0.05*)
which seams reasonable.
Update:
As suggested by Daniel Lichtblau, this also works for parametric curves:
pf = {(t^2 - 1)/(t^2 + 1),
2 t/(t^2 + 1), ((t^2 - 1)/(t^2 + 1))^2 - (2 t/(t^2 + 1))^2};
data = Reap[ParametricPlot3D[Sow[pf], {t, -10, 10}]][[2, 1]];
pts = Cases[data, {_?NumericQ, _?NumericQ, _?NumericQ}];
pts = DeleteDuplicates[Developer`ToPackedArray@N[pts]];
Graphics3D[Point[pts], Boxed -> False]
<< TetGenLink`
ch = TetGenConvexHull[pts];
Graphics3D[GraphicsComplex[ch[[1]], Polygon[ch[[2]]]], Boxed -> False]
And what I find most amazing is the suggestion from george2079:
shoelace3rd = Compile[{{coords, _Real, 2}, {tris, _Integer, 2}},
-Total[Det[coords[[#]]] & /@ tris]/6
];
shoelace3rd @@ ch
(* 3.12 *)
-
3$\begingroup$ I voted this up because it is quite useful, but I remark that it applies to a parametric surface, not curve. To do similarly with a curve one would perhaps take points thereon, and also convex combinations of (many) pairs of points. Then proceed as above. Example (saddle curve) to test with:
ParametricPlot3D[{(t^2 - 1)/(t^2 + 1), 2 t/(t^2 + 1), ((t^2 - 1)/(t^2 + 1))^2 - (2 t/(t^2 + 1))^2}, {t, -10, 10}, PlotRange -> All]
$\endgroup$ Commented May 28, 2013 at 17:53 -
$\begingroup$ @DanielLichtblau, I added the extension, thanks. $\endgroup$– user21Commented May 28, 2013 at 19:43
Following ruebenko's approach, after computing the convex hull you can much faster directly get the volume without triangulating the volume as 1/6 Sum[ Det [ triangle vertices ] ]:
Do[ -Total[
Det[{ch[[1, #[[1]]]], ch[[1, #[[2]]]], ch[[1, #[[3]]]]}] & /@
ch[[2]]]/6 , {10}]
(* 12.5077 *)
This is the 3d shoelace formula:
http://en.wikipedia.org/wiki/Shoelace_formula
I must say I've searched pretty good for a link to derivation/proof of this useful thing and come up empty.
Ok the derivation was not so hard to work out.. Note implict here is an assumption that the vertices of each triangle are ordered consistantly CW or CCW. Also this does not require convexity, only whatever connectivity restrictions follow from the divergance theorem.
-
$\begingroup$ +1 this is quite impressive, if you do find a deviation, I'd be very interested to hear about it. $\endgroup$– user21Commented May 28, 2013 at 19:26
-
$\begingroup$ @gerrge2079, thanks for the deviation. Very useful indeed. $\endgroup$– user21Commented May 29, 2013 at 5:50
In Version 10, once the points have been obtained as per user21's approach, we can tetrahedralize them directly using DelaunayMesh
pf = {Cos[u], Sin[u] + Cos[v], Sin[v]};
pp = ParametricPlot3D[pf, {u, 0, 2 Pi}, {v, -Pi, Pi}]
data = Reap[ParametricPlot3D[Sow[pf], {u, 0, 2 Pi}, {v, -Pi, Pi}]][[2, 1]];
pts = Cases[data, {_?NumericQ, _?NumericQ, _?NumericQ}];
Then:
del = DelaunayMesh[pts]
And the volume is computed easily using RegionMeasure
RegionMeasure[del]
12.5077258
Here is another way that uses the Graphics
object directly:
gr = ParametricPlot3D[{Cos[u], Sin[u] + Cos[v], Sin[v]}, {u, 0, 2 Pi}, {v, -Pi, Pi}]
We discretize the graphics using DiscretizeGraphics
mr = DiscretizeGraphics[Normal[gr /. (Lighting -> _) :> Lighting -> Automatic]]
We compute the convex hull
hull = ConvexHullMesh[MeshCoordinates[mr]]
And finally, we get the volume using RegionMeasure
RegionMeasure[hull]
12.5077258
OR Volume
Volume[hull]
12.5077258
As a bonus we can get the surface area of the ParametricPlot
object:
RegionMeasure[mr, 2]
33.1870442
Same result can be obtained using Area
Area[mr]
33.1870442