Distribution of random points in 3D space to simulate the Crab Nebula

Here's an attempt in which I start with a set of "void points", which will be the centres of the gaps between filaments. The stars are then created as an initially random distribution, and are repeatedly nudged away from their nearest void point. Or, to look at it another way, they are attracted towards the edges of the Voronoi cells defined by the void points. There is also a contraction at each iteration to prevent stars from escaping towards infinity.

Update: My original code used ParallelMap which turned out to be considerably slower than plain old Map. Thanks to @halmir for pointing that out. I should have checked. Following that observation, a couple of other optimisations emerged. The updated code below includes simplification of the filamentation function using Expand, and performs each iteration step on all the points at once (where the original code did the full set of iterations on each point in turn). Finally, I have used ParallelTable to distribute the calculation across all the CPU cores (and this time I have checked that it is faster that way...) The filementation code now runs in a couple of seconds on my 4-core machine.

A bit more explanation as requested:

In the code below the first two lines create random points in the sphere (actually it would be better to use the OP's Coords function in the question for this bit, as it provides better control of the point density).

The function f embodies the the filamentation. At each step, each point in pts moves 1% further away from its nearest void point (the 0.01) and then 0.25% closer to the origin (the 0.9975). This is repeated 200 times for each point.

The filamentation process reduces the size of the point cloud from the initial radius of 1 to something around 0.75. In the Graphics3D output the points are coloured according to their distance from the origin, the factor of 1.3 in the colour function is simply to there to compensate for the contraction.

voidpts = Select[RandomReal[{-1, 1}, {1000, 3}], Norm[#] <= 1 &];
pts = Select[RandomReal[{-1, 1}, {10000, 3}], Norm[#] <= 1 &];
nf = Nearest[voidpts];

f = Evaluate[Expand[0.9975 (#1 + 0.01 (#1 - #2))]] &;

DistributeDefinitions[nf, f];
pts = Developer`ToPackedArray @ Drop[pts, Length[pts] ~ Mod ~ $KernelCount];

pts = Join @@ ParallelTable[Nest[f[#, (nf /@ #)[[All, 1]]] &, p, 200],
    {p, Partition[pts, Length[pts]/$KernelCount]}];

cf = ColorData["SunsetColors"];
Graphics3D[{PointSize[0.005], {cf[Norm[1.3 #]], Sphere[#, 0.005]} & /@ pts}, 
  Boxed -> False, Background -> Black, Lighting -> "Neutral", 
  SphericalRegion -> True, ViewPoint -> {0.75, -0.75, 0.75}, ViewAngle -> 0.7]

enter image description here

In principle you could muck around with the initial distribution of void points to get larger voids and better defined filaments in the centre, as appears to be the case in the original image. Unfortunately the code is rather slow so it's not much fun to experiment with.

Here's the gratuitous animation:

enter image description here

To create an ouput list of the form {{X1, Y1, Z1, R1, G1, B1}, {X2, Y2, Z2, R2, G2, B2}, {X3, Y3, Z3, R3, G3, B3}, ...} you could do something like:

coords = Join[#, List @@ cf[1.3 Norm[#]]] & /@ pts;

Update 2021

Astronomers have actually done the job for you with the real crab nebula:

http://www.cfht.hawaii.edu/en/news/HeartofTheCrab/out-outreach.mp4

enter image description here

This movie (be a bit patient) allows you to rotate around the observed nebulae as described here


If you use this code take the hessian of it and plot the map of the largest eigenvalues you get a nice filamentary map like the bottom right panel.

Mathematica graphics

see this reference (specifically pp 28 of the phd).

In mathematica it can be coded as follows

 nn = 256;u = GaussianRandomField[nn, 2, Function[k, k^-4]]//GaussianFilter[#, 4] & // Chop;
  Clear[f]; f[x_, y_] = ListInterpolation[u][x, y];
  Clear[d2f]; d2f[x_, y_] = {{D[f[x, y], {x, 2}],
        D[f[x, y], x, y]}, {D[f[x, y], x, y], D[f[x, y], {y, 2}]}};
  h = Table[d2f[x, y], {x, nn}, {y, nn}];
  ee = Table[Eigenvalues[h[[i, j, All, All]]], {i, nn}, {j, nn}];
  ee = Map[Max, Abs[ee], {2}];
  ee[[1 ;; nn - 1, 1 ;; nn - 1]] // Image // ImageAdjust

producing

Mathematica graphics

Removing the Abs for nn=512 yields

Mathematica graphics

Varying the power law and the smoothing would allow you to produce e.g.

Mathematica graphics

and if you mix the result of 3 such images

Transpose[{ee1, ee2, ee3}, {3, 1, 2}] // Image // ImageAdjust

Mathematica graphics

The same applies in 3D

nn = 64; u = GaussianRandomField[nn, 3, Function[k, k^-3]]//GaussianFilter[#, 6] & // Chop; 
Clear[f]; f[x_, y_, z_] = ListInterpolation[u][x, y, z];
Clear[d2f]; d2f[x_, y_, z_] = {
  {D[f[x, y, z], x, x], D[f[x, y, z], x, y], 
   D[f[x, y, z], x, z]}, {D[f[x, y, z], x, y], D[f[x, y, z], y, y], 
   D[f[x, y, z], y, z]},
  {D[f[x, y, z], x, z], D[f[x, y, z], y, z], D[f[x, y, z], z, z]}};
h = Table[d2f[x, y, z], {x, nn}, {y, nn}, {z, nn}];

ee = Table[
   Eigenvalues[h[[i, j, k, All, All]]], {i, nn}, {j, nn}, {k, nn}];
ee = Map[Max, ee, {3}];

If we look at a slice in 3D

 ImageAdjust@Image3D[Exp[ee/StandardDeviation[Flatten[ee]]], Background -> Black]

Mathematica graphics

EDIT

Let us explore another venue, just because this is how cosmologist generate initial conditions for simulations. Let us generate a displacement field corresponding to the gradient of a Gaussian Random field:

nn = 256; u = 
 GaussianRandomField[nn, 2, Function[k, k^-4]] // 
   GaussianFilter[#, 4] & // Chop;
Clear[f]; f[x_, y_] = ListInterpolation[u][x, y];
df[x_, y_] = {D[f[x, y], x], D[f[x, y], y]};
g = Table[df[x, y], {x, nn}, {y, nn}]; g /= Max[g];
grid = Outer[{#1, #2} &, Range[nn], Range[nn]];
Map[Point, grid + g*15, {2}] // 
 Graphics[{AbsolutePointSize[0.1], #}] &

Mathematica graphics

and in 3D

nn = 32; u = GaussianRandomField[nn, 3, Function[k, k^-4]] //GaussianFilter[#, 4] & // Chop;
Clear[f]; f[x_, y_, z_] = ListInterpolation[u][x, y, z];
df[x_, y_, z_] = {D[f[x, y, z], x], D[f[x, y, z], y], D[f[x, y, z], z]};
g = Table[df[x, y, z], {x, nn}, {y, nn}, {z, nn}]; g /= Max[g];
grid = Table[{i, j, k}, {i, nn}, {j, nn}, {k, nn}];
Map[Point, grid + g*8, {2}] // Graphics3D[{AbsolutePointSize[0.1], #}] &

Mathematica graphics

Or to make it look good borrowing Simon's graphics primitive

cf = ColorData["SunsetColors"]
Graphics3D[{PointSize[0.1], {cf[#[[2]]/nn], Sphere[#, 0.2]} & /@ pts}, 
Boxed -> False, Background -> Black, Lighting -> "Neutral", SphericalRegion -> True]

Mathematica graphics

Now the above code is fast (and could be made faster while using FFT to compute the gradients).

Note that we can remove the regular low density region points as follows

 pts = MapThread[If[Norm[#1] > 1/3, 15 #1 + #2, {}] &, {g, grid}, 2] //
  Flatten[#, 1] & // Union // Rest;
 Map[Point, pts] // Graphics[{AbsolutePointSize[0.1], #}] &

Mathematica graphics

EDIT 2

If I steal the set of points from Simon above (I hope he doesn't mind!) and trace its 3D skeleton I get this (So the credit to this method lies with Simon Woods and Thierry Sousbie)

Mathematica graphics

or changing the so called level of persistence and increasing the number of drawn points in Simon's code:

Mathematica graphics

And its really 3D :-)

enter image description here

Note that the original 2D image can be analysed directly by the skeleton, channel per channel,

Mathematica graphics

which demonstrates that the filamentary structure is colour dependent, but I guess I am getting over-carried! :-)

COMMENT

To answer the OP, the skeleton is not currently implemented in mathematica. The closest current implementation is watershading:

nn = 512; u0 =  GaussianRandomField[nn, 2, Function[k, k^-3]]//GaussianFilter[#, 3] & // Chop;
u = u0 // GaussianFilter[#, 8] & // Chop;
Clear[f]; f[x_, y_] = ListInterpolation[u][x, y];
df[x_, y_] = {D[f[x, y], x], D[f[x, y], y]};
g = Table[df[x, y] // Sqrt[#.#] &, {x, nn}, {y, nn}];
im0 = u0 // Image;im1 = g // Image // WatershedComponents // Image;
ImageMultiply[im1, im0] // ImageAdjust

Mathematica graphics

May be in version 10 ;-)


Here is the modified version of Simon Woods answer. In my machine with 2 core, ParallelMap version is slower and you could gain a little bit of speed up by using compiled version of iteration:

voidpts = Select[RandomReal[{-1, 1}, {1000, 3}], Norm[#] <= 1 &];
pts = Select[RandomReal[{-1, 1}, {10000, 3}], Norm[#] <= 1 &];
nf = Nearest[voidpts];
DistributeDefinitions[nf];

cNest = Compile[{{x, _Real, 1}, {n, _Integer}}, 
         Block[{pt = x}, 
             Do[pt = 0.9975 (pt + 0.01 (pt - First@nf[pt])), {i, n}]; 
             pt], {{nf[_], _Real, 2}}];

The following is the timing I got:

In[75]:= pt1 = 
    ParallelMap[Nest[0.9975 (# + 0.01 (# - First@nf[#])) &, #, 100] &, 
     pts]; // AbsoluteTiming
Out[75]= {98.073226, Null}

In[85]:= pt2 = 
   Map[Nest[0.9975 (# + 0.01 (# - First@nf[#])) &, #, 100] &, 
    pts]; // AbsoluteTiming
Out[85]= {7.226970, Null}

In[86]:= pt3 = Map[cNest[#, 100] &, pts]; // AbsoluteTiming
Out[86]= {5.901947, Null}

In[80]:= pt1 == pt2 == pt3
Out[80]= True

I don't see the any reason to use Sphere, so I replace with Point to gain speed:

cf = ColorData["SunsetColors"]; 
Graphics3D[{AbsolutePointSize[2], 
     Point[pt1, VertexColors -> (cf[Norm[1.3 #]] & /@ pt1)]}, 
     Boxed -> False, SphericalRegion -> True, 
     ViewPoint -> {0.75, -0.75, 0.75}, ViewAngle -> 0.7, 
     Background -> Black]

enter image description here

To check how each iteration goes (for fun):

ptlist = Transpose[
      Map[NestList[0.9975 (# + 0.01 (# - First@nf[#])) &, #, 200] &, 
     pts]];

Manipulate[
  Graphics3D[{AbsolutePointSize[2], 
    Point[ptlist[[i]], 
    VertexColors -> (cf[Norm[1.3 #]] & /@ ptlist[[i]])]}, 
    Boxed -> False, SphericalRegion -> True, 
    ViewPoint -> {0.75, -0.75, 0.75}, ViewAngle -> 0.7, 
    Background -> Black, PlotRange -> {-1.5, 1.5}], 
 {i, 1, Length[ptlist], 1}]