The natural way to go is BSplineFunction[]
. The problem is that it needs a rectangular array of data as input and you collected a different number of points for each z plane.
So what we will do is to get an interpolating function for each z == const
plane and generate an equal number of points at each plane. To be somewhat more clever, we could generate evenly spaced points along each curve, but that small modification is left as an exercise.
Please note that the Spline Degree determines if the curve pass along your points exactly, or is just a smoothed approximation.
ClearAll["Global`*"];
ptv = Import["http://leaf.dragonflybsd.org/~beket/ag1", "Table"];
Needs["DifferentialEquations`InterpolatingFunctionAnatomy`"];
gb = GatherBy[ptv, Last];
f[k_InterpolatingFunction, p_] :=
k[p (Length @@ InterpolatingFunctionCoordinates[k] - 1) + 1]
t = Append[#, First@#] & /@
Transpose@ Table[{f[Interpolation[#[[All, 1]]], p],
f[Interpolation[#[[All, 2]]], p], #[[1, 3]]}& /@ gb,
{p, 0, 1, 0.05}];
s = BSplineFunction[t];
ParametricPlot3D[s[u, v], {u, 0, 1}, {v, 0, 1},
PlotStyle -> {Orange, Specularity[White, 10]},
Axes -> None, Mesh -> None]
Edit
You may toy around with SplineDegree
to go from a very smooth surface to a very tight fit for your points. For example with degree -> 1, you get:
s = BSplineFunction[t, SplineDegree -> 1]
Show[{Graphics3D@Point@ptv,
ParametricPlot3D[s[u, v], {u, 0, 1}, {v, 0, 1},
PlotStyle -> {Orange, Specularity[White, 10]},
Axes ->None, Mesh -> None]}]