Skip to content

Commit a35c346

Browse files
author
Cyrille Pierre Henri Favreau
committed
Build of somas as spheres
1 parent 99e0571 commit a35c346

File tree

5 files changed

+81
-73
lines changed

5 files changed

+81
-73
lines changed

bioexplorer/backend/science/morphologies/Astrocytes.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,15 @@ void Astrocytes::_buildModel(const LoaderProgress& callback, const doubles& radi
203203
const bool useSdf = andCheck(static_cast<uint32_t>(_details.realismLevel),
204204
static_cast<uint32_t>(MorphologyRealismLevel::soma));
205205

206-
if (!_spheresRepresentation.enabled)
207-
{
206+
if (_spheresRepresentation.enabled)
207+
_addSomaAsSpheres(somaId, somaMaterialId, sections, somaPosition, Quaterniond(), somaRadius,
208+
NO_USER_DATA, _details.radiusMultiplier, container);
209+
else
208210
somaGeometryIndex = container.addSphere(
209211
somaPosition, somaRadius, somaMaterialId, useSdf, NO_USER_DATA, {},
210212
Vector3f(somaRadius * _getDisplacementValue(DisplacementElement::morphology_soma_strength),
211213
somaRadius * _getDisplacementValue(DisplacementElement::morphology_soma_frequency),
212214
0.f));
213-
}
214215

215216
if (_details.generateInternals)
216217
{
@@ -259,7 +260,7 @@ void Astrocytes::_buildModel(const LoaderProgress& callback, const doubles& radi
259260
const bool useSdf = andCheck(static_cast<uint32_t>(_details.realismLevel),
260261
static_cast<uint32_t>(MorphologyRealismLevel::dendrite));
261262
uint64_t geometryIndex = 0;
262-
if (section.second.parentId == SOMA_AS_PARENT)
263+
if (section.second.parentId == SOMA_AS_PARENT && !_spheresRepresentation.enabled)
263264
{
264265
// Section connected to the soma
265266
const auto& point = points[0];

bioexplorer/backend/science/morphologies/Morphologies.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,76 @@ size_t Morphologies::_getNbMitochondrionSegments() const
4141
return 2 + rand() % 5;
4242
}
4343

44+
double Morphologies::_addSomaAsSpheres(const uint64_t neuronId, const size_t somaMaterialId, const SectionMap& sections,
45+
const Vector3d& somaPosition, const Quaterniond& somaRotation,
46+
const double somaRadius, const uint64_t somaUserData,
47+
const double radiusMultiplier, ThreadSafeContainer& container)
48+
{
49+
Vector3ds sectionRoots;
50+
51+
double minRadius = std::numeric_limits<double>::max();
52+
double maxRadius = std::numeric_limits<double>::min();
53+
double sectionRootRadius = std::numeric_limits<double>::max();
54+
Vector3d baryCenter;
55+
for (const auto& section : sections)
56+
if (section.second.parentId == SOMA_AS_PARENT)
57+
{
58+
const auto& points = section.second.points;
59+
const uint64_t index = std::min(size_t(0), points.size());
60+
const Vector3d p = points[index];
61+
sectionRoots.push_back(p);
62+
const double l = length(p);
63+
minRadius = std::min(l, minRadius);
64+
maxRadius = std::max(l, maxRadius);
65+
sectionRootRadius = std::min(sectionRootRadius, static_cast<double>(points[index].w * 0.5));
66+
baryCenter += p;
67+
}
68+
baryCenter /= sectionRoots.size();
69+
// sectionRootRadius = sectionRootRadius / sectionRoots.size() * radiusMultiplier;
70+
71+
const double radius = (minRadius + maxRadius) / 2.0;
72+
const double somaSurface = 4.0 * glm::pi<double>() * pow(radius, 2.0);
73+
const double sphereSurfaceOnSoma = glm::pi<double>() * pow(sectionRootRadius, 2.0);
74+
const uint64_t nbSpheres = somaSurface / sphereSurfaceOnSoma;
75+
76+
Vector3ds spheres(nbSpheres);
77+
78+
const double goldenRatio = (1.0 + std::sqrt(5.0)) / 2.0;
79+
const double angleIncrement = 2.0 * M_PI * goldenRatio;
80+
for (uint64_t i = 0; i < nbSpheres; ++i)
81+
{
82+
const double t = static_cast<double>(i) / static_cast<double>(nbSpheres - 1);
83+
const double phi = std::acos(1.0 - 2.0 * t);
84+
const double theta = angleIncrement * static_cast<double>(i);
85+
const double r = minRadius;
86+
spheres[i] = Vector3d(r * sin(phi) * cos(theta), r * sin(phi) * sin(theta), r * cos(phi));
87+
}
88+
89+
// Smooth soma according to section root
90+
for (auto& sphere : spheres)
91+
{
92+
#if 1
93+
const double smoothingFactor = 1.0;
94+
double r = minRadius * smoothingFactor;
95+
for (const auto& sr : sectionRoots)
96+
{
97+
const auto dir = sr - (baryCenter + sphere);
98+
const double angle = dot(normalize(sr), normalize(baryCenter + sphere));
99+
if (angle >= 0.0)
100+
r += length(dir) * -angle * smoothingFactor;
101+
}
102+
#endif
103+
104+
const auto src =
105+
_animatedPosition(Vector4d(somaPosition + somaRotation * (baryCenter + normalize(sphere) * r * 0.5),
106+
sectionRootRadius),
107+
neuronId);
108+
container.addSphere(src, sectionRootRadius, somaMaterialId, false, somaUserData);
109+
}
110+
111+
return somaRadius;
112+
}
113+
44114
void Morphologies::_addSomaInternals(ThreadSafeContainer& container, const size_t baseMaterialId,
45115
const Vector3d& somaPosition, const double somaRadius,
46116
const double mitochondriaDensity, const bool useSdf, const double radiusMultiplier)

bioexplorer/backend/science/morphologies/Morphologies.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class Morphologies : public common::SDFGeometries
5656
protected:
5757
size_t _getNbMitochondrionSegments() const;
5858

59+
double _addSomaAsSpheres(const uint64_t neuronId, const size_t somaMaterialId, const SectionMap& sections,
60+
const core::Vector3d& somaPosition, const core::Quaterniond& somaRotation,
61+
const double somaRadius, const uint64_t somaUserData, const double radiusMultiplier,
62+
common::ThreadSafeContainer& container);
63+
5964
void _addSomaInternals(common::ThreadSafeContainer& container, const size_t materialId,
6065
const core::Vector3d& somaPosition, const double somaRadius,
6166
const double mitochondriaDensity, const bool useSdf, const double radiusMultiplier);

bioexplorer/backend/science/morphologies/Neurons.cpp

Lines changed: 1 addition & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -555,69 +555,6 @@ double Neurons::_addSoma(const uint64_t neuronId, const size_t somaMaterialId, c
555555
return count == 0 ? somaRadius : correctedSomaRadius / count;
556556
}
557557

558-
double Neurons::_addSomaAsSpheres(const uint64_t neuronId, const size_t somaMaterialId, const SectionMap& sections,
559-
const Vector3d& somaPosition, const Quaterniond& somaRotation,
560-
const double somaRadius, const uint64_t somaUserData, ThreadSafeContainer& container)
561-
{
562-
// Paramètres
563-
uint64_t nbPoints = 2000;
564-
double small_sphere_radius = 0.5;
565-
566-
// Vecteurs pour stocker les coordonnées
567-
Vector3ds points(nbPoints);
568-
Vector3ds stretched_points;
569-
570-
double minRadius = std::numeric_limits<double>::max();
571-
double maxRadius = std::numeric_limits<double>::min();
572-
Vector3d baryCenter;
573-
for (const auto& section : sections)
574-
{
575-
if (section.second.parentId == SOMA_AS_PARENT)
576-
{
577-
const auto& points = section.second.points;
578-
const uint64_t index = std::min(size_t(1), points.size());
579-
const Vector3d p = points[index];
580-
stretched_points.push_back(p);
581-
const double l = length(p);
582-
minRadius = std::min(l, minRadius);
583-
maxRadius = std::max(l, maxRadius);
584-
baryCenter += p;
585-
}
586-
}
587-
baryCenter /= stretched_points.size();
588-
589-
const auto radius = (minRadius + maxRadius) / 2.0;
590-
591-
// Génération des points aléatoires sur une sphère
592-
for (uint64_t i = 0; i < nbPoints; ++i)
593-
{
594-
const double theta = glm::linearRand(0.0, 2.0 * glm::pi<double>());
595-
const double phi = acos(glm::linearRand(-1.0, 1.0));
596-
points[i] = baryCenter + Vector3d(minRadius * sin(theta) * cos(phi), minRadius * sin(theta) * sin(phi),
597-
minRadius * cos(theta));
598-
}
599-
600-
for (auto& point : points)
601-
{
602-
auto p = Vector3d();
603-
for (const auto& sp : stretched_points)
604-
{
605-
const auto dir = sp - point;
606-
const double angle = dot(normalize(sp), normalize(point));
607-
if (angle > 0.7)
608-
p += dir * angle;
609-
}
610-
p /= stretched_points.size();
611-
point += 3.0 * p;
612-
613-
const auto src =
614-
_animatedPosition(Vector4d(somaPosition + somaRotation * point, small_sphere_radius), neuronId);
615-
container.addSphere(src, small_sphere_radius, somaMaterialId, false, somaUserData);
616-
}
617-
618-
return somaRadius;
619-
}
620-
621558
void Neurons::_buildMorphology(ThreadSafeContainer& container, const uint64_t neuronId, const NeuronSoma& soma,
622559
const uint64_t neuronIndex, const float* voltages)
623560
{
@@ -733,7 +670,7 @@ void Neurons::_buildMorphology(ThreadSafeContainer& container, const uint64_t ne
733670
double correctedSomaRadius = 0.f;
734671
if (_spheresRepresentation.enabled)
735672
correctedSomaRadius = _addSomaAsSpheres(neuronId, somaMaterialId, sections, somaPosition, somaRotation,
736-
somaRadius, somaUserData, container);
673+
somaRadius, somaUserData, _details.radiusMultiplier, container);
737674

738675
// Sections (dendrites and axon)
739676
Neighbours somaNeighbours;

bioexplorer/backend/science/morphologies/Neurons.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@ class Neurons : public Morphologies
7878
const uint64_t somaUserData, const double voltageScaling, common::ThreadSafeContainer& container,
7979
common::Neighbours& somaMeighbours, common::Neighbours& sectionNeighbours);
8080

81-
double _addSomaAsSpheres(const uint64_t neuronId, const size_t somaMaterialId, const SectionMap& sections,
82-
const core::Vector3d& somaPosition, const core::Quaterniond& somaRotation,
83-
const double somaRadius, const uint64_t somaUserData,
84-
common::ThreadSafeContainer& container);
85-
8681
void _buildOrientations(common::ThreadSafeContainer& container, const NeuronSomaMap& somas);
8782

8883
void _buildMorphology(common::ThreadSafeContainer& container, const uint64_t neuronId, const NeuronSoma& soma,

0 commit comments

Comments
 (0)