Commit 446c5edc authored by Sreekanth Arikatla's avatar Sreekanth Arikatla

Merge branch 'EnhanceTextStatus' into 'master'

Enhance text status and allow to change debug geometry at run time

See merge request !337
parents e48e52a3 369159b5
Pipeline #141212 passed with stage
in 0 seconds
......@@ -20,81 +20,169 @@
=========================================================================*/
#include "imstkSimulationManager.h"
#include "imstkTetrahedralMesh.h"
#include "imstkMeshIO.h"
#include "imstkSceneObject.h"
#include "imstkDebugGeometry.h"
#include "imstkAPIUtilities.h"
#include "imstkSurfaceMesh.h"
#include <memory>
#include "imstkVTKViewer.h"
#include "imstkVTKTextStatusManager.h"
#include <thread>
#include <chrono>
using namespace imstk;
///
/// \brief This example demonstrates the debug rendering
///
int main()
std::shared_ptr<DebugRenderGeometry>
addPointsDebugRendering(const std::shared_ptr<Scene>& scene)
{
auto sdk = std::make_shared<SimulationManager>();
auto scene = sdk->createNewScene("DebugRendering");
scene->getCamera()->setPosition(0, 2.0, 15.0);
auto debugPoints = std::make_shared<DebugRenderPoints>("Debug Points");
auto material = std::make_shared<RenderMaterial>();
material->setDebugColor(Color::Blue);
debugPoints->setRenderMaterial(material);
scene->addDebugGeometry(debugPoints);
// Create debug triangles
auto debugTriangleGeo = std::make_shared<DebugRenderTriangles>("debugtriangles", 9);
StdVectorOfVec3d triVerts;
triVerts.push_back(Vec3d(0., 0., 0.));
triVerts.push_back(Vec3d(0., 10., 0.));
triVerts.push_back(Vec3d(0., 0., 10.));
triVerts.push_back(Vec3d(0., 0., 0.));
triVerts.push_back(Vec3d(10., 0., 0.));
triVerts.push_back(Vec3d(0., 0., 10.));
return std::dynamic_pointer_cast<DebugRenderGeometry>(debugPoints);
}
triVerts.push_back(Vec3d(0., 0., 0.));
triVerts.push_back(Vec3d(10., 0., 0.));
triVerts.push_back(Vec3d(0., 10., 0.));
std::shared_ptr<DebugRenderGeometry>
addLinesDebugRendering(const std::shared_ptr<Scene>& scene)
{
auto debugLines = std::make_shared<DebugRenderLines>("Debug Lines");
auto material = std::make_shared<RenderMaterial>();
material->setBackFaceCulling(false);
material->setDebugColor(Color::Green);
material->setLineWidth(2.0);
debugLines->setRenderMaterial(material);
scene->addDebugGeometry(debugLines);
debugTriangleGeo->setVertexData(triVerts);
return std::dynamic_pointer_cast<DebugRenderGeometry>(debugLines);
}
auto material = std::make_shared<RenderMaterial>();
std::shared_ptr<DebugRenderGeometry>
addTrianglesDebugRendering(const std::shared_ptr<Scene>& scene)
{
auto debugTriangles = std::make_shared<DebugRenderTriangles>("Debug Triangles");
auto material = std::make_shared<RenderMaterial>();
material->setBackFaceCulling(false);
material->setDebugColor(Color::Red);
material->setDisplayMode(RenderMaterial::DisplayMode::WIREFRAME_SURFACE);
debugTriangleGeo->setRenderMaterial(material);
scene->addDebugGeometry(debugTriangleGeo);
// Create debug Lines
auto debugLinesGeo = std::make_shared<DebugRenderLines>("debugLines");
StdVectorOfVec3d linesVerts;
linesVerts.push_back(Vec3d(15, 0, 0));
linesVerts.push_back(Vec3d(100, 0, 0));
debugTriangles->setRenderMaterial(material);
scene->addDebugGeometry(debugTriangles);
linesVerts.push_back(Vec3d(0, 15, 0));
linesVerts.push_back(Vec3d(0, 100, 0));
linesVerts.push_back(Vec3d(0, 0, 15));
linesVerts.push_back(Vec3d(0, 0, 100));
debugLinesGeo->setVertexData(linesVerts);
auto materialLines = std::make_shared<RenderMaterial>();
materialLines->setBackFaceCulling(false);
materialLines->setDebugColor(Color::Green);
materialLines->setLineWidth(2.0);
debugLinesGeo->setRenderMaterial(materialLines);
scene->addDebugGeometry(debugLinesGeo);
return std::dynamic_pointer_cast<DebugRenderGeometry>(debugTriangles);
}
// Add light
auto light = std::make_shared<DirectionalLight>("light");
light->setFocalPoint(Vec3d(5, -8, -5));
light->setIntensity(1);
scene->addLight(light);
Vec3d
getRandomPositions(double radius)
{
return radius * Vec3d(2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0,
2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0,
2.0 * static_cast<double>(rand()) / static_cast<double>(RAND_MAX) - 1.0);
}
// Run the simulation
///
/// \brief This example demonstrates debug rendering in iMSTK
///
int
main()
{
// SDK and Scene
auto sdk = std::make_shared<SimulationManager>();
auto scene = sdk->createNewScene("Debug rendering example");
sdk->setActiveScene(scene);
sdk->startSimulation(SimulationStatus::PAUSED);
// Get the VTKViewer
auto viewer = std::dynamic_pointer_cast<VTKViewer>(sdk->getViewer());
viewer->getVtkRenderWindow()->SetSize(1920, 1080);
auto statusManager = viewer->getTextStatusManager();
statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Orange);
// Get VTK Renderer
auto renderer = std::dynamic_pointer_cast<VTKRenderer>(viewer->getActiveRenderer());
LOG_IF(FATAL, (!renderer)) << "Invalid renderer: Only VTKRenderer is supported for debug rendering";
auto debugPoints = addPointsDebugRendering(scene);
auto debugLines = addLinesDebugRendering(scene);
auto debugTriangles = addTrianglesDebugRendering(scene);
int mode = 0; // 0: add point, 1: add line, 2: add triangle
int count = 0; // The number of times cycling between modes
auto updateFunc =
[&](Module*) {
if (count > 5)
{
count = 0;
debugPoints->clear();
debugLines->clear();
debugTriangles->clear();
}
if (mode % 3 == 0)
{
debugPoints->appendVertex(getRandomPositions(15.0));
}
else if (mode % 3 == 1)
{
auto p = getRandomPositions(50.0);
auto shift = getRandomPositions(1.0);
debugLines->appendVertex(p + shift);
debugLines->appendVertex(-p + shift);
}
else
{
auto shift = getRandomPositions(10.0);
debugTriangles->appendVertex(getRandomPositions(5.0) + shift);
debugTriangles->appendVertex(getRandomPositions(5.0) + shift);
debugTriangles->appendVertex(getRandomPositions(5.0) + shift);
mode = -1;
++count;
}
++mode;
debugPoints->turnDataModifiedFlagON();
debugLines->turnDataModifiedFlagON();
debugTriangles->turnDataModifiedFlagON();
// Must call to update render data
for (auto& delegate : renderer->getDebugRenderDelegates())
{
delegate->updateDataSource();
}
statusManager->setCustomStatus("Primatives: " +
std::to_string(debugPoints->getNumVertices()) + " (points) | " +
std::to_string(debugLines->getNumVertices() / 2) + " (lines) | " +
std::to_string(debugTriangles->getNumVertices() / 3) + " (triangles)"
);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
};
sdk->getSceneManager(scene)->setPostUpdateCallback(updateFunc);
// Set Camera configuration
auto cam = scene->getCamera();
cam->setPosition(Vec3d(0, 0, 50));
cam->setFocalPoint(Vec3d(0, 0, 0));
// Light
{
auto light = std::make_shared<DirectionalLight>("Light 1");
light->setFocalPoint(Vec3d(-1, -1, -1));
light->setIntensity(1);
scene->addLight(light);
}
{
auto light = std::make_shared<DirectionalLight>("Light 2");
light->setFocalPoint(Vec3d(1, -1, -1));
light->setIntensity(1);
scene->addLight(light);
}
// Run
sdk->startSimulation(SimulationStatus::RUNNING);
return 0;
}
......@@ -26,6 +26,7 @@
#include "imstkAPIUtilities.h"
#include "imstkPlane.h"
#include "imstkSphere.h"
#include "imstkVTKTextStatusManager.h"
#include "Fluid.hpp"
#include "Solid.hpp"
......@@ -36,25 +37,26 @@ using namespace imstk;
/// \brief Usage: ./SPHFluid [threads=<num_threads>] [radius=<particle_radius>]
/// \brief Example: ./SPHFluid threads=8 radius=0.01
///
int main(int argc, char* argv[])
int
main(int argc, char* argv[])
{
// SimulationManager must be created first
auto sdk = std::make_shared<SimulationManager>();
int threads = -1;
int threads = -1;
double particleRadius = 0.1;
// Parse command line arguments
for (int i = 1; i < argc; ++i)
{
auto param = std::string(argv[i]);
if (param.find("threads") == 0 &&
param.find_first_of("=") != std::string::npos)
if (param.find("threads") == 0
&& param.find_first_of("=") != std::string::npos)
{
threads = std::stoi(param.substr(param.find_first_of("=") + 1));
}
else if (param.find("radius") == 0 &&
param.find_first_of("=") != std::string::npos)
else if (param.find("radius") == 0
&& param.find_first_of("=") != std::string::npos)
{
particleRadius = std::stod(param.substr(param.find_first_of("=") + 1));
LOG(INFO) << "Particle radius: " << particleRadius;
......@@ -76,9 +78,23 @@ int main(int argc, char* argv[])
auto scene = sdk->createNewScene("SPH Fluid");
// Get the VTKViewer
auto viewer = std::dynamic_pointer_cast<VTKViewer>(sdk->getViewer());
viewer->getVtkRenderWindow()->SetSize(1920, 1080);
auto statusManager = viewer->getTextStatusManager();
statusManager->setStatusFontSize(VTKTextStatusManager::Custom, 30);
statusManager->setStatusFontColor(VTKTextStatusManager::Custom, Color::Red);
// Generate fluid and solid objects
auto fluidObj = generateFluid(scene, particleRadius);
auto solids = generateSolids(scene);
auto solids = generateSolids(scene);
sdk->getSceneManager(scene)->setPostUpdateCallback([&](Module*) {
statusManager->setCustomStatus("Number of particles: " +
std::to_string(fluidObj->getSPHModel()->getState().getNumParticles()) +
"\nNumber of solids: " + std::to_string(solids.size()));
});
// Collision between fluid and solid objects
auto colGraph = scene->getCollisionGraph();
......
......@@ -21,40 +21,35 @@
#include "imstkDebugGeometry.h"
void
imstk::DebugRenderGeometry::setRenderMaterial(std::shared_ptr<RenderMaterial> renderMat)
namespace imstk
{
m_renderMaterial = renderMat;
}
std::shared_ptr<imstk::RenderMaterial>
imstk::DebugRenderGeometry::getRenderMaterial() const
const Vec3d&
DebugRenderGeometry::getVertex(const size_t idx) const
{
return m_renderMaterial;
#if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
LOG_IF(FATAL, (idx >= getNumVertices())) << "Invalid index";
#endif
return m_VertexBuffer[idx];
}
void
imstk::DebugRenderGeometry::clear()
DebugRenderGeometry::setVertex(const size_t idx, const Vec3d& vert)
{
std::fill(m_vertices.begin(), m_vertices.end(), Vec3d(0., 0., 0.));
m_dataSize = 0;
#if defined(DEBUG) || defined(_DEBUG) || !defined(NDEBUG)
LOG_IF(FATAL, (idx >= getNumVertices())) << "Invalid index";
#endif
m_VertexBuffer[idx] = vert;
}
void
imstk::DebugRenderGeometry::setVertexData(const StdVectorOfVec3d& verts)
DebugRenderGeometry::setRenderMaterial(const std::shared_ptr<RenderMaterial>& renderMat)
{
if (verts.size() > m_vertices.size())
{
LOG(WARNING) << "The size of the vertices supplied is larger than the base size";
}
for (unsigned int i = 0; i < verts.size(); ++i)
{
m_vertices[i] = verts[i];
}
m_dataSize = verts.size();
//std::fill(m_vertices.begin() + verts.size(), m_vertices.end(), Vec3d(0., 0., 0.));
m_renderMaterial = renderMat;
}
m_isModified = true;
const std::shared_ptr<imstk::RenderMaterial>&
DebugRenderGeometry::getRenderMaterial() const
{
return m_renderMaterial;
}
} // end namespace imstk
......@@ -30,7 +30,10 @@ namespace imstk
///
/// \class imstkDbgRenderGeometry
///
/// \brief debug render geometry base class
/// \brief Debug render geometry base class
/// During rendering, firstly call to clear() to clear the vertex buffer then iteratively call to appendVertex()
/// Another way to modify rendering data is to call resizeBuffer(), then fill data by calling to setVertex() function
/// In both ways, after finishing data modification, triggerDataModified() must be called to notify the render backend
///
class DebugRenderGeometry
{
......@@ -47,42 +50,71 @@ public:
};
///
/// \brief Clear the memory and set the count to zero
/// \brief Clear the vertex buffer
///
void clear();
void clear() { resizeBuffer(0); }
///
/// \brief Returns the vertex positions that are used for debug line rendering
/// \brief Reserve memory for fast push_back
///
const StdVectorOfVec3d& getVertexPositions() { return m_vertices; };
StdVectorOfVec3d& getVertexPositionsNonConst() { return m_vertices; };
virtual void reserve(const size_t size) { m_VertexBuffer.reserve(size); }
///
/// \brief Set the vertex data
/// \brief Returns the vertex position buffer that is used for debug rendering
///
void setVertexData(const StdVectorOfVec3d& verts);
const StdVectorOfVec3d& getVertexBuffer() const { return m_VertexBuffer; }
double* getVertexBufferPtr() { return reinterpret_cast<double*>(m_VertexBuffer.data()); }
const double* getVertexBufferPtr() const { return reinterpret_cast<const double*>(m_VertexBuffer.data()); }
///
/// \brief Get the name
/// \brief Returns the number of the vertices in the buffer
///
const std::string& getName() const { return m_name; };
size_t getNumVertices() const { return m_VertexBuffer.size(); }
///
/// \brief Get type
/// \brief Resize the vertex buffer
///
const Type& getType() const { return m_type; };
void resizeBuffer(const size_t newSize) { m_VertexBuffer.resize(newSize); }
///
/// \brief
/// \brief Return the vertex at the given idx
///
bool isModified() { return m_isModified; }
void setDataModifiedFlag(const bool flag) { m_isModified = flag; };
const Vec3d& getVertex(const size_t idx) const;
///
/// \brief Set the vertex at index idx
///
void setVertex(const size_t idx, const Vec3d& vert);
///
/// \brief Append a vertex
///
void appendVertex(const Vec3d& vert) { m_VertexBuffer.push_back(vert); }
///
/// \brief Get the name of debug geometry
///
const std::string& getName() const { return m_name; }
///
/// \brief Get rendering geometry type
///
const Type& getType() const { return m_type; }
///
/// \brief Return m_isModified flag, used to communicate with the render engine
/// For performance reason, the only way to change this flag is to manually call to turnDataModifiedFlagON() or turnDataModifiedFlagOFF
/// Thus, we must call turnDataModifiedFlagON() explicity after finished data manipulation
///
bool isModified() const { return m_isModified; }
void turnDataModifiedFlagON() { m_isModified = true; }
void turnDataModifiedFlagOFF() { m_isModified = false; }
///
/// \brief Set/Get render material
///
void setRenderMaterial(std::shared_ptr<RenderMaterial> renderMat);
std::shared_ptr<RenderMaterial> getRenderMaterial() const;
void setRenderMaterial(const std::shared_ptr<RenderMaterial>& renderMat);
const std::shared_ptr<RenderMaterial>& getRenderMaterial() const;
protected:
friend class VTKRenderer;
......@@ -91,48 +123,38 @@ protected:
///
/// \brief Constructor
///
DebugRenderGeometry(const std::string& name, Type type, const unsigned int size = 300) :
m_name(name), m_type(type), m_dataSize(size)
DebugRenderGeometry(const std::string& name, const Type type) :
m_name(name), m_type(type), m_renderMaterial(std::make_shared<RenderMaterial>())
{
allocate(size);
m_renderMaterial = std::make_shared<RenderMaterial>();
}
///
/// \brief Preallocate a fixed size for the debug rendering data
///
virtual void allocate(const unsigned int size)
{
m_vertices.resize(size);
};
virtual ~DebugRenderGeometry() = default;
Type m_type; ///> Debug geometry type
StdVectorOfVec3d m_vertices; ///> Vertex data
size_t m_dataSize = 0; ///> Count for data size
std::string m_name; ///> Custom name of the scene object
Type m_type; ///> Debug geometry type
StdVectorOfVec3d m_VertexBuffer; ///> Vertex buffer
std::string m_name; ///> Custom name of the scene object
bool m_renderDelegateCreated = false;
bool m_renderDelegateCreated = false; ///> This variable is used in Renderer
bool m_isModified = false;
std::shared_ptr<RenderMaterial> m_renderMaterial = nullptr; ///> Render material
std::shared_ptr<RenderMaterial> m_renderMaterial = nullptr;
};
///
/// \class imstkDbgRenderPoints
/// \class DebugRenderPoints
///
/// \brief debug points to render
/// \brief Debug points to render
///
class DebugRenderPoints : public DebugRenderGeometry
{
public:
///
/// \brief Constructor/destructor
/// \brief Constructor
///
DebugRenderPoints(const std::string& name, const unsigned int size) : DebugRenderGeometry(name, Type::Points, size){}
DebugRenderPoints(const std::string& name) : DebugRenderGeometry(name, Type::Points) {}
};
///
/// \class DbgRenderLines
/// \class DebugRenderLines
///
/// \brief List of disjoint lines to render
///
......@@ -140,38 +162,32 @@ class DebugRenderLines : public DebugRenderGeometry
{
public:
///
/// \brief Constructor/destructor
/// \brief Constructor
///
DebugRenderLines(const std::string& name) : DebugRenderGeometry(name, Type::Lines) {}
///
/// \brief Reserve memory for fast push_back
///
DebugRenderLines(const std::string& name, const unsigned int size = 300) : DebugRenderGeometry(name, Type::Lines, size){}
virtual void reserve(const size_t size) override { m_VertexBuffer.reserve(size * 2); }
};
///
/// \class imstkDbgRenderTriangles
/// \class DebugRenderTriangles
///
/// \brief debug triangles to render
/// \brief Debug triangles to render
///
class DebugRenderTriangles : public DebugRenderGeometry
{
public:
///
/// \brief Constructor/destructor
/// \brief Constructor
///
DebugRenderTriangles(const std::string& name, const unsigned int size = 3*100) : DebugRenderGeometry(name, Type::Triangles, size){}
DebugRenderTriangles(const std::string& name) : DebugRenderGeometry(name, Type::Triangles) {}
protected:
///
/// \brief Preallocate a fixed size for the debug rendering data
/// \brief Reserve memory for fast push_back
///
void allocate(const unsigned int size) override
{
if (size % 3 == 0)
{
m_vertices.reserve(size);
}
else
{
LOG(WARNING) << "WARNING: The size of the triangle array should be multiples of three!";
}
}
virtual void reserve(const size_t size) override { m_VertexBuffer.reserve(size * 3); }
};
}
......@@ -112,6 +112,8 @@ protected:
m_actor->SetUserTransform(m_transform);
}
virtual ~VTKRenderDelegate() = default;
std::shared_ptr<VisualModel> m_visualModel;
vtkSmartPointer<vtkActor> m_actor;
vtkSmartPointer<VTKCustomPolyDataMapper> m_mapper;
......
/*=========================================================================
Library: iMSTK
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "imstkVTKdebugLinesRenderDelegate.h"
#include "imstkSurfaceMesh.h"
#include <vtkPolyData.h>
......@@ -37,55 +36,70 @@ limitations under the License.
namespace imstk
{
VTKdbgLinesRenderDelegate::VTKdbgLinesRenderDelegate(std::shared_ptr<DebugRenderLines> renderLines) :
m_Lines(renderLines),
VTKdbgLinesRenderDelegate::VTKdbgLinesRenderDelegate(const std::shared_ptr<DebugRenderLines>& lineData) :
m_RenderGeoData(lineData),
m_mappedVertexArray(vtkSmartPointer<vtkDoubleArray>::New())
{
// Map vertices
StdVectorOfVec3d& triVertData = renderLines->getVertexPositionsNonConst();
m_mappedVertexArray->SetNumberOfComponents(3);
double* vertData = reinterpret_cast<double*>(triVertData.data());
m_mappedVertexArray->SetArray(vertData, triVertData.size() * 3, 1);
// Create lines polydata
auto linesPolyData = vtkSmartPointer<vtkPolyData>::New();
// Create points
auto points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(triVertData.size());
points->SetData(m_mappedVertexArray);
linesPolyData->SetPoints(points);
m_points = vtkSmartPointer<vtkPoints>::New();
m_points->SetData(m_mappedVertexArray);
// Create cells
auto lines = vtkSmartPointer<vtkCellArray>::New();
for (unsigned int i = 0; i < triVertData.size() - 1; i += 2)
{
auto l = vtkSmartPointer<vtkLine>::New();
l->GetPointIds()->SetId(0, i);
l->GetPointIds()->SetId(1, i + 1);
m_cellArray = vtkSmartPointer<vtkCellArray>::New();
lines->InsertNextCell(l);
}
linesPolyData->SetLines(lines);
// Create lines polydata
m_polyData = vtkSmartPointer<vtkPolyData>::New();
m_polyData->SetPoints(m_points);
m_polyData->SetLines(m_cellArray);
// Create connection source
auto source = vtkSmartPointer<vtkTrivialProducer>::New();
source->SetOutput(linesPolyData);
m_Lines->setDataModifiedFlag(false);
source->SetOutput(m_polyData);
// Update Transform, Render Properties
this->updateDataSource();
this->updateActorProperties();
updateActorProperties();
setUpMapper(source->GetOutputPort(), false, m_RenderGeoData->getRenderMaterial());
this->setUpMapper(source->GetOutputPort(), false, m_Lines->getRenderMaterial());
updateDataSource();