Skip to content

Commit b5ee397

Browse files
authored
BRAYNS-661 Vector field. (#1282)
1 parent 8f576db commit b5ee397

File tree

12 files changed

+348
-2
lines changed

12 files changed

+348
-2
lines changed

plugins/AtlasExplorer/api/AtlasFactory.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "atlases/LayerDistanceAtlas.h"
2525
#include "atlases/OrientationAtlas.h"
2626
#include "atlases/ScalarAtlas.h"
27+
#include "atlases/VectorAtlas.h"
2728

2829
namespace
2930
{
@@ -60,6 +61,7 @@ AtlasFactory AtlasFactory::createDefault()
6061
builder.registerType<LayerDistanceAtlas>();
6162
builder.registerType<OrientationAtlas>();
6263
builder.registerType<ScalarAtlas>();
64+
builder.registerType<VectorAtlas>();
6365
return AtlasFactory(std::move(builder.factories));
6466
}
6567

plugins/AtlasExplorer/api/UseCaseManager.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <api/usecases/LayerDistance.h>
2828
#include <api/usecases/OrientationField.h>
2929
#include <api/usecases/OutlineShell.h>
30+
#include <api/usecases/VectorField.h>
3031

3132
UseCaseManager UseCaseManager::createDefault()
3233
{
@@ -36,6 +37,7 @@ UseCaseManager UseCaseManager::createDefault()
3637
useCases.push_back(std::make_unique<HighlightColumn>());
3738
useCases.push_back(std::make_unique<LayerDistance>());
3839
useCases.push_back(std::make_unique<OrientationField>());
40+
useCases.push_back(std::make_unique<VectorField>());
3941
useCases.push_back(std::make_unique<OutlineShell>());
4042
useCases.push_back(std::make_unique<FlatmapAreas>());
4143
return UseCaseManager(std::move(useCases));

plugins/AtlasExplorer/api/VoxelType.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ enum class VoxelType
2525
Scalar,
2626
Orientation,
2727
Flatmap,
28-
LayerDistance
28+
LayerDistance,
29+
Vector,
2930
};
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/* Copyright (c) 2015-2024, EPFL/Blue Brain Project
2+
* All rights reserved. Do not distribute without permission.
3+
* Responsible Author: Nadir Roman Guerrero <[email protected]>
4+
*
5+
* This file is part of Brayns <https://github.com/BlueBrain/Brayns>
6+
*
7+
* This library is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU Lesser General Public License version 3.0 as published
9+
* by the Free Software Foundation.
10+
*
11+
* This library is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library; if not, write to the Free Software Foundation, Inc.,
18+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*/
20+
21+
#include "VectorAtlas.h"
22+
23+
#include <cassert>
24+
25+
namespace
26+
{
27+
float finiteOrZero(float value)
28+
{
29+
if (std::isfinite(value))
30+
{
31+
return value;
32+
}
33+
34+
return 0.0F;
35+
}
36+
37+
brayns::Vector3f sanitizeVector(brayns::Vector3f vector)
38+
{
39+
for (auto i = std::size_t(0); i < std::size_t(3); ++i)
40+
{
41+
vector[i] = finiteOrZero(vector[i]);
42+
}
43+
44+
auto norm = brayns::math::length(vector);
45+
46+
if (norm == 0.0F)
47+
{
48+
return vector;
49+
}
50+
51+
return vector / norm;
52+
}
53+
54+
std::vector<brayns::Vector3f> extractVectors(const IDataMangler &data)
55+
{
56+
auto floats = data.asFloats();
57+
auto itemCount = floats.size() / 3;
58+
59+
auto result = std::vector<brayns::Vector3f>(itemCount);
60+
61+
#pragma omp parallel for
62+
for (size_t i = 0; i < itemCount; ++i)
63+
{
64+
auto index = i * 3;
65+
66+
auto x = floats[index];
67+
auto y = floats[index + 1];
68+
auto z = floats[index + 2];
69+
70+
result[i] = sanitizeVector({x, y, z});
71+
}
72+
73+
return result;
74+
}
75+
}
76+
77+
VectorAtlas::VectorAtlas(
78+
const brayns::Vector3ui &size,
79+
const brayns::Vector3f &spacing,
80+
const IDataMangler &dataMangler):
81+
Atlas(size, spacing),
82+
_voxels(extractVectors(dataMangler))
83+
{
84+
}
85+
86+
bool VectorAtlas::isValidVoxel(size_t index) const noexcept
87+
{
88+
assert(_isValidIndex(index));
89+
return brayns::math::dot(_voxels[index], _voxels[index]) > 0.f;
90+
}
91+
92+
VoxelType VectorAtlas::getVoxelType() const noexcept
93+
{
94+
return type;
95+
}
96+
97+
const brayns::Vector3f &VectorAtlas::operator[](size_t index) const noexcept
98+
{
99+
assert(_isValidIndex(index));
100+
return _voxels[index];
101+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Copyright (c) 2015-2024, EPFL/Blue Brain Project
2+
* All rights reserved. Do not distribute without permission.
3+
* Responsible Author: Nadir Roman Guerrero <[email protected]>
4+
*
5+
* This file is part of Brayns <https://github.com/BlueBrain/Brayns>
6+
*
7+
* This library is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU Lesser General Public License version 3.0 as published
9+
* by the Free Software Foundation.
10+
*
11+
* This library is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library; if not, write to the Free Software Foundation, Inc.,
18+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*/
20+
21+
#pragma once
22+
23+
#include <api/Atlas.h>
24+
#include <api/DataMangler.h>
25+
26+
class VectorAtlas final : public Atlas
27+
{
28+
public:
29+
static inline const VoxelType type = VoxelType::Vector;
30+
31+
public:
32+
VectorAtlas(const brayns::Vector3ui &size, const brayns::Vector3f &spacing, const IDataMangler &dataMangler);
33+
34+
bool isValidVoxel(size_t linealIndex) const noexcept override;
35+
VoxelType getVoxelType() const noexcept override;
36+
const brayns::Vector3f &operator[](size_t index) const noexcept;
37+
38+
private:
39+
std::vector<brayns::Vector3f> _voxels;
40+
};
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/* Copyright (c) 2015-2024, EPFL/Blue Brain Project
2+
* All rights reserved. Do not distribute without permission.
3+
* Responsible Author: Adrien Fleury <[email protected]>
4+
*
5+
* This file is part of Brayns <https://github.com/BlueBrain/Brayns>
6+
*
7+
* This library is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU Lesser General Public License version 3.0 as published
9+
* by the Free Software Foundation.
10+
*
11+
* This library is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library; if not, write to the Free Software Foundation, Inc.,
18+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*/
20+
21+
#include "VectorField.h"
22+
23+
#include <brayns/engine/components/Geometries.h>
24+
#include <brayns/engine/components/GeometryViews.h>
25+
#include <brayns/engine/geometry/types/Capsule.h>
26+
#include <brayns/engine/systems/GenericBoundsSystem.h>
27+
#include <brayns/engine/systems/GeometryDataSystem.h>
28+
#include <ospray/ospray_cpp/ext/rkcommon.h>
29+
30+
#include <api/ModelType.h>
31+
#include <api/atlases/VectorAtlas.h>
32+
33+
#include <cassert>
34+
35+
namespace
36+
{
37+
float getAxisColor(float value)
38+
{
39+
return (value + 1.0F) / 2.0F;
40+
}
41+
42+
brayns::Vector4f getVectorColor(const brayns::Vector3f &vector)
43+
{
44+
return {
45+
getAxisColor(vector.x),
46+
getAxisColor(vector.y),
47+
getAxisColor(vector.z),
48+
1.0F,
49+
};
50+
}
51+
52+
std::vector<std::size_t> getNonEmptyVoxelIndices(const VectorAtlas &atlas)
53+
{
54+
auto indices = std::vector<std::size_t>();
55+
56+
auto itemCount = atlas.getVoxelCount();
57+
58+
for (auto i = std::size_t(0); i < itemCount; ++i)
59+
{
60+
if (atlas[i] != brayns::Vector3f())
61+
{
62+
indices.push_back(i);
63+
}
64+
}
65+
66+
return indices;
67+
}
68+
69+
struct ColoredCapsules
70+
{
71+
std::vector<brayns::Capsule> capsules;
72+
std::vector<brayns::Vector4f> colors;
73+
};
74+
75+
ColoredCapsules createVectorCapsules(const VectorAtlas &atlas)
76+
{
77+
auto indices = getNonEmptyVoxelIndices(atlas);
78+
auto indexCount = indices.size();
79+
80+
auto result = ColoredCapsules();
81+
result.capsules.resize(indexCount);
82+
result.colors.resize(indexCount);
83+
84+
#pragma omp parallel for
85+
for (auto i = std::size_t(0); i < indexCount; ++i)
86+
{
87+
auto index = indices[i];
88+
const auto &direction = atlas[index];
89+
90+
assert(direction != brayns::Vector3f());
91+
92+
auto bounds = atlas.getVoxelBounds(index);
93+
auto origin = bounds.center();
94+
95+
const auto &spacing = atlas.getSpacing();
96+
auto length = brayns::math::reduce_min(spacing) * 0.5F;
97+
98+
auto radius = 0.05F * length;
99+
100+
auto vector = direction * length;
101+
auto tip = origin + vector;
102+
103+
result.capsules[i] = brayns::CapsuleFactory::cone(origin, radius, tip, 0.0F);
104+
result.colors[i] = getVectorColor(direction);
105+
}
106+
107+
return result;
108+
}
109+
110+
void buildVectorModel(brayns::Model &model, ColoredCapsules capsules)
111+
{
112+
auto &components = model.getComponents();
113+
114+
auto &geometries = components.add<brayns::Geometries>();
115+
auto &geometry = geometries.elements.emplace_back(std::move(capsules.capsules));
116+
117+
auto &views = components.add<brayns::GeometryViews>();
118+
auto &view = views.elements.emplace_back(geometry);
119+
view.setColorPerPrimitive(ospray::cpp::CopiedData(capsules.colors));
120+
121+
auto &systems = model.getSystems();
122+
systems.setBoundsSystem<brayns::GenericBoundsSystem<brayns::Geometries>>();
123+
systems.setDataSystem<brayns::GeometryDataSystem>();
124+
}
125+
}
126+
127+
std::string VectorField::getName() const
128+
{
129+
return "Vector field";
130+
}
131+
132+
bool VectorField::isValidAtlas(const Atlas &atlas) const
133+
{
134+
return atlas.getVoxelType() == VoxelType::Vector;
135+
}
136+
137+
std::shared_ptr<brayns::Model> VectorField::run(const Atlas &atlas, const brayns::JsonValue &payload) const
138+
{
139+
(void)payload;
140+
141+
assert(dynamic_cast<const VectorAtlas *>(&atlas));
142+
const auto &vectorAtlas = static_cast<const VectorAtlas &>(atlas);
143+
144+
auto capsules = createVectorCapsules(vectorAtlas);
145+
146+
auto model = std::make_shared<brayns::Model>(ModelType::atlas);
147+
buildVectorModel(*model, std::move(capsules));
148+
149+
return model;
150+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* Copyright (c) 2015-2024, EPFL/Blue Brain Project
2+
* All rights reserved. Do not distribute without permission.
3+
* Responsible Author: Adrien Fleury <[email protected]>
4+
*
5+
* This file is part of Brayns <https://github.com/BlueBrain/Brayns>
6+
*
7+
* This library is free software; you can redistribute it and/or modify it under
8+
* the terms of the GNU Lesser General Public License version 3.0 as published
9+
* by the Free Software Foundation.
10+
*
11+
* This library is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13+
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14+
* details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this library; if not, write to the Free Software Foundation, Inc.,
18+
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19+
*/
20+
21+
#pragma once
22+
23+
#include <api/IUseCase.h>
24+
25+
class VectorField : public IUseCase
26+
{
27+
public:
28+
std::string getName() const override;
29+
bool isValidAtlas(const Atlas &atlas) const override;
30+
std::shared_ptr<brayns::Model> run(const Atlas &atlas, const brayns::JsonValue &payload) const override;
31+
};

plugins/AtlasExplorer/io/NRRDLoadeParameters.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ struct EnumReflector<VoxelType>
4040
{"scalar", VoxelType::Scalar},
4141
{"orientation", VoxelType::Orientation},
4242
{"flatmap", VoxelType::Flatmap},
43-
{"layer_distance", VoxelType::LayerDistance}};
43+
{"layer_distance", VoxelType::LayerDistance},
44+
{"vector", VoxelType::Vector},
45+
};
4446
}
4547
};
4648

python/brayns/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
AtlasOrientationField,
168168
AtlasShellOutline,
169169
AtlasUsecase,
170+
AtlasVectorField,
170171
BbpCells,
171172
BbpLoader,
172173
BbpReport,
@@ -251,6 +252,7 @@
251252
"AtlasOrientationField",
252253
"AtlasShellOutline",
253254
"AtlasUsecase",
255+
"AtlasVectorField",
254256
"Axis",
255257
"BbpCells",
256258
"BbpLoader",

0 commit comments

Comments
 (0)