Here's a pretty neat way, based on the new FEM utilities for dealing with meshes, that works automatically for dimension 2 and 3, positively oriented, convex, simplex-element meshes. (More precisely, instead of being convex, the intersection of the region only with an arbitrary vertical line needs to consist of at most one connected component).
Initialization:
Needs["NDSolve`FEM`"]
data2D = {{4.4, 14}, {6.7, 15.25}, {6.9, 12.8}, {2.1, 11.1}, {9.5,
14.9}, {13.2, 11.9}, {10.3, 12.3}, {6.8, 9.5}, {3.3, 7.7}, {0.6,
5.1}, {5.3, 2.4}, {8.45, 4.7}, {11.5, 9.6}, {13.8, 7.3}, {12.9, 3.1}, {11, 1.1}};
g = ConvexHullMesh[data2D];
SeedRandom[0];
chm = ConvexHullMesh[RandomReal[{0, 5}, {20, 3}]];
The function top
produces an InterpolatingFunction
. The top mesh elements are selected and projected onto the domain. The height coordinates (y or z) are used as the values
for the interpolation over the projected mesh coordinates, basecoords
. The top elements are determined by their orientation in the domain. ConvexHullMesh
produces (or seems to) a positively oriented boundary in the sense of integration theorems of Green/Stokes/Gauss. Here orientation
means something slightly different. It yields the vertical component of an outward normal to the element, which will be positive, if the element is on top.
ClearAll[top];
top[reg_?BoundaryMeshRegionQ] /; reg["SimplexMeshQ"] :=
Module[{
dim, orientation,
allsimplices, topsimplices, topindices, basecoords,
values, element, mesh},
dim = reg["Dimension"];
orientation = dim /. {
2 -> (-First[Differences[#[[All, 1]]]] &),
3 -> (Last[Cross @@ Differences[#]] &)
};
allsimplices = MeshCells[reg, dim - 1] /. h_[list : {__Integer}] :> list;
topsimplices = Pick[
allsimplices,
Positive[orientation /@ (reg["Coordinates"][[#]] &) /@ allsimplices]];
topindices = AssociationThread[# -> Range@Length@#] &[Union @@ topsimplices];
With[{topcoords = reg["Coordinates"] ~Part~ Keys[topindices]},
basecoords = topcoords[[All, 1 ;; -2]];
values = topcoords[[All, dim]]
];
element = dim /. {2 -> LineElement, 3 -> TriangleElement};
mesh = ToElementMesh[
"Coordinates" -> basecoords,
"MeshElements" -> {element[topsimplices /. topindices]}];
ElementMeshInterpolation[{mesh}, values]
]
OP's example:
meshifn = top[g]
Show[
g,
Plot[meshifn[x], Evaluate@Flatten[{x, meshifn["Domain"]}], PlotStyle -> Red],
Frame -> True
]
Random convex hull:
meshifn = top[chm]
plot = Plot3D[meshifn[x, y], {x, y} ∈ meshifn["ElementMesh"], PlotPoints -> 100]
Show[
RegionPlot3D[chm, PlotStyle -> LightBlue],
plot,
Axes -> True, AxesLabel -> {x, y, z}
]
The funny color of the top surface in the plot on the right is due to the surfaces approximately coinciding.
It wouldn't be too hard to extend this to other sides.
MaxValue[y && x == #, {x, y} \[Element] g] &
is a natural approach, but it does not seem to be implemented. (Not forNMaxValue
either.) $\endgroup$