Skip to main content

graphics3d - How to calculate volume of convex hull and volume of a 3D object


I have a set of random 3D data points.


How can I calculate the volume of the convex hull?



Answer



This following code that uses TetGen we will compute the volume of the convex hull.


Needs["TetGenLink`"];

TetraMaker[pts_, surface_, TetGenString_?StringQ] :=
Module[{inInst, outInst, coords, surface1, meshElements, facets},
inInst = TetGenCreate[];
TetGenSetPoints[inInst, pts];
facets = Partition[surface, 1];
TetGenSetFacets[inInst, facets];
outInst = TetGenTetrahedralize[inInst, TetGenString];
coords = TetGenGetPoints[outInst];
surface1 = TetGenGetFaces[outInst];
meshElements = TetGenGetElements[outInst];

{coords, surface1, meshElements}
];
TetrahedraVolume = Compile[{{coords, _Real, 2}, {elements, _Integer, 1}},
Block[{p},
p = coords[[elements]];
1/6*Abs[Det[p[[ {1, 2, 3}]] - p[[{2, 3, 4}]]]]
], RuntimeAttributes -> {Listable}, RuntimeOptions -> "Speed"
];

Some 3D data



data3D = RandomReal[{0, 10}, {65, 3}];

Compute the convex hull and then call the above function to form the tetrahedralization. Then call TetrahedraVolume to compute the volume.


{pts, surface} = TetGenConvexHull[data3D];
{coords, surface1, meshElements} = TetraMaker[pts, surface, "pqa2.8"];
Total[ TetrahedraVolume[coords, meshElements]]


505.135




You can use this to compute surface area of a triangulated 3D geometry


TriangleArea[pts_List?(Length[#] == 3 &)] := 
Norm[Cross[pts[[2]] - pts[[1]], pts[[3]] - pts[[1]]]]/2
TriangleArea[{pts[[#[[1]]]], pts[[#[[2]]]], pts[[#[[3]]]]}] & /@ surface // Total


337.121



I compute the area of the triangles separately and adding them gives me the area of the surface that defines the convex hull. enter image description here


In the above picture first you see the convex hull in black lines. The middle one shows the blue surface mesh created by TetGen during tetrahedralization. In the last one you can see the cell volumes of the tetrahedrons that discretize the volume of the convex hull in different random colors. We get the total volume by adding the volumes of these tetrahedrons.



Volume for Convex Hull of the point cloud in your data


data3D = Import["http://dl.dropbox.com/u/68983831/object.vtk", "VertexData"];
{pts, surface} = TetGenConvexHull[data3D];
{coords, surface1, meshElements} = TetraMaker[pts, surface, "pqa2.8"];
Total[ TetrahedraVolume[coords, meshElements]]


3120.05



Volume for 3D Geometry in your data



surface = Import["http://dl.dropbox.com/u/68983831/object.vtk", "PolygonData"];
{coords, surface1, meshElements} = TetraMaker[pts, surface, "pqa.8"];
Total[TetrahedraVolume[coords, meshElements]]


1622.23



enter image description here Code for Graphics


p1 = Graphics3D[{{Red, PointSize[0.03], Point[data3D]}, {Yellow, 
Opacity[.8], EdgeForm[{Thick, Black}],

GraphicsComplex[pts, Polygon[surface]]}}, Boxed -> False, Axes -> True];
p2 = Graphics3D[{{Red, PointSize[0.03],
Point[data3D]}, {EdgeForm[{Thick, Black}], FaceForm[None],
GraphicsComplex[pts, Polygon[surface]]}, {Yellow, Opacity[.8],
EdgeForm[Blue], GraphicsComplex[coords, Polygon[surface1]]}},
Boxed -> False, Axes -> True];
p3 = Graphics3D[{{Red, PointSize[0.03], Point[data3D]},
Table[With[{p =
RGBColor[RandomReal[{0, 1}, 3]]}, {Blend[{Lighter[Yellow, .8],
Red, Yellow}, i/Length@meshElements], Glow[Darker[p, .5]],

Specularity[White, 20], Opacity[.2], EdgeForm[p],
GraphicsComplex[coords,
Polygon@Partition[meshElements[[i]], 3, 1, 1]]}], {i, 1,
Length@meshElements}]}, Boxed -> False, Axes -> True];
GraphicsGrid[Transpose@{{p1, p2, p3}}, Spacings -> {0, 0},ImageSize -> 600]

Comments

Popular posts from this blog

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

plotting - Plot 4D data with color as 4th dimension

I have a list of 4D data (x position, y position, amplitude, wavelength). I want to plot x, y, and amplitude on a 3D plot and have the color of the points correspond to the wavelength. I have seen many examples using functions to define color but my wavelength cannot be expressed by an analytic function. Is there a simple way to do this? Answer Here a another possible way to visualize 4D data: data = Flatten[Table[{x, y, x^2 + y^2, Sin[x - y]}, {x, -Pi, Pi,Pi/10}, {y,-Pi,Pi, Pi/10}], 1]; You can use the function Point along with VertexColors . Now the points are places using the first three elements and the color is determined by the fourth. In this case I used Hue, but you can use whatever you prefer. Graphics3D[ Point[data[[All, 1 ;; 3]], VertexColors -> Hue /@ data[[All, 4]]], Axes -> True, BoxRatios -> {1, 1, 1/GoldenRatio}]