# Visualising and detecting stacked oblate particles

Context:

I am trying to learn how to visualize a box filled with oblate-shaped particles. These are in contrast to prolates which can be drawn using for example Tube. Each oblate is characterized by a center of mass vector $$\mathbf{r},$$ a normalized orientation vector $$\mathbf{o},$$ and an aspect ratio $$ar=a/c$$ with $$a>c$$ where $$a$$ is the equatorial radius and $$c$$ the polar radius. Intuitively, the aspect ratio simply is a width to thickness ratio.

Attempts and issues so far:

I cannot find a Graphics3D function that already draws such particles, the closest I could find was to use Ellipsoid which takes a center of mass position vector and the 3 axis lengths. Therefore, this function does not allow to draw the oblates with the desired orientation. So I then tried to use either Rotate or GeometricTransformation[...,RotationTransform[]] but unsuccessfully so, as it seems to ignore the orientations in the way that I have written it.

Below is the module I've written that takes as input: a file for the center coordinates of particles (one line of 3 coordinates per particle), a similar file but for orientation vectors, $$lx,ly,lz$$ which are the box side lengths, and finally the aspect ratio $$ar$$ of the oblates. The module reads the input and draws everything: (sample file for center and orientation can be downloaded from hyperlinks)

f[centres_, orientations_, lx_, ly_, lz_, ar_] :=
Module[{csvcentres = centres, csvorien = orientations, lxx = lx,
lyy = ly, lzz = lz, L = ar},
oblatecenters =
Import[FileNameJoin[{NotebookDirectory[], csvcentres}], "Data"];
oblatedirections =
Import[FileNameJoin[{NotebookDirectory[], csvorien}], "Data"];
r = 1.0;
oblates = {};
(*Below the orientations of each particle mx,my,mz are not yet added to oblates list.*)
For[i = 1, i <= Length[oblatecenters], i++,
{rx, ry, rz} = oblatecenters[[i]]; {mx, my, mz} =
oblatedirections[[i]];
AppendTo[oblates, {{rx, ry, rz}, {L, L, r}}]
];
boxLowerPoint = {-0.5*lxx, -0.5*lyy, -0.5*lzz};
boxUpperPoint = {0.5*lxx, 0.5*lyy, 0.5*lzz};
cube = Cuboid[boxLowerPoint, boxUpperPoint];
(*For test purposes, we are assuming all particles have same orientation vector of (0,0,1) here.*)
graph1 =
Graphics3D[{GeometricTransformation[
Ellipsoid[#1, #2] & @@@ oblates,
RotationTransform[
N@VectorAngle[{0., 0., 1.}, {1, 0., 0.}], {0., 0., 1.}]], Blue,
Opacity[0.01], cube}, Boxed -> False];
Show[graph1]
]


Then we call the module for the following example:

f["cluster2_centres.csv", "cluster2_orientations.csv", 150, 150, 150, \
20]


which produces:

And they all have the same original/default orientation (that is, the geometric transformation appears to not have done anything, my guess is it is being applied maybe to whole box instead of individual particles).

My questions:

1. Is there a way we could draw the oblate particles with their respective orientations (mx,my,mz) taken into account? The Ellipsoid function does not directly allow for this, so a workaround would be to apply a rotation transformation to each drawn object, unless there's another function (other than Ellipsoid) that can draw spheroids with orientation. This is in contrast to capsules in Mathematica, for which the two end-points are taken as input instead of just center of mass coordinate, which means the orientation can be encoded in the Capsule input (by computing the endpoint coordinates from the center and orientation vectors).

Illustration to clarify how orientation vectors which are part of input data, are defined for each oblate:

In the image below, we see a blue vector which is the initial orientation {0,0,1} the particle gets drawn with, which is the normal to the surface of the oblate, going through the centre point of the oblate. And the red vector is the wanted (input) orientation {-0.150611, 0.00905835, 0.988552} vector that also with its tail anchored to the centre of the particle:

centers = Import["C:\\Users\\W10\\Downloads\\cluster2_centres.csv", "Data"];



You can use Scale to create an oblate spheroid from Sphere:

ClearAll[oblate, translaterotate]
oblate[a_, c_] := Scale[Sphere[], {a, a, c}, {0, 0, 0}]


then transform oblate[a, c] using Rotate and Translate:

translaterotate = MapThread[Translate[Rotate[oblate[20, 4], #, #2, {0, 0, 0}], #2] &,
{angles, centers}];

Graphics3D[{Opacity[.5], RandomColor[], #} & /@ translaterotate,  ImageSize -> 600]


Note: I am not sure if I interpreted the relation between centers, orientations and angles correctly.