22
$\begingroup$

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?

$\endgroup$
5
  • 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 s
    Commented May 24, 2013 at 16:59
  • 1
    $\begingroup$ duplicate : mathematica.stackexchange.com/q/6908/5467 $\endgroup$
    – andre314
    Commented 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$
    – whuber
    Commented May 24, 2013 at 17:07
  • $\begingroup$ @whuber sorry. Also : related question $\endgroup$
    – andre314
    Commented May 24, 2013 at 17:44
  • 2
    $\begingroup$ It does provide a feasible numerical solution though. $\endgroup$
    – Szabolcs
    Commented May 24, 2013 at 18:48

4 Answers 4

14
$\begingroup$

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]

enter image description here

Load TetGenLink and compute and visualize the convex hull:

<<TetGenLink`
ch = TetGenConvexHull[pts];
Graphics3D[GraphicsComplex[ch[[1]], Polygon[ch[[2]]]], Boxed -> False]

enter image description here

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]

enter image description here

<< TetGenLink`
ch = TetGenConvexHull[pts];
Graphics3D[GraphicsComplex[ch[[1]], Polygon[ch[[2]]]], Boxed -> False]

enter image description here

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 *)
$\endgroup$
2
  • 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$
    – user21
    Commented May 28, 2013 at 19:43
10
$\begingroup$

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:

https://stackoverflow.com/questions/14710682/algorithm-for-partially-filling-a-polygonal-mesh/14713130#14713130

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.

enter image description here

$\endgroup$
2
  • $\begingroup$ +1 this is quite impressive, if you do find a deviation, I'd be very interested to hear about it. $\endgroup$
    – user21
    Commented May 28, 2013 at 19:26
  • $\begingroup$ @gerrge2079, thanks for the deviation. Very useful indeed. $\endgroup$
    – user21
    Commented May 29, 2013 at 5:50
7
$\begingroup$

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}]

Mathematica graphics

data = Reap[ParametricPlot3D[Sow[pf], {u, 0, 2 Pi}, {v, -Pi, Pi}]][[2, 1]];
pts = Cases[data, {_?NumericQ, _?NumericQ, _?NumericQ}];

Then:

del = DelaunayMesh[pts]

Mathematica graphics

And the volume is computed easily using RegionMeasure

RegionMeasure[del]

12.5077258

$\endgroup$
7
$\begingroup$

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}]

Mathematica graphics

We discretize the graphics using DiscretizeGraphics

mr = DiscretizeGraphics[Normal[gr /. (Lighting -> _) :> Lighting -> Automatic]]

Mathematica graphics

We compute the convex hull

hull = ConvexHullMesh[MeshCoordinates[mr]]

Mathematica graphics

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

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.