Blue Brain BioExplorer
XYZBLoader.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2024, EPFL/Blue Brain Project
3  *
4  * The Blue Brain BioExplorer is a tool for scientists to extract and analyse
5  * scientific data from visualization
6  *
7  * This file is part of Blue Brain BioExplorer <https://github.com/BlueBrain/BioExplorer>
8  *
9  * This library is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU Lesser General Public License version 3.0 as published
11  * by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include "XYZBLoader.h"
24 
30 
31 #include <fstream>
32 #include <sstream>
33 
34 namespace core
35 {
36 namespace
37 {
38 constexpr auto ALMOST_ZERO = 1e-7f;
39 constexpr auto LOADER_NAME = "xyzb";
40 
41 float _computeHalfArea(const Boxf& bbox)
42 {
43  const auto size = bbox.getSize();
44  return size[0] * size[1] + size[0] * size[2] + size[1] * size[2];
45 }
46 } // namespace
47 
49  : Loader(scene)
50 {
51 }
52 
53 bool XYZBLoader::isSupported(const std::string& storage, const std::string& extension) const
54 {
55  const std::set<std::string> types = {"xyz"};
56  return types.find(extension) != types.end();
57 }
58 
60  const PropertyMap& properties) const
61 {
62  CORE_INFO("Loading xyz " << blob.name);
63 
64  std::stringstream stream(std::string(blob.data.begin(), blob.data.end()));
65  size_t numlines = 0;
66  {
67  numlines = std::count(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>(), '\n');
68  }
69  stream.seekg(0);
70 
71  auto model = _scene.createModel();
72 
73  const auto name = fs::path({blob.name}).stem();
74  const auto materialId = 0;
75  model->createMaterial(materialId, name);
76  auto& spheres = model->getSpheres()[materialId];
77 
78  const size_t startOffset = spheres.size();
79  spheres.reserve(spheres.size() + numlines);
80 
81  Boxf bbox;
82  size_t i = 0;
83  std::string line;
84  std::stringstream msg;
85  msg << "Loading " << string_utils::shortenString(blob.name) << " ...";
86  while (std::getline(stream, line))
87  {
88  std::vector<float> lineData;
89  std::stringstream lineStream(line);
90 
91  float value;
92  while (lineStream >> value)
93  lineData.push_back(value);
94 
95  switch (lineData.size())
96  {
97  case 3:
98  {
99  const Vector3f position(lineData[0], lineData[1], lineData[2]);
100  bbox.merge(position);
101  // The point radius used here is irrelevant as it's going to be
102  // changed later.
103  model->addSphere(materialId, {position, 1});
104  break;
105  }
106  default:
107  throw std::runtime_error("Invalid content in line " + std::to_string(i + 1) + ": " + line);
108  }
109  callback.updateProgress(msg.str(), i++ / static_cast<float>(numlines));
110  }
111 
112  // Find an appropriate mean radius to avoid overlaps of the spheres, see
113  // https://en.wikipedia.org/wiki/Wigner%E2%80%93Seitz_radius
114 
115  const auto volume = glm::compMul(bbox.getSize());
116  const auto density4PI = 4 * M_PI * numlines / (volume > ALMOST_ZERO ? volume : _computeHalfArea(bbox));
117 
118  const double meanRadius = volume > ALMOST_ZERO ? std::pow((3. / density4PI), 1. / 3.) : std::sqrt(1 / density4PI);
119 
120  // resize the spheres to the new mean radius
121  for (i = 0; i < numlines; ++i)
122  spheres[i + startOffset].radius = meanRadius;
123 
124  Transformation transformation;
125  transformation.setRotationCenter(model->getBounds().getCenter());
126  auto modelDescriptor = std::make_shared<ModelDescriptor>(std::move(model), blob.name);
127  modelDescriptor->setTransformation(transformation);
128 
129  Property radiusProperty("radius", meanRadius, 0., meanRadius * 2., {"Point size"});
130  radiusProperty.onModified(
131  [modelDesc = std::weak_ptr<ModelDescriptor>(modelDescriptor)](const auto& property)
132  {
133  if (auto modelDesc_ = modelDesc.lock())
134  {
135  const auto newRadius = property.template get<double>();
136  for (auto& sphere : modelDesc_->getModel().getSpheres()[materialId])
137  sphere.radius = newRadius;
138  }
139  });
140  PropertyMap modelProperties;
141  modelProperties.setProperty(radiusProperty);
142  modelDescriptor->setProperties(modelProperties);
143  return modelDescriptor;
144 }
145 
146 ModelDescriptorPtr XYZBLoader::importFromStorage(const std::string& storage, const LoaderProgress& callback,
147  const PropertyMap& properties) const
148 {
149  std::ifstream file(storage);
150  if (!file.good())
151  CORE_THROW("Could not open file " + storage);
152  return importFromBlob({"xyz", storage, {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()}},
153  callback, properties);
154 }
155 
156 std::string XYZBLoader::getName() const
157 {
158  return LOADER_NAME;
159 }
160 
161 std::vector<std::string> XYZBLoader::getSupportedStorage() const
162 {
163  return {"xyz"};
164 }
165 } // namespace core
vec getSize() const
Definition: MathTypes.h:91
void merge(const Box< T > &aabb)
Definition: MathTypes.h:64
void updateProgress(const std::string &message, const float fraction) const
Definition: Loader.h:58
Scene & _scene
Definition: Loader.h:126
void setProperty(const Property &newProperty)
Definition: PropertyMap.h:307
Scene object This object contains collections of geometries, materials and light sources that are use...
Definition: Scene.h:43
virtual PLATFORM_API ModelPtr createModel() const =0
Factory method to create an engine-specific model.
Defines the translation, rotation and scale parameters to be applied to a scene asset.
void setRotationCenter(const Vector3d &value)
bool isSupported(const std::string &storage, const std::string &extension) const final
Definition: XYZBLoader.cpp:53
ModelDescriptorPtr importFromBlob(Blob &&blob, const LoaderProgress &callback, const PropertyMap &properties) const final
Definition: XYZBLoader.cpp:59
std::vector< std::string > getSupportedStorage() const final
Definition: XYZBLoader.cpp:161
std::string getName() const final
Definition: XYZBLoader.cpp:156
ModelDescriptorPtr importFromStorage(const std::string &storage, const LoaderProgress &callback, const PropertyMap &properties) const final
Definition: XYZBLoader.cpp:146
XYZBLoader(Scene &scene)
Definition: XYZBLoader.cpp:48
const std::string LOADER_NAME
Definition: AtlasLoader.cpp:42
std::string shortenString(const std::string &string, const size_t maxLength)
Definition: StringUtils.cpp:37
glm::vec3 Vector3f
Definition: MathTypes.h:137
std::shared_ptr< ModelDescriptor > ModelDescriptorPtr
Definition: Types.h:112
Box< float > Boxf
Definition: MathTypes.h:118
#define CORE_THROW(__msg)
Definition: Logs.h:42
#define CORE_INFO(__msg)
Definition: Logs.h:33
void onModified(const ModifiedCallback &callback)
Definition: PropertyMap.h:172