ListSurfacePlot3D generates ugly artifacts
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/ptvgeom/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.005}];
s = BSplineFunction[t];
ParametricPlot3D[s[u, v], {u, 0, 1}, {v, 0, 1},
PlotStyle -> {Orange, Specularity[White, 10]},
Axes -> None, Mesh -> None]
The following is a laborious procedure to build an homogeneous grid with angular symmetry. Not for the faint of heart, but it matches the original points quite well:
ptv = Import["http://leaf.dragonflybsd.org/~beket/ptvgeom/ag1", "Table"];
Needs["DifferentialEquations`InterpolatingFunctionAnatomy`"];
gb = GatherBy[ptv, Last];
means = {1, 1, 0} # & /@ Mean /@ gb;
(*with the means subtracted the rings are almost concentric circles *)
ListPointPlot3D@(mi = MapIndexed[#1 - means[[#2[[1]]]] &, gb, {2}])
(* Order them by angle *)
miOrd = SortBy[#, ArcTan[#[[1]], #[[2]]] &] & /@ mi;
(* find a nice curved path for them *)
miM = #[[First@FindCurvePath[#[[All, 1 ;; 2]]]]] & /@ mi;
(* get all of them winding in the same direction *)
miMdir = If[Tr@Sign@(Subtract @@@ Partition[ArcTan[#[[1]], #[[2]]] & /@ #, 2, 1]) > 0, #,
Reverse@#] & /@ miM;
(* and strting at the same angle *)
miMR = RotateLeft[#, First@Ordering[#, 1,
ArcTan[#1[[1]], #1[[2]]] < ArcTan[#2[[1]], #2[[2]]] &]] & /@ miMdir;
(* close the curves *)
miMRP = Append[#, #[[1]]] & /@ miMR;
(* calculate the interpolations *)
interp = Map[Interpolation[#] &, Transpose /@ miMRP, {2}];
(* Now we will calculate a homogeneous grid*)
mm = Max[Length /@ Flatten[(InterpolatingFunctionCoordinates@#[[1]] & /@ interp), 1]];
Show @@ (Plot[
ArcTan[#[[1]], #[[2]]] &@Through[#[x]], {x,
1, (Length @@ InterpolatingFunctionCoordinates@#[[1]] - 1)},
PlotRange -> {{0, mm}, {-Pi, Pi}}] & /@ interp)
findAngle[angle_, fun_] :=
x /. FindRoot[ angle == ArcTan[#[[1]], #[[2]]] &@Through[#[x]], {x, 1, 1,
Length @@ InterpolatingFunctionCoordinates@#[[1]] - 1}] &@fun
radii = Quiet@ Outer[{#1, #2, Norm[#[[1 ;; 2]]] &@
Through[(interp[[#2]])@findAngle[#1, interp[[#2]]]]} &,
Range[Pi - .001, -Pi + .001, -Pi/100], Range@Length@interp, 1];
(* so, this is the grid *)
ListPlot3D[Flatten[radii, 1]]
(* the cylindrical interpolation*)
g = Interpolation[Flatten[radii, 1]];
(*a scale conversion*)
conv[pt_] := {pt[[1]], pt[[2]], Rescale[pt[[3]], {-81, 25}, {1, Length@interp}]}
Show[Quiet@
ParametricPlot3D[{# Cos@u, # Sin@u, v} &@g[u, v] +
Join[Through[(Interpolation /@ Transpose@means[[All, 1 ;; 2]])[
v]], {0}], {u, -Pi, Pi}, {v, 1, 22}, BoxRatios -> 1,
PlotStyle -> {Opacity[.8], Orange, Specularity[White, 10]},
Axes -> None, Mesh -> None],
ListPointPlot3D[conv /@ ptv, PlotStyle -> {Blue, PointSize[Medium]}]]