Skip to content

Commit 47433bf

Browse files
committed
initial temportal support for mesh
1 parent a89c03e commit 47433bf

File tree

6 files changed

+57
-144
lines changed

6 files changed

+57
-144
lines changed

library/private/scene_impl.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,7 @@ class scene_impl : public scene
3434
scene& add(const std::filesystem::path& filePath) override;
3535
scene& add(const std::vector<std::filesystem::path>& filePath) override;
3636
scene& add(const std::vector<std::string>& filePathStrings) override;
37-
scene& add(const mesh_t& mesh) override;
38-
scene& add(const std::vector<mesh_t>& mesh, double timeStep) override;
37+
scene& add(const mesh_t& mesh, const double timeStamp = 0) override;
3938
scene& clear() override;
4039
int addLight(const light_state_t& lightState) const override;
4140
int getLightCount() const override;

library/public/scene.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,12 @@ class F3D_EXPORT scene
5555
virtual scene& add(const std::filesystem::path& filePath) = 0;
5656
virtual scene& add(const std::vector<std::filesystem::path>& filePath) = 0;
5757
virtual scene& add(const std::vector<std::string>& filePathStrings) = 0;
58-
virtual scene& add(const std::vector<mesh_t>& mesh, double timeStep) = 0;
5958
///@}
6059

6160
/**
6261
* Add and load provided mesh into the scene
6362
*/
64-
virtual scene& add(const mesh_t& mesh) = 0;
63+
virtual scene& add(const mesh_t& mesh, const double timeStamp = 0) = 0;
6564

6665
///@{
6766
/**

library/src/scene_impl.cxx

Lines changed: 14 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ scene& scene_impl::add(const std::vector<fs::path>& filePaths)
296296
}
297297

298298
//----------------------------------------------------------------------------
299-
scene& scene_impl::add(const mesh_t& mesh)
299+
scene& scene_impl::add(const mesh_t& mesh, const double timeStamp)
300300
{
301301
// sanity checks
302302
auto [valid, err] = mesh.isValid();
@@ -305,58 +305,25 @@ scene& scene_impl::add(const mesh_t& mesh)
305305
throw scene::load_failure_exception(err);
306306
}
307307

308-
vtkNew<vtkF3DMemoryMesh> vtkSource;
309-
vtkSource->SetPoints(mesh.points);
310-
vtkSource->SetNormals(mesh.normals);
311-
vtkSource->SetTCoords(mesh.texture_coordinates);
312-
vtkSource->SetFaces(mesh.face_sides, mesh.face_indices);
308+
// vtkSmartPointer<vtkF3DGenericImporter> importer =
309+
// vtkSmartPointer<vtkF3DGenericImporter>::New();
310+
// something like
311+
// const f3d::reader* reader = f3d::factory::instance()->getReader(filePath.string(),
312+
// forceReader);
313+
// vtkSmartPointer<vtkImporter> importer = reader->createSceneReader(filePath.string());
313314

314-
vtkSmartPointer<vtkF3DGenericImporter> importer = vtkSmartPointer<vtkF3DGenericImporter>::New();
315-
importer->SetInternalReader(vtkSource);
315+
vtkNew<vtkF3DMemoryMesh> memoryMesh = getMemoryMeshReader(); // or create if absent
316316

317317
log::debug("Loading 3D scene from memory");
318-
this->Internals->Load({ importer });
319-
return *this;
320-
}
321-
322-
//----------------------------------------------------------------------------
323-
scene& scene_impl::add(const std::vector<mesh_t>& meshes, double_t timeStep)
324-
{
325-
if (meshes.empty())
326-
{
327-
throw scene::load_failure_exception("No mesh provided for temporal scene");
328-
}
329-
330-
if (timeStep <= 0.0)
331-
{
332-
throw scene::load_failure_exception("Time step must be strictly positive");
333-
}
334318

335-
vtkNew<vtkF3DMemoryMesh> vtkSource;
336-
vtkSource->ReserveTemporalEntries(meshes.size());
319+
memoryMesh->SetPoints(mesh.points, timeStamp);
320+
memoryMesh->SetNormals(mesh.normals, timeStamp);
321+
memoryMesh->SetTCoords(mesh.texture_coordinates, timeStamp);
322+
memoryMesh->SetFaces(mesh.face_sides, mesh.face_indices, timeStamp);
337323

338-
for (size_t idx = 0; idx < meshes.size(); idx++)
339-
{
340-
auto [valid, err] = meshes[idx].isValid();
341-
if (!valid)
342-
{
343-
throw scene::load_failure_exception(err);
344-
}
324+
// Trigger update for temporal changes
325+
this->Internals->MetaImporter->Update();
345326

346-
vtkSource->SetPoints(meshes[idx].points, idx);
347-
vtkSource->SetNormals(meshes[idx].normals, idx);
348-
vtkSource->SetTCoords(meshes[idx].texture_coordinates, idx);
349-
vtkSource->SetFaces(meshes[idx].face_sides, meshes[idx].face_indices, idx);
350-
}
351-
vtkSource->SetTimeStep(timeStep);
352-
const double endTime = timeStep * static_cast<double>(meshes.size() - 1);
353-
vtkSource->SetTimeRange({ 0, endTime });
354-
355-
vtkSmartPointer<vtkF3DGenericImporter> importer = vtkSmartPointer<vtkF3DGenericImporter>::New();
356-
importer->SetInternalReader(vtkSource);
357-
358-
log::debug("Loading 3D scene from memory");
359-
this->Internals->Load({ importer });
360327
return *this;
361328
}
362329

@@ -368,7 +335,6 @@ scene& scene_impl::clear()
368335

369336
// Clear the window of all actors
370337
this->Internals->Window.Initialize();
371-
372338
return *this;
373339
}
374340

library/testing/TestSDKSceneTemporalFromMemory.cxx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
2323
std::string texturePath = std::string(argv[1]) + "data/world.png";
2424
eng.getOptions().model.color.texture = texturePath;
2525
const std::string outputPath = std::string(argv[2]);
26+
const std::string frame0Path = outputPath + "TestSDKSceneTemporalFromMemory_frame0.png";
27+
const std::string frame1Path = outputPath + "TestSDKSceneTemporalFromMemory_frame1.png";
2628

2729
const std::vector<float> basePoints{ 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 0.f };
2830
const std::vector<float> translatedPoints{ 0.25f, 0.f, 0.f, 0.25f, 1.f, 0.f, 1.25f, 0.f, 0.f,
@@ -36,8 +38,10 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
3638
f3d::mesh_t meshFrame0{ basePoints, normals, tcoords, faceSides, faceIndices };
3739
f3d::mesh_t meshFrame1{ translatedPoints, normals, tcoords, faceSides, faceIndices };
3840

39-
test("add temporal mesh sequence",
40-
[&]() { sce.add(std::vector<f3d::mesh_t>{ meshFrame0, meshFrame1 }, 1.0); });
41+
test("add temporal mesh sequence", [&]() {
42+
sce.add(meshFrame0, 0.0);
43+
sce.add(meshFrame1, 1.0);
44+
});
4145

4246
test("animation time range", [&]() {
4347
auto range = sce.animationTimeRange();
@@ -48,7 +52,7 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
4852
test("qualitative baseline comparison", [&]() {
4953
sce.loadAnimationTime(0.0);
5054
f3d::image frame0 = win.renderToImage();
51-
frame0.save(outputPath + "TestSDKSceneTemporalFromMemory_frame0.png");
55+
frame0.save(frame0Path);
5256
f3d::image baseline(baselinePath);
5357
double error = frame0.compare(baseline);
5458
if (error > 0.05)
@@ -62,10 +66,10 @@ int TestSDKSceneTemporalFromMemory([[maybe_unused]] int argc, [[maybe_unused]] c
6266
test("quantitative temporal difference", [&]() {
6367
sce.loadAnimationTime(0.0);
6468
f3d::image frame0 = win.renderToImage();
65-
frame0.save(outputPath + "TestSDKSceneTemporalFromMemory_frame0.png");
69+
frame0.save(frame0Path);
6670
sce.loadAnimationTime(1.0);
6771
f3d::image frame1 = win.renderToImage();
68-
frame1.save(outputPath + "TestSDKSceneTemporalFromMemory_frame1.png");
72+
frame1.save(frame1Path);
6973
double error = frame0.compare(frame1);
7074
if (error <= 0.01)
7175
{

vtkext/private/module/vtkF3DMemoryMesh.cxx

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include <vtkStreamingDemandDrivenPipeline.h>
1111

1212
#include <algorithm>
13-
#include <cmath>
1413

1514
vtkStandardNewMacro(vtkF3DMemoryMesh);
1615

@@ -41,40 +40,37 @@ vtkSmartPointer<vtkFloatArray> ConvertToFloatArray(const std::vector<float>& pos
4140
//------------------------------------------------------------------------------
4241
vtkF3DMemoryMesh::vtkF3DMemoryMesh()
4342
{
44-
Meshes = std::vector<vtkNew<vtkPolyData>>(1);
4543
this->SetNumberOfInputPorts(0);
46-
this->timeRange = { 0.0, 0.0 };
47-
this->timeStep = 1.0;
4844
}
4945

5046
//------------------------------------------------------------------------------
5147
vtkF3DMemoryMesh::~vtkF3DMemoryMesh() = default;
5248

5349
//------------------------------------------------------------------------------
54-
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions, size_t timeIdx)
50+
void vtkF3DMemoryMesh::SetPoints(const std::vector<float>& positions, const double timeStep)
5551
{
5652
vtkNew<vtkPoints> points;
5753
points->SetDataTypeToFloat();
5854
points->SetData(ConvertToFloatArray<3>(positions));
5955

60-
this->Meshes[timeIdx]->SetPoints(points);
56+
this->Meshes[timeStep]->SetPoints(points);
6157
}
6258

6359
//------------------------------------------------------------------------------
64-
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals, size_t timeIdx)
60+
void vtkF3DMemoryMesh::SetNormals(const std::vector<float>& normals, const double timeStamp)
6561
{
66-
this->Meshes[timeIdx]->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
62+
this->Meshes[timeStamp]->GetPointData()->SetNormals(ConvertToFloatArray<3>(normals));
6763
}
6864

6965
//------------------------------------------------------------------------------
70-
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords, size_t timeIdx)
66+
void vtkF3DMemoryMesh::SetTCoords(const std::vector<float>& tcoords, const double timeStamp)
7167
{
72-
this->Meshes[timeIdx]->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
68+
this->Meshes[timeStamp]->GetPointData()->SetTCoords(ConvertToFloatArray<2>(tcoords));
7369
}
7470

7571
//------------------------------------------------------------------------------
7672
void vtkF3DMemoryMesh::SetFaces(const std::vector<unsigned int>& faceSizes,
77-
const std::vector<unsigned int>& faceIndices, size_t timeIdx)
73+
const std::vector<unsigned int>& faceIndices, const double timeStamp)
7874
{
7975
vtkNew<vtkIdTypeArray> offsets;
8076
vtkNew<vtkIdTypeArray> connectivity;
@@ -102,44 +98,18 @@ void vtkF3DMemoryMesh::SetFaces(const std::vector<unsigned int>& faceSizes,
10298
vtkNew<vtkCellArray> polys;
10399
polys->SetData(offsets, connectivity);
104100

105-
this->Meshes[timeIdx]->SetPolys(polys);
106-
}
107-
108-
//------------------------------------------------------------------------------
109-
void vtkF3DMemoryMesh::SetTimeRange(std::pair<double, double> newTimeRange)
110-
{
111-
timeRange = newTimeRange;
112-
}
113-
114-
//------------------------------------------------------------------------------
115-
void vtkF3DMemoryMesh::SetTimeStep(double newTimeStep)
116-
{
117-
timeStep = newTimeStep;
118-
}
119-
120-
//------------------------------------------------------------------------------
121-
size_t vtkF3DMemoryMesh::GetTemporalStateCount()
122-
{
123-
return Meshes.size();
124-
}
125-
126-
//------------------------------------------------------------------------------
127-
void vtkF3DMemoryMesh::ReserveTemporalEntries(size_t newSize)
128-
{
129-
Meshes.resize(newSize);
101+
this->Meshes[timeStamp]->SetPolys(polys);
130102
}
131103

132104
//------------------------------------------------------------------------------
133105
int vtkF3DMemoryMesh::RequestInformation(vtkInformation* vtkNotUsed(request),
134106
vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* outputVector)
135107
{
136-
vtkInformation* outInfo = outputVector->GetInformationObject(0);
108+
// timeRange = {map_min, map_max}, map_min always <= map_max
109+
auto timeRange = std::array<double, 2>{ Meshes.begin()->first, Meshes.rbegin()->first };
137110

138-
if (timeRange.first < timeRange.second)
139-
{
140-
std::array<double, 2> arr = { timeRange.first, timeRange.second };
141-
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), arr.data(), 2);
142-
}
111+
vtkInformation* outInfo = outputVector->GetInformationObject(0);
112+
outInfo->Set(vtkStreamingDemandDrivenPipeline::TIME_RANGE(), timeRange.data(), 2);
143113

144114
return 1;
145115
}
@@ -152,21 +122,21 @@ int vtkF3DMemoryMesh::RequestData(vtkInformation* vtkNotUsed(request),
152122
vtkPolyData* output = vtkPolyData::GetData(outInfo);
153123

154124
double requestedTimeValue = 0.0;
155-
size_t timeIdx = 0;
156125

157-
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()) && this->timeStep > 0.0 &&
158-
!this->Meshes.empty())
126+
if (outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()) && !this->Meshes.empty())
159127
{
160128
requestedTimeValue = outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP());
161-
const double clampedTime =
162-
std::clamp(requestedTimeValue, this->timeRange.first, this->timeRange.second);
163-
const double relative = (clampedTime - this->timeRange.first) / this->timeStep;
164-
const double boundedRelative =
165-
std::clamp(relative, 0.0, static_cast<double>(std::max<size_t>(this->Meshes.size(), 1) - 1));
166-
timeIdx = static_cast<size_t>(std::llround(boundedRelative));
129+
auto iter = Meshes.upper_bound(requestedTimeValue);
130+
if (iter != Meshes.begin())
131+
{
132+
iter = std::prev(iter);
133+
}
134+
output->ShallowCopy(iter->second);
135+
}
136+
else
137+
{
138+
output->ShallowCopy(this->Meshes[0.0]);
167139
}
168-
169-
output->ShallowCopy(this->Meshes[timeIdx]);
170140

171141
return 1;
172142
}

vtkext/private/module/vtkF3DMemoryMesh.h

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,63 +18,40 @@ class vtkF3DMemoryMesh : public vtkPolyDataAlgorithm
1818
vtkTypeMacro(vtkF3DMemoryMesh, vtkPolyDataAlgorithm);
1919

2020
/**
21-
* Set contiguous list of positions.
21+
* Set contiguous list of positions for a given timestamp, 0 by default.
2222
* Length of the list must be a multiple of 3.
2323
* The list is copied internally.
2424
*/
25-
void SetPoints(const std::vector<float>& positions, size_t timeIdx = 0);
25+
void SetPoints(const std::vector<float>& positions, const double timeStamp = 0);
2626

2727
/**
28-
* Set contiguous list of normals.
28+
* Set contiguous list of normals for a given timestamp, 0 by default.
2929
* Length of the list must be a multiple of 3 (or left empty).
3030
* Must match the number of points specified in SetPoints.
3131
* The list is copied internally.
3232
* The list can be empty.
3333
*/
34-
void SetNormals(const std::vector<float>& normals, size_t timeIdx = 0);
34+
void SetNormals(const std::vector<float>& normals, const double timeStamp = 0);
3535

3636
/**
37-
* Set contiguous list of texture coordinates.
37+
* Set contiguous list of texture coordinates for a given timestamp, 0 by default.
3838
* Length of the list must be a multiple of 2 (or left empty).
3939
* Must match the number of points specified in SetPoints.
4040
* The list is copied internally.
4141
* The list can be empty.
4242
*/
43-
void SetTCoords(const std::vector<float>& tcoords, size_t timeIdx = 0);
43+
void SetTCoords(const std::vector<float>& tcoords, const double timeStamp = 0);
4444

4545
/**
46-
* Set faces by vertex indices.
46+
* Set faces by vertex indices for a given timestamp, 0 by default.
4747
* faceSizes contains the size of each face (3 is triangle, 4 is quad, etc...)
4848
* cellIndices is a contiguous array of all face indices
4949
* The length of faceIndices should be the sum of all values in faceSizes
5050
* The lists are copied internally.
5151
* The lists can be empty, resulting in a point cloud.
5252
*/
5353
void SetFaces(const std::vector<unsigned int>& faceSizes,
54-
const std::vector<unsigned int>& faceIndices, size_t timeIdx = 0);
55-
56-
/**
57-
* Set time range in seconds for the saved frames, [0,0] by default, no animation.
58-
*/
59-
void SetTimeRange(std::pair<double, double> newTimeRange);
60-
61-
/**
62-
* Set time step in seconds for the saved frames, 1 by default.
63-
*/
64-
void SetTimeStep(double newTimeStep);
65-
66-
/** Get number of animation frames.ß
67-
* result * timeStep is a total animation length in seconds.
68-
*/
69-
size_t GetTemporalStateCount();
70-
71-
/**
72-
* Resize underlying vector to store temporal sequence.
73-
* By default vector is of size one and acts like mesh without animation, it's a must to resize
74-
* the vector for animation sequence. newSize is the resulting size of the resised vector, in
75-
* other words number of animation frames.
76-
*/
77-
void ReserveTemporalEntries(size_t newSize);
54+
const std::vector<unsigned int>& faceIndices, const double timeStamp = 0);
7855

7956
protected:
8057
vtkF3DMemoryMesh();
@@ -87,9 +64,7 @@ class vtkF3DMemoryMesh : public vtkPolyDataAlgorithm
8764
vtkF3DMemoryMesh(const vtkF3DMemoryMesh&) = delete;
8865
void operator=(const vtkF3DMemoryMesh&) = delete;
8966

90-
std::vector<vtkNew<vtkPolyData>> Meshes;
91-
std::pair<double, double> timeRange;
92-
double timeStep;
67+
std::map<double, vtkNew<vtkPolyData>> Meshes;
9368
};
9469

9570
#endif

0 commit comments

Comments
 (0)