Commit 080d795f authored by Alexis Girault's avatar Alexis Girault

Merge branch 'refactor-controllers' into 'master'

Refactor controllers

This MR aims to refactor the VirtualCouplingObject class into a SceneObjectController, as well as correct some style and architecture issues.

### STYLE: correct identation 97fc549f
Convert tabs to 4 spaces

### ENH: simplify TrackingController constructor fbc48bae
- Get rid of scaling in constructor (too many parameters, why choose scaling and not others? Use `setTranslationScaling` instead) 
- No more default `nullptr` value for `DeviceClient` in controller constructor

### ENH: Implement getMasterGeometry 85470771
Returns the master geometry. A geometry is qualified master by the direction of the geometry maps of the object. For example with a dynamic object, physic geometry will drive the changes to the colliding geometry, which will drive the changes to the visual geometry...

### ENH: Divide SceneObject & CollidingObject d8fee1f4 (fixes #84)
Colliding geometry is only in `CollidingObject, not `SceneObject`.  To do this, we also had to :
- Have `PbdObject` inherit `CollidingObject` *(in the future there should not be a distinct object class just for Pbd : there should just be dynamical objects that can use different models, like Pbd or FEM)*
- Remove useless checks when creating interactions: even two colliding objects (not dynamic, aka static) could be interacting if they are both controlled by devices

### STYLE: correct some includes and forward declarations 0340bde7

### ENH: remove interface for transforming geometry in RigidObject 7c272963
We are still wondering how to store/apply our geometries. Having yet another interface to only wrap the API to transform the geometry is not needed: we can directly call them on the geometry themselves for more transparency on what geometry is being updated. *This should be investigated later on when we will work with rigid body dynamics.*

### ENH: Refactor VirtualCouplingObject in a controller  (fixes #99)
- `SceneObjectController`: similar to cameraController, it subclasses trackingController to update the transformation of an object master geometry, instead of updating itself. 
- `SceneObject`: similar to camera, has an interface to easily setup a controller using a device client. 
- `CollidingObject`: stores the force vector that needs to be applied to the device.
- `SceneManager`: make the API calls from controller instead of object

### STYLE: Rename cameraController attribute to controller 9e199a30

See merge request !102
parents 4821c848 9e199a30
......@@ -38,11 +38,10 @@ CollisionHandling::make_collision_handling(const Type& type,
{
case Type::Penalty:
{
if (objA->getType() != SceneObject::Type::VirtualCoupling &&
objA->getType() == SceneObject::Type::Rigid)
if (objA->getType() == SceneObject::Type::Visual)
{
LOG(WARNING) << "CollisionHandling::make_collision_handling error: "
<< "penalty collision handling not yet implemented for non-rigid objects.";
<< "penalty collision handling only implemented for colliding objects.";
return nullptr;
}
return std::make_shared<PenaltyRigidCH>(side, colData, objA);
......
......@@ -22,7 +22,6 @@
#include "imstkPenaltyMeshToRigidCH.h"
#include "imstkCollidingObject.h"
#include "imstkVirtualCouplingObject.h"
#include "imstkCollisionData.h"
#include "imstkDeformableObject.h"
......
......@@ -22,7 +22,6 @@
#include "imstkPenaltyRigidCH.h"
#include "imstkCollidingObject.h"
#include "imstkVirtualCouplingObject.h"
#include "imstkCollisionData.h"
#include <g3log/g3log.hpp>
......@@ -32,7 +31,7 @@ namespace imstk {
void
PenaltyRigidCH::computeContactForces()
{
auto movableObj = std::dynamic_pointer_cast<VirtualCouplingObject>(m_obj);
auto movableObj = std::dynamic_pointer_cast<CollidingObject>(m_obj);
if(movableObj == nullptr)
{
LOG(WARNING) << "PenaltyRigidCH::computeContactForces error: "
......
......@@ -47,14 +47,6 @@ InteractionPair::InteractionPair(std::shared_ptr<CollidingObject> A,
return;
}
// Check that at least one object is not static
if (A->getType() == SceneObject::Type::Static &&
B->getType() == SceneObject::Type::Static)
{
LOG(WARNING) << "InteractionPair error: can not create interaction between two static objects.";
//return;
}
// Collision Detection
std::shared_ptr<CollisionDetection> CD = CollisionDetection::make_collision_detection(CDType, A, B, m_colData);
if (CD == nullptr)
......@@ -65,28 +57,28 @@ InteractionPair::InteractionPair(std::shared_ptr<CollidingObject> A,
// Collision Handling A
std::shared_ptr<CollisionHandling> CHA;
if (A->getType() != SceneObject::Type::Static)
if(CHAType != CollisionHandling::Type::None)
{
CHA = CollisionHandling::make_collision_handling(CHAType, CollisionHandling::Side::A, m_colData, A, B);
if (CHA == nullptr)
{
LOG(WARNING) << "InteractionPair error: can not instantiate collision handling for '"
CHA = CollisionHandling::make_collision_handling(CHAType, CollisionHandling::Side::A, m_colData, A, B);
if (CHA == nullptr)
{
LOG(WARNING) << "InteractionPair error: can not instantiate collision handling for '"
<< A->getName() << "' object.";
return;
}
return;
}
}
// Collision Handling B
std::shared_ptr<CollisionHandling> CHB;
if (B->getType() != SceneObject::Type::Static)
if(CHBType != CollisionHandling::Type::None)
{
CHB = CollisionHandling::make_collision_handling(CHBType, CollisionHandling::Side::B, m_colData, B, A);
if (CHB == nullptr)
{
LOG(WARNING) << "InteractionPair error: can not instantiate collision handling for '"
CHB = CollisionHandling::make_collision_handling(CHBType, CollisionHandling::Side::B, m_colData, B, A);
if (CHB == nullptr)
{
LOG(WARNING) << "InteractionPair error: can not instantiate collision handling for '"
<< B->getName() << "' object.";
return;
}
return;
}
}
// Init interactionPair
......
This diff is collapsed.
......@@ -20,11 +20,9 @@ public:
///
/// \brief Constructor
///
PbdInteractionPair(std::shared_ptr<PbdObject> A, std::shared_ptr<PbdObject> B)
: first (A), second (B)
{
}
PbdInteractionPair(std::shared_ptr<PbdObject> A, std::shared_ptr<PbdObject> B):
first(A), second(B)
{}
///
/// \brief
......@@ -58,7 +56,7 @@ public:
void doCollision();
private:
std::vector<CollisionConstraint*> m_collisionConstraints;
std::vector<CollisionConstraint*> m_collisionConstraints;
std::shared_ptr<PbdObject> first;
std::shared_ptr<PbdObject> second;
unsigned int maxIter;
......@@ -66,4 +64,4 @@ private:
}
#endif // IMSTKPBDINTERACTIONPAIR_H
\ No newline at end of file
#endif // IMSTKPBDINTERACTIONPAIR_H
......@@ -16,7 +16,6 @@ EdgeEdgeConstraint::initConstraint( PositionBasedModel* model1, const unsigned i
m_bodiesFirst[1] = pIdx2;
m_bodiesSecond[0] = pIdx3;
m_bodiesSecond[1] = pIdx4;
}
bool
......@@ -117,8 +116,8 @@ EdgeEdgeConstraint::solvePositionConstraint()
void
PointTriangleConstraint::initConstraint(PositionBasedModel* model1, const unsigned int &pIdx1,
PositionBasedModel* model2, const unsigned int &pIdx2,
const unsigned int &pIdx3, const unsigned int &pIdx4)
PositionBasedModel* model2, const unsigned int &pIdx2,
const unsigned int &pIdx3, const unsigned int &pIdx4)
{
m_model1 = model1;
m_model2 = model2;
......@@ -214,4 +213,4 @@ PointTriangleConstraint::solvePositionConstraint()
return true;
}
} // imstk
\ No newline at end of file
} // imstk
......@@ -58,6 +58,7 @@ FEMTetConstraint::initConstraint (PositionBasedModel &model,
m_invRestMat = m.inverse();
return true;
}
return false;
}
......@@ -101,12 +102,12 @@ FEMTetConstraint::solvePositionConstraint(PositionBasedModel &model)
case MaterialType::StVK :
{
Mat3d E;
E(0, 0) = 0.5*(F(0, 0) * F(0, 0) + F(1, 0) * F(1, 0) + F(2, 0) * F(2, 0) - 1.0); // xx
E(1, 1) = 0.5*(F(0, 1) * F(0, 1) + F(1, 1) * F(1, 1) + F(2, 1) * F(2, 1) - 1.0); // yy
E(2, 2) = 0.5*(F(0, 2) * F(0, 2) + F(1, 2) * F(1, 2) + F(2, 2) * F(2, 2) - 1.0); // zz
E(0, 1) = 0.5*(F(0, 0) * F(0, 1) + F(1, 0) * F(1, 1) + F(2, 0) * F(2, 1)); // xy
E(0, 2) = 0.5*(F(0, 0) * F(0, 2) + F(1, 0) * F(1, 2) + F(2, 0) * F(2, 2)); // xz
E(1, 2) = 0.5*(F(0, 1) * F(0, 2) + F(1, 1) * F(1, 2) + F(2, 1) * F(2, 2)); // yz
E(0, 0) = 0.5*(F(0, 0) * F(0, 0) + F(1, 0) * F(1, 0) + F(2, 0) * F(2, 0) - 1.0); // xx
E(1, 1) = 0.5*(F(0, 1) * F(0, 1) + F(1, 1) * F(1, 1) + F(2, 1) * F(2, 1) - 1.0); // yy
E(2, 2) = 0.5*(F(0, 2) * F(0, 2) + F(1, 2) * F(1, 2) + F(2, 2) * F(2, 2) - 1.0); // zz
E(0, 1) = 0.5*(F(0, 0) * F(0, 1) + F(1, 0) * F(1, 1) + F(2, 0) * F(2, 1)); // xy
E(0, 2) = 0.5*(F(0, 0) * F(0, 2) + F(1, 0) * F(1, 2) + F(2, 0) * F(2, 2)); // xz
E(1, 2) = 0.5*(F(0, 1) * F(0, 2) + F(1, 1) * F(1, 2) + F(2, 1) * F(2, 2)); // yz
E(1, 0) = E(0, 1);
E(2, 0) = E(0, 2);
E(2, 1) = E(1, 2);
......@@ -206,7 +207,6 @@ FEMTetConstraint::solvePositionConstraint(PositionBasedModel &model)
p3 += s*im4*(gradC.col(0) + gradC.col(1) + gradC.col(2));
return true;
}
void
......@@ -250,14 +250,15 @@ DistanceConstraint::solvePositionConstraint(PositionBasedModel &model)
p0 += im1*gradC;
if (im2 > 0)
p1 += -im2*gradC;
return true;
}
void
DihedralConstraint::initConstraint(PositionBasedModel &model,
const unsigned int &pIdx1, const unsigned int &pIdx2,
const unsigned int &pIdx3, const unsigned int &pIdx4,
const double k)
const unsigned int &pIdx1, const unsigned int &pIdx2,
const unsigned int &pIdx3, const unsigned int &pIdx4,
const double k)
{
m_bodies[0] = pIdx1;
m_bodies[1] = pIdx2;
......@@ -478,7 +479,6 @@ VolumeConstraint::solvePositionConstraint(PositionBasedModel &model)
x4 += -im4*lambda*grad4;
return true;
}
} // imstk
\ No newline at end of file
} // imstk
......@@ -37,22 +37,22 @@ void
stdSink::ReceiveLogMessage(g3::LogMessageMover logEntry)
{
auto level = logEntry.get()._level;
auto message = logEntry.get().message();
auto message = logEntry.get().message();
#ifndef WIN32
auto color = GetColor(level);
std::cout << "\033[" << color << "m"
<< message
<< "\033[m" << std::endl;
<< "\033[m" << std::endl;
#else
if (level.value == WARNING.value || level.value == FATAL.value)
{
std::cerr << message << std::endl;
}
else
{
std::cout << message << std::endl;
}
if (level.value == WARNING.value || level.value == FATAL.value)
{
std::cerr << message << std::endl;
}
else
{
std::cout << message << std::endl;
}
#endif
}
......
......@@ -34,15 +34,15 @@ namespace imstk
void
HDAPIDeviceClient::init()
{
// Open Device
// Open Device
m_handle = hdInitDevice(this->getDeviceName().c_str());
// If failed
HDErrorInfo error;
if (HD_DEVICE_ERROR(error = hdGetError()))
{
// If failed
HDErrorInfo error;
if (HD_DEVICE_ERROR(error = hdGetError()))
{
LOG(FATAL) << "Failed to initialize Phantom Omni " << this->getDeviceName();
m_handle = -1;
m_handle = -1;
return;
}
......@@ -73,7 +73,7 @@ HDAPIDeviceClient::hapticCallback(void* pData)
auto handle = client->m_handle;
auto state = client->m_state;
hdBeginFrame(handle);
hdBeginFrame(handle);
hdMakeCurrentDevice(handle);
hdSetDoublev(HD_CURRENT_FORCE, client->m_force.data());
hdGetDoublev(HD_CURRENT_POSITION, state.pos);
......
......@@ -66,7 +66,7 @@ protected:
private:
static HDCallbackCode HDCALLBACK hapticCallback(void* pData);
HHD m_handle; //!< device handle
HD_state m_state; //!< device reading state
......
......@@ -169,8 +169,8 @@ TetraTriangleMap::findClosestTetrahedron(std::shared_ptr<TetrahedralMesh> tetraM
{
center += tetraMesh->getInitialVertexPosition(vert[i]);
}
center = center / 4;
double dist = (pos - center).norm();
center = center / 4;
double dist = (pos - center).norm();
if (dist < closestDistance)
{
closestDistance = dist;
......
......@@ -25,28 +25,44 @@
namespace imstk
{
void LineMesh::clear(){}
void LineMesh::print() const {
Mesh::print();
}
double LineMesh::getVolume() const{
return 0.0;
}
void LineMesh::setConnectivity(const std::vector<std::vector<int> >& lines){
m_lines = lines;
}
int LineMesh::getNumLines(){
return m_lines.size();
}
std::vector<std::vector<int> > LineMesh::getLines() const{
return m_lines;
}
std::vector<int> LineMesh::getLine(int index) const{
return m_lines[index];
}
} // imstk
\ No newline at end of file
void
LineMesh::clear()
{}
void
LineMesh::print() const
{
Mesh::print();
}
double
LineMesh::getVolume() const
{
return 0.0;
}
void
LineMesh::setConnectivity(const std::vector<std::vector<int> >& lines)
{
m_lines = lines;
}
int
LineMesh::getNumLines()
{
return m_lines.size();
}
std::vector<std::vector<int>>
LineMesh::getLines() const
{
return m_lines;
}
std::vector<int>
LineMesh::getLine(int index) const
{
return m_lines[index];
}
} // imstk
......@@ -38,31 +38,54 @@ namespace imstk
class LineMesh : public Mesh
{
public:
LineMesh() : Mesh(Geometry::Type::LineMesh) {}
///
/// \brief Constructor
///
LineMesh() : Mesh(Geometry::Type::LineMesh) {}
///
/// \brief Default destructor
///
~LineMesh() = default;
virtual void clear();
///
/// \brief
///
virtual void clear();
///
/// \brief Print the mesh info
///
virtual void print() const override;
///
/// \brief
///
virtual void print() const override;
virtual double getVolume() const;
void setConnectivity(const std::vector<std::vector<int> >& lines);
///
/// \brief
///
virtual double getVolume() const;
int getNumLines();
///
/// \brief
///
void setConnectivity(const std::vector<std::vector<int> >& lines);
std::vector<std::vector<int> > getLines() const;
///
/// \brief
///
int getNumLines();
std::vector<int> getLine(int index) const;
///
/// \brief
///
std::vector<std::vector<int> > getLines() const;
///
/// \brief
///
std::vector<int> getLine(int index) const;
private:
std::vector<std::vector<int> > m_lines; ///> line connectivity
std::vector<std::vector<int> > m_lines; ///> line connectivity
};
} // imstk
......
......@@ -55,7 +55,7 @@ void
Mesh::computeBoundingBox(Vec3d& min, Vec3d& max, const double percent) const
{
min = Vec3d(MAX_D, MAX_D, MAX_D);
max = Vec3d(-MAX_D, -MAX_D, -MAX_D);
max = Vec3d(-MAX_D, -MAX_D, -MAX_D);
for (auto& pos : m_verticesPositions)
{
......
......@@ -151,7 +151,7 @@ protected:
friend class SurfaceMeshRenderDelegate;
friend class TetrahedralMeshRenderDelegate;
friend class LineMeshRenderDelegate;
friend class LineMeshRenderDelegate;
///
/// \brief Get vertices positions
......
......@@ -84,8 +84,8 @@ Geometry::isMesh() const
return (this->m_type == Type::HexahedralMesh ||
this->m_type == Type::SurfaceMesh ||
this->m_type == Type::TetrahedralMesh ||
this->m_type == Type::LineMesh
) ? true : false;
this->m_type == Type::LineMesh
) ? true : false;
}
const Vec3d&
......
......@@ -47,7 +47,7 @@ public:
SurfaceMesh,
TetrahedralMesh,
HexahedralMesh,
LineMesh
LineMesh
};
///
......
......@@ -41,29 +41,29 @@ LineMeshRenderDelegate::LineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMes
m_geometry(lineMesh)
{
// Map vertices
m_mappedVertexArray = vtkDoubleArray::New();
m_mappedVertexArray->SetNumberOfComponents(3);
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->InsertNextTuple3(vertices[i][0], vertices[i][1], vertices[i][2]);
}
this->mapVertices();
m_mappedVertexArray = vtkDoubleArray::New();
m_mappedVertexArray->SetNumberOfComponents(3);
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->InsertNextTuple3(vertices[i][0], vertices[i][1], vertices[i][2]);
}
this->mapVertices();
// Create points
auto points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(m_geometry->getNumVertices());
points->SetData(m_mappedVertexArray);
points->SetData(m_mappedVertexArray);
m_lines = vtkSmartPointer<vtkLineSource>::New();
m_lines->SetPoints(points);
m_lines->Update();
m_lines = vtkSmartPointer<vtkLineSource>::New();
m_lines->SetPoints(points);
m_lines->Update();
//Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
//Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(m_lines->GetOutputPort());
mapper->SetInputConnection(m_lines->GetOutputPort());
m_actor->SetMapper(mapper);
m_actor->SetMapper(mapper);
// Transform
this->updateActorTransform();
......@@ -72,14 +72,14 @@ LineMeshRenderDelegate::LineMeshRenderDelegate(std::shared_ptr<LineMesh> lineMes
void
LineMeshRenderDelegate::mapVertices()
{
auto vertices = m_geometry->getVerticesPositionsNotConst();
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->SetTuple3(i, vertices[i][0], vertices[i][1], vertices[i][2]);
}
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->SetTuple3(i, vertices[i][0], vertices[i][1], vertices[i][2]);
}
// TODO: only when vertices modified
m_mappedVertexArray->Modified();
// TODO: only when vertices modified
m_mappedVertexArray->Modified();
}
void
......@@ -88,8 +88,8 @@ LineMeshRenderDelegate::update()
// Base class update
RenderDelegate::update();
this->mapVertices();
m_lines->Update();
this->mapVertices();
m_lines->Update();
}
std::shared_ptr<Geometry>
......
......@@ -51,11 +51,10 @@ public:
///
LineMeshRenderDelegate(std::shared_ptr<LineMesh>LineMesh);
///
/// \brief
///
void mapVertices();
///
/// \brief
///
void mapVertices();
///
/// \brief
......@@ -68,7 +67,7 @@ public:
std::shared_ptr<Geometry>getGeometry() const override;
protected:
vtkSmartPointer<vtkLineSource> m_lines;
vtkSmartPointer<vtkLineSource> m_lines;
std::shared_ptr<LineMesh> m_geometry;
vtkSmartPointer<vtkDoubleArray> m_mappedVertexArray;
......
......@@ -74,11 +74,11 @@ RenderDelegate::make_delegate(std::shared_ptr<Geometry>geom)
auto mesh = std::dynamic_pointer_cast<TetrahedralMesh>(geom);
return std::make_shared<TetrahedralMeshRenderDelegate>(mesh);
}
case Geometry::Type::LineMesh:
{
auto mesh = std::dynamic_pointer_cast<LineMesh>(geom);
return std::make_shared<LineMeshRenderDelegate>(mesh);
}
case Geometry::Type::LineMesh:
{
auto mesh = std::dynamic_pointer_cast<LineMesh>(geom);
return std::make_shared<LineMeshRenderDelegate>(mesh);
}
case Geometry::Type::HexahedralMesh:
{
auto mesh = std::dynamic_pointer_cast<TetrahedralMesh>(geom);
......
......@@ -40,18 +40,18 @@ SurfaceMeshRenderDelegate::SurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh
m_geometry(surfaceMesh)
{
// Map vertices
m_mappedVertexArray = vtkDoubleArray::New();
m_mappedVertexArray->SetNumberOfComponents(3);
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->InsertNextTuple3(vertices[i][0], vertices[i][1], vertices[i][2]);
}
this->mapVertices();
m_mappedVertexArray = vtkDoubleArray::New();
m_mappedVertexArray->SetNumberOfComponents(3);
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->InsertNextTuple3(vertices[i][0], vertices[i][1], vertices[i][2]);
}
this->mapVertices();
// Create points
auto points = vtkSmartPointer<vtkPoints>::New();
points->SetNumberOfPoints(m_geometry->getNumVertices());
points->SetData(m_mappedVertexArray);
points->SetData(m_mappedVertexArray);
// Copy triangles
auto triangles = vtkSmartPointer<vtkCellArray>::New();
......@@ -114,17 +114,17 @@ SurfaceMeshRenderDelegate::SurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh
unit++;
}
//// Update normals
//auto normals = surfaceMesh->getPointDataArray("Normals");
//auto vtkNormals = vtkSmartPointer<vtkFloatArray>::New();
//vtkNormals->SetNumberOfComponents(3);
//vtkNormals->SetName("Normals");
//for (auto const normal : normals)
//{
// double triple[3] = { normal[0], normal[1], normal[2] };
// vtkNormals->InsertNextTuple(triple);
//}
//polydata->GetPointData()->SetNormals(vtkNormals);
//// Update normals
//auto normals = surfaceMesh->getPointDataArray("Normals");
//auto vtkNormals = vtkSmartPointer<vtkFloatArray>::New();
//vtkNormals->SetNumberOfComponents(3);
//vtkNormals->SetName("Normals");
//for (auto const normal : normals)
//{
// double triple[3] = { normal[0], normal[1], normal[2] };
// vtkNormals->InsertNextTuple(triple);
//}
//polydata->GetPointData()->SetNormals(vtkNormals);
// Actor
m_actor->SetMapper(mapper);
......@@ -136,14 +136,14 @@ SurfaceMeshRenderDelegate::SurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh
void
SurfaceMeshRenderDelegate::mapVertices()
{
auto vertices = m_geometry->getVerticesPositionsNotConst();
auto vertices = m_geometry->getVerticesPositionsNotConst();
for (int i = 0; i < vertices.size(); i++) {
m_mappedVertexArray->SetTuple3(i, vertices[i][0], vertices[i][1], vertices[i][2]);
}