How to integrate a function over a 3D planar polygon?

Even if it's a 2D planar polygon in 3D space, it's still a 2D object. 2D objects are always 0 under a 3D measure.

Here we go through two methods of performing the scalar surface integral with a random polygon example.

Say we have a general 3D polygon defined as this:

polygonPts3D = {
                {-0.902757, -0.116805, 0},
                {0.203504, -0.972294, 0},
                {0.849893, 0.414192, 0},
                {0.374057, 0.835407, 0},
                {-0.907079, 0.352119, 0}
               };

and a scalar function defined in $xyz$ space:

Clear[f]
f[x_,y_,z_] := x^3-y^2+z

The standard way:

It's easy to derive the equation of the planar (planeEq) which the polygon is on:

Clear[normFunc]
normFunc[pts_] := Mean[
  Normalize[Cross[##]] & @@@
   Partition[
    Subtract @@@ Partition[pts, 2, 1, 1],
    2, 1, 1]
  ]

norm = normFunc[polygonPts3D]

planeEq = norm.({x, y, z} - Mean[polygonPts3D]) == 0

ContourPlot3D[
    Evaluate[planeEq],
    {x, -1, 1}, {y, -1, 1}, {z, -1, 1},
    RegionFunction -> Function[{x, y, z, func},
        inPolyQ[ReplacePart[polygonPts3D, {_, 3} :> 0], {x, y, 0}]
        ],
    Mesh -> 20,
    MeshFunctions -> Function[{x, y, z, func}, f[x, y, z]],
    ColorFunction -> Function[{x, y, z, func}, Hue[f[x, y, z]]],
    ColorFunctionScaling -> False,
    AxesLabel -> (Style[#, Red, Bold, 20] & /@ {x, y, z})
 ]

3D image

Thus the standard way to perform the surface integral

$$\int_P f(x,y,z)\,\mathrm{d}S = \int_{P_{xy}} f(x,y,z(x,y)) \sqrt{1+\left(\frac{\partial z}{\partial x}\right)^2+\left(\frac{\partial z}{\partial y}\right)^2} \,\mathrm{d}x\mathrm{d}y$$

would be straightforward in Mathematica

zFunc[x_, y_] := Evaluate[z /. Solve[planeEq, z][[1]]]

1/norm[[3]] NIntegrate[
    f[x, y, zFunc[x, y]]*
    Boole[inPolyQ[ polygonPts3D, {x, y, zFunc[x, y]} ]],
     {x, -∞, ∞}, {y, -∞, ∞}
    ] // Quiet

0.484606

The other way:

Also, we can establish a new coordinate system $x'y'z'$ such that the polygon lies on plane of $z'=0$, so we can convert the surface integral in $xyz$-space to a 2D area integral in $x'y'$-space.

To achieve that, we need a rotation which convert the norm of the polygon to $z'$ axis:

transMatrix = RotationMatrix[{
                              normFunc[polygonPts3D],
                              {0, 0, 1}
                             }]\[Transpose]
transMatrixInverse = Inverse@transMatrix

So the polygon in $x'y'z'$ should be:

polygonPts2D = ReplacePart[polygonPts3D.transMatrix, {_, 3} :> 0]

and the distance from the origin to the polygon plane:

distance = norm.Mean[polygonPts3D]

It can be seen that the transformed polygon is essentially the same with the original one:

RegionPlot[
    Evaluate[inPolyQ[polygonPts2D, {x, y, 0}]],
    {x, -1.2, 1.2}, {y, -1.2, 1.2},
    MeshFunctions -> Function[{x, y, z, func},
        f @@ ({{x, y, distance}}.transMatrixInverse)[[1]]
        ],
    Mesh -> 20,
    ColorFunction -> Function[{x, y, z, func},
        Hue[f @@ ({{x, y, distance}}.transMatrixInverse)[[1]]]
        ],
    ColorFunctionScaling -> False,
    FrameLabel -> (Style[#, Red, Bold, 20] & /@ {x, y})
 ]

2D image

And the integral is:

NIntegrate[
  f @@ ({{x, y, distance}}.transMatrixInverse)[[1]]*
   Boole[inPolyQ[polygonPts2D, {x, y, 0} ]],
   {x, -∞, ∞}, {y, -∞, ∞}
  ] // Quiet

0.483194

Side note:

For planar polygons, I think there is conformal transformation which can provide bijective maps between the polygon and the unit disk (or eventually maps between the polygon and a rectangle), which in some cases might simplify the integrals and provide more precise results.

SC mapping


In Mathematica 10, this can be easily computed using built-in functionality. Using Silvia's answer's polygon and function:

polygonPts3D = {
           {-0.902757, -0.116805, 0},
            {0.203504, -0.972294, 0},
            {0.849893, 0.414192, 0},
            {0.374057, 0.835407, 0},
            {-0.907079, 0.352119, 0}
           };
f[x_,y_,z_] := x^3-y^2+z

All you need to do is:

Integrate[f[x, y, z], Element[{x, y, z}, Polygon[polygonPts3D]]]
Out[]:= -0.323842

For a triangle, this can be solved by integrating in barycentric coordinates. Assuming the function that is being integrated takes in f[{x,y,z}] as an argument:

f[pos_List] := 1
integralOverTriangle[vertices_,f_]:=
 Module[{area},
  area=Norm[1/2 Cross[vertices[[1]]-vertices[[2]],vertices[[1]]-vertices[[3]]]];
  2 area Integrate[f[l1 vertices[[1]]+l2 vertices[[2]]+(1-l1-l2)vertices[[3]]],
   {l2,0,1},  {l1,0,1-l2}]
 ]
nintegralOverTriangle[vertices_,f_]:=
 Module[{area},
  area=Norm[1/2 Cross[vertices[[1]]-vertices[[2]],vertices[[1]]-vertices[[3]]]];
  2 area NIntegrate[f[l1 vertices[[1]]+l2 vertices[[2]]+(1-l1-l2)vertices[[3]]],
   {l2,0,1},  {l1,0,1-l2}]
 ]

Then,

integralOverTriangle[basetri,1&]
(* Out[]:= Sqrt[3]/4 *)

and, the triangle can be oriented arbitrarily:

integralOverTriangle[RotationTransform[{{0, 0, 1}, Normalize[{1, 1, 1}]}] /@ basetri, 1 &]
(* Out[]:= Sqrt[3]/4 *)