Skip to content

Commit

Permalink
Added API for torus and vesical geometry objects
Browse files Browse the repository at this point in the history
  • Loading branch information
favreau committed Nov 30, 2023
1 parent 6a9132b commit 4432018
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 7 deletions.
52 changes: 52 additions & 0 deletions bioexplorer/backend/science/BioExplorerPlugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,18 @@ void BioExplorerPlugin::init()
endPoint = PLUGIN_API_PREFIX + "add-sdf-demo";
PLUGIN_INFO(1, "Registering '" + endPoint + "' endpoint");
actionInterface->registerRequest<Response>(endPoint, [&]() { return _addSdfDemo(); });

endPoint = PLUGIN_API_PREFIX + "add-torus";
PLUGIN_REGISTER_ENDPOINT(endPoint);
_api->getActionInterface()->registerRequest<SDFTorusDetails, Response>(endPoint,
[&](const SDFTorusDetails &payload)
{ return _addTorus(payload); });

endPoint = PLUGIN_API_PREFIX + "add-vesica";
PLUGIN_REGISTER_ENDPOINT(endPoint);
_api->getActionInterface()->registerRequest<SDFVesicaDetails, Response>(endPoint,
[&](const SDFVesicaDetails &payload)
{ return _addVesica(payload); });
}

auto &params = engine.getParametersManager().getApplicationParameters();
Expand Down Expand Up @@ -2147,6 +2159,46 @@ Response BioExplorerPlugin::_setSpikeReportVisualizationSettings(const SpikeRepo
return response;
}

Response BioExplorerPlugin::_addTorus(const details::SDFTorusDetails &payload)
{
Response response;
try
{
auto &scene = _api->getScene();
auto model = scene.createModel();
ThreadSafeContainer modelContainer(*model, 0.f, Vector3d(), Quaterniond());
const size_t materialId = 0;
const auto position = doublesToVector3d(payload.position);
const auto displacement = doublesToVector3d(payload.displacement);
modelContainer.addTorus(position, payload.outerRadius, payload.innerRadius, materialId, NO_USER_DATA, {},
displacement);
modelContainer.commitToModel();
scene.addModel(std::make_shared<ModelDescriptor>(std::move(model), payload.name));
}
CATCH_STD_EXCEPTION()
return response;
}

Response BioExplorerPlugin::_addVesica(const details::SDFVesicaDetails &payload)
{
Response response;
try
{
auto &scene = _api->getScene();
auto model = scene.createModel();
ThreadSafeContainer modelContainer(*model, 0.f, Vector3d(), Quaterniond());
const size_t materialId = 0;
const auto source = doublesToVector3d(payload.srcPosition);
const auto target = doublesToVector3d(payload.dstPosition);
const auto displacement = doublesToVector3d(payload.displacement);
modelContainer.addVesica(source, target, payload.radius, materialId, NO_USER_DATA, {}, displacement);
modelContainer.commitToModel();
scene.addModel(std::make_shared<ModelDescriptor>(std::move(model), payload.name));
}
CATCH_STD_EXCEPTION()
return response;
}

extern "C" ExtensionPlugin *core_plugin_create(int argc, char **argv)
{
PLUGIN_INFO(1, " _|_|_| _| _|_|_|_| _| ");
Expand Down
4 changes: 4 additions & 0 deletions bioexplorer/backend/science/BioExplorerPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ class BioExplorerPlugin : public core::ExtensionPlugin
details::LookAtResponseDetails _lookAt(const details::LookAtDetails &payload);
details::Response _addSdfDemo();

// SDF Geometries
details::Response _addTorus(const details::SDFTorusDetails &payload);
details::Response _addVesica(const details::SDFVesicaDetails &payload);

// Attributes
common::AssemblyMap _assemblies;

Expand Down
37 changes: 37 additions & 0 deletions bioexplorer/backend/science/api/Params.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1155,4 +1155,41 @@ bool from_json(SpikeReportVisualizationSettingsDetails &param, const std::string
}
return true;
}

bool from_json(bioexplorer::details::SDFTorusDetails &param, const std::string &payload)
{
try
{
auto js = nlohmann::json::parse(payload);
FROM_JSON(param, js, name);
FROM_JSON(param, js, position);
FROM_JSON(param, js, outerRadius);
FROM_JSON(param, js, innerRadius);
FROM_JSON(param, js, displacement);
}
catch (...)
{
return false;
}
return true;
}

bool from_json(bioexplorer::details::SDFVesicaDetails &param, const std::string &payload)
{
try
{
auto js = nlohmann::json::parse(payload);
FROM_JSON(param, js, name);
FROM_JSON(param, js, srcPosition);
FROM_JSON(param, js, dstPosition);
FROM_JSON(param, js, radius);
FROM_JSON(param, js, displacement);
}
catch (...)
{
return false;
}
return true;
}

#endif
4 changes: 4 additions & 0 deletions bioexplorer/backend/science/api/Params.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ bool from_json(bioexplorer::details::SynapsesDetails &param, const std::string &
bool from_json(bioexplorer::details::SynapseEfficacyDetails &param, const std::string &payload);
bool from_json(bioexplorer::details::SpikeReportVisualizationSettingsDetails &param, const std::string &payload);

// Extra geometry
bool from_json(bioexplorer::details::SDFTorusDetails &param, const std::string &payload);
bool from_json(bioexplorer::details::SDFVesicaDetails &param, const std::string &payload);

// Utilities
bool from_json(bioexplorer::details::LookAtDetails &param, const std::string &payload);
std::string to_json(const bioexplorer::details::LookAtResponseDetails &param);
Expand Down
3 changes: 0 additions & 3 deletions bioexplorer/backend/science/common/ThreadSafeContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ namespace bioexplorer
{
namespace common
{
using MaterialSet = std::set<size_t>;
using Neighbours = std::set<size_t>;

/**
* @brief The ThreadSafeContainer class is used to load large datasets in
* parallel. Every individual element is loaded in a separate thread and
Expand Down
21 changes: 21 additions & 0 deletions bioexplorer/backend/science/common/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ const double NO_GRID_ALIGNMENT = 0.0;

namespace common
{
using MaterialSet = std::set<size_t>;
using Neighbours = std::set<size_t>;

class Node;
using NodePtr = std::shared_ptr<Node>;
using NodeMap = std::map<std::string, NodePtr>;
Expand Down Expand Up @@ -1669,5 +1672,23 @@ typedef struct
double frequency{1.0};
} CellAnimationDetails;

typedef struct
{
std::string name;
doubles position;
double outerRadius;
double innerRadius;
doubles displacement;
} SDFTorusDetails;

typedef struct
{
std::string name;
doubles srcPosition;
doubles dstPosition;
double radius;
doubles displacement;
} SDFVesicaDetails;

} // namespace details
} // namespace bioexplorer
7 changes: 4 additions & 3 deletions bioexplorer/backend/science/morphologies/Neurons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ void Neurons::_buildMorphology(ThreadSafeContainer& container, const uint64_t ne
if (distanceToSoma <= _details.maxDistanceToSoma)
_addSection(container, neuronId, soma.morphologyId, section.first, section.second, geometryIndex,
somaPosition, somaRotation, somaRadius, baseMaterialId, mitochondriaDensity, somaUserData,
synapses, distanceToSoma);
synapses, distanceToSoma, neighbours);
}
} // namespace morphology

Expand Down Expand Up @@ -730,7 +730,8 @@ void Neurons::_addSection(ThreadSafeContainer& container, const uint64_t neuronI
const uint64_t sectionId, const Section& section, const uint64_t somaGeometryIndex,
const Vector3d& somaPosition, const Quaterniond& somaRotation, const double somaRadius,
const size_t baseMaterialId, const double mitochondriaDensity, const uint64_t somaUserData,
const SectionSynapseMap& synapses, const double distanceToSoma)
const SectionSynapseMap& synapses, const double distanceToSoma,
const Neighbours& somaNeighbours)
{
const auto& connector = DBConnector::getInstance();
const auto sectionType = static_cast<NeuronSectionType>(section.type);
Expand Down Expand Up @@ -778,7 +779,7 @@ void Neurons::_addSection(ThreadSafeContainer& container, const uint64_t neuronI
double sectionLength = 0.0;
double sectionVolume = 0.0;
uint64_t geometryIndex = 0;
Neighbours neighbours;
Neighbours neighbours = somaNeighbours;
if (_details.morphologyColorScheme == MorphologyColorScheme::none)
neighbours.insert(somaGeometryIndex);

Expand Down
3 changes: 2 additions & 1 deletion bioexplorer/backend/science/morphologies/Neurons.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ class Neurons : public Morphologies
const uint64_t sectionId, const Section& section, const uint64_t somaGeometryIndex,
const core::Vector3d& somaPosition, const core::Quaterniond& somaRotation, const double somaRadius,
const size_t baseMaterialId, const double mitochondriaDensity, const uint64_t somaUserData,
const SectionSynapseMap& synapses, const double distanceToSoma);
const SectionSynapseMap& synapses, const double distanceToSoma,
const common::Neighbours& somaNeighbours);

void _addSpine(common::ThreadSafeContainer& container, const uint64_t neuronId, const uint64_t morphologyId,
const uint64_t sectionId, const Synapse& synapse, const size_t baseMaterialId,
Expand Down
46 changes: 46 additions & 0 deletions bioexplorer/pythonsdk/bioexplorer/bio_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3040,6 +3040,52 @@ def add_sdf_demo(self):

return self._invoke_and_check("add-sdf-demo")

def add_torus(self, name, position, outer_radius, inner_radius, displacement_parameters=Vector3()):
"""
Add a torus to the scene
:return: Result of the request submission
"""
if self._client is None:
return

assert isinstance(name, str)
assert isinstance(position, Vector3)
assert isinstance(outer_radius, float)
assert isinstance(inner_radius, float)
assert isinstance(displacement_parameters, Vector3)

params = dict()
params["name"] = name
params["position"] = position.to_list()
params["outerRadius"] = outer_radius
params["innerRadius"] = inner_radius
params["displacement"] = displacement_parameters.to_list()
return self._invoke_and_check("add-torus", params)

def add_vesica(self, name, source_position, target_position, radius, displacement_parameters=Vector3()):
"""
Add a vesica to the scene
:return: Result of the request submission
"""
if self._client is None:
return

assert isinstance(name, str)
assert isinstance(source_position, Vector3)
assert isinstance(target_position, Vector3)
assert isinstance(radius, float)
assert isinstance(displacement_parameters, Vector3)

params = dict()
params["name"] = name
params["srcPosition"] = source_position.to_list()
params["dstPosition"] = target_position.to_list()
params["radius"] = radius
params["displacement"] = displacement_parameters.to_list()
return self._invoke_and_check("add-vesica", params)

def add_streamlines(self, name, indices, vertices, colors):
"""
Add streamlines to the scene
Expand Down

0 comments on commit 4432018

Please sign in to comment.