Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration with 3Dconnexion input devices #1311

Merged
merged 5 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions avogadro/core/molecule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ Molecule::Molecule(const Molecule& other)
m_meshes(std::vector<Mesh*>()), m_cubes(std::vector<Cube*>()),
m_basisSet(other.m_basisSet ? other.m_basisSet->clone() : nullptr),
m_unitCell(other.m_unitCell ? new UnitCell(*other.m_unitCell) : nullptr),
m_residues(other.m_residues),
m_hallNumber(other.m_hallNumber), m_graph(other.m_graph),
m_bondOrders(other.m_bondOrders), m_atomicNumbers(other.m_atomicNumbers),
m_residues(other.m_residues), m_hallNumber(other.m_hallNumber),
m_graph(other.m_graph), m_bondOrders(other.m_bondOrders),
m_atomicNumbers(other.m_atomicNumbers),
m_layers(LayerManager::getMoleculeLayer(this))
{
// Copy over any meshes
Expand Down Expand Up @@ -88,8 +88,8 @@ Molecule::Molecule(Molecule&& other) noexcept
m_selectedAtoms(std::move(other.m_selectedAtoms)),
m_meshes(std::move(other.m_meshes)), m_cubes(std::move(other.m_cubes)),
m_residues(other.m_residues), m_hallNumber(other.m_hallNumber),
m_graph(other.m_graph),
m_bondOrders(other.m_bondOrders), m_atomicNumbers(other.m_atomicNumbers),
m_graph(other.m_graph), m_bondOrders(other.m_bondOrders),
m_atomicNumbers(other.m_atomicNumbers),
m_layers(LayerManager::getMoleculeLayer(this))
{
m_basisSet = other.m_basisSet;
Expand Down Expand Up @@ -1324,4 +1324,29 @@ std::list<Index> Molecule::getAtomsAtLayer(size_t layer)
return result;
}

void Molecule::boundingBox(Vector3& boxMin, Vector3& boxMax,
const double radius) const
{
boxMin.setConstant(std::numeric_limits<double>::max());
boxMax.setConstant(-std::numeric_limits<double>::max());

const bool noSelection = isSelectionEmpty();

for (uint32_t i = 0; i < atomCount(); i++) {
if (noSelection || m_selectedAtoms[i]) {

const Vector3 boxMinBuffer = atom(i).position3d().array() - radius;
const Vector3 boxMaxBuffer = atom(i).position3d().array() + radius;

boxMin.x() = std::min(boxMinBuffer.x(), boxMin.x());
boxMin.y() = std::min(boxMinBuffer.y(), boxMin.y());
boxMin.z() = std::min(boxMinBuffer.z(), boxMin.z());

boxMax.x() = std::max(boxMaxBuffer.x(), boxMax.x());
boxMax.y() = std::max(boxMaxBuffer.y(), boxMax.y());
boxMax.z() = std::max(boxMaxBuffer.z(), boxMax.z());
}
}
}

} // namespace Avogadro::Core
20 changes: 16 additions & 4 deletions avogadro/core/molecule.h
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,10 @@ class AVOGADROCORE_EXPORT Molecule

/**
* Perceives bonds in the molecule based on preset residue data.
*
* Use this if you have residue data available (e.g., reading PDB or MMTF files)
* Otherwise consider @sa perceiveBondsSimple and @sa perceiveBondOrders
*
* Use this if you have residue data available (e.g., reading PDB or MMTF
* files) Otherwise consider @sa perceiveBondsSimple and @sa
* perceiveBondOrders
*/
void perceiveBondsFromResidueData();

Expand Down Expand Up @@ -717,9 +718,20 @@ class AVOGADROCORE_EXPORT Molecule
Layer& layer();
const Layer& layer() const;

/**
* Calculte and return bounding box of the whole molecule or selected atoms
* only.
* @param boxMin [out] the minimum corner (first end of the box diagonal)
* @param boxMax [out] the maximum corner (second end of the box diagonal)
* @param radius [in] radius of a single sphere
*/
void boundingBox(Vector3& boxMin, Vector3& boxMax,
const double radius = 1.0) const;

protected:
VariantMap m_data;
std::map<std::string, MatrixX> m_partialCharges; //!< Sets of atomic partial charges
std::map<std::string, MatrixX>
m_partialCharges; //!< Sets of atomic partial charges
CustomElementMap m_customElementMap;
ElementMask m_elements; //!< Which elements this molecule contains (e.g., for
//!< force fields)
Expand Down
5 changes: 5 additions & 0 deletions avogadro/rendering/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)

if(WIN32 AND NOT BUILD_SHARED_LIBS)
add_definitions(-DGLEW_STATIC)
endif()
Expand Down Expand Up @@ -144,3 +145,7 @@ target_link_libraries(Rendering
Avogadro::Core # Needed for an emum in residue.h that we should move, maybe others.
GLEW::GLEW
OpenGL::GL)

if(USE_3DCONNEXION AND (WIN32 OR APPLE))
target_compile_definitions(Rendering PUBLIC _3DCONNEXION)
endif()
23 changes: 19 additions & 4 deletions avogadro/rendering/camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ Vector3f Camera::unProject(const Vector3f& point) const
m_data->projection.matrix() * m_data->modelView.matrix();
Vector4f result(
2.0f * point.x() / static_cast<float>(m_width) - 1.0f,
2.0f * (static_cast<float>(m_height) - point.y()) /
static_cast<float>(m_height) -
1.0f,
2.0f * point.z() - 1.0f, 1.0f);
2.0f * (static_cast<float>(m_height) - point.y()) /
static_cast<float>(m_height) -
1.0f,
2.0f * point.z() - 1.0f, 1.0f);
result = mvp.matrix().inverse() * result;
return Vector3f(result.x() / result.w(), result.y() / result.w(),
result.z() / result.w());
Expand Down Expand Up @@ -184,4 +184,19 @@ void Camera::setModelView(const Eigen::Affine3f& transform)
m_data->modelView = transform;
}

void Camera::calculatePerspective(float left, float right, float bottom,
float top, float zNear, float zFar)
{
m_data->projection.setIdentity();

m_data->projection(0, 0) = (2.0f * zNear) / (right - left);
m_data->projection(1, 1) = (2.0f * zNear) / (top - bottom);
m_data->projection(0, 2) = (right + left) / (right - left);
m_data->projection(1, 2) = (top + bottom) / (top - bottom);
m_data->projection(2, 2) = -(zFar + zNear) / (zFar - zNear);
m_data->projection(3, 2) = -1.0f;
m_data->projection(2, 3) = -(2.0f * zFar * zNear) / (zFar - zNear);
m_data->projection(3, 3) = 0.0f;
}

} // namespace Avogadro
13 changes: 13 additions & 0 deletions avogadro/rendering/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,19 @@ class AVOGADRORENDERING_EXPORT Camera
*/
void calculatePerspective(float fieldOfView, float zNear, float zFar);

/**
* Calculate the perspective projection matrix using frustum planes
* coordinates.
* @param left left vertical clipping plane.
* @param right right vertical clipping plane.
* @param bottom bottom horizontal clipping plane.
* @param top top horizontal clipping plane.
* @param zNear distance to the near clipping plane.
* @param zFar distance to the far clipping plane.
*/
void calculatePerspective(float left, float right, float bottom, float top,
float zNear, float zFar);

/**
* Calculate the orthographic projection matrix.
* @param left left vertical clipping plane.
Expand Down
14 changes: 5 additions & 9 deletions avogadro/rendering/geometryvisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@ GeometryVisitor::GeometryVisitor()
{
}

GeometryVisitor::~GeometryVisitor()
{
}
GeometryVisitor::~GeometryVisitor() {}

void GeometryVisitor::visit(Drawable&)
{
}
void GeometryVisitor::visit(Drawable&) {}

void GeometryVisitor::visit(SphereGeometry& geometry)
ghutchis marked this conversation as resolved.
Show resolved Hide resolved
{
Expand Down Expand Up @@ -122,13 +118,13 @@ void GeometryVisitor::visit(LineStripGeometry& lsg)
m_dirty = true;

Vector3f tmpCenter(Vector3f::Zero());
for (const auto & vert : verts) {
for (const auto& vert : verts) {
tmpCenter += vert.vertex;
}
tmpCenter /= static_cast<float>(verts.size());

float tmpRadius(0.f);
for (const auto & vert : verts) {
for (const auto& vert : verts) {
float distance = (vert.vertex - tmpCenter).squaredNorm();
if (distance > tmpRadius)
tmpRadius = distance;
Expand Down Expand Up @@ -187,4 +183,4 @@ void GeometryVisitor::average()
}
}

} // End namespace Avogadro
} // namespace Avogadro::Rendering
73 changes: 65 additions & 8 deletions avogadro/rendering/glrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,25 @@ using Core::Array;
GLRenderer::GLRenderer()
: m_valid(false), m_textRenderStrategy(nullptr), m_center(Vector3f::Zero()),
m_radius(20.0)
#ifdef _3DCONNEXION
,
m_drawIcon(false), m_iconData(nullptr), m_iconWidth(0u), m_iconHeight(0u),
m_iconPosition(Eigen::Vector3f::Zero())
#endif
{
m_overlayCamera.setIdentity();

float aspectRatio = static_cast<float>(m_camera.width()) /
static_cast<float>(m_camera.height());
float distance = m_camera.distance(m_center);
float offset = distance + m_radius;
m_perspectiveFrustum = {
-aspectRatio, aspectRatio, -1.0f, 1.0f, 2.0f, offset
};
m_orthographicFrustum = {
-5.0f * aspectRatio, 5.0f * aspectRatio, -5.0f, 5.0f, -offset, offset
};

}

GLRenderer::~GLRenderer()
Expand All @@ -50,7 +67,7 @@ void GLRenderer::initialize()
m_valid = false;
return;
}

m_solidPipeline.initialize();
}

Expand Down Expand Up @@ -117,6 +134,24 @@ void GLRenderer::render()
visitor.setCamera(m_overlayCamera);
glDisable(GL_DEPTH_TEST);
m_scene.rootNode().accept(visitor);

#ifdef _3DCONNEXION
if (m_drawIcon && (m_iconData != nullptr)) {
glPushMatrix();
Eigen::Vector4f pivotPosition =
m_camera.projection().matrix() * m_camera.modelView().matrix() *
Eigen::Vector4f(m_iconPosition.x(), m_iconPosition.y(),
m_iconPosition.z(), 1.0);
pivotPosition /= pivotPosition.w();
glRasterPos3d(pivotPosition.x(), pivotPosition.y(), pivotPosition.z());
glPixelZoom(1.0f, -1.0f);
glBitmap(0.0f, 0.0f, 0.0f, 0.0f, -static_cast<float>(m_iconWidth >> 1),
static_cast<float>(m_iconHeight >> 1), NULL);
glDrawPixels(m_iconWidth, m_iconHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE,
m_iconData);
glPopMatrix();
}
#endif
}

void GLRenderer::resetCamera()
Expand Down Expand Up @@ -169,16 +204,28 @@ void GLRenderer::setTextRenderStrategy(TextRenderStrategy* tren)
void GLRenderer::applyProjection()
{
float distance = m_camera.distance(m_center);
float aspectRatio = static_cast<float>(m_camera.width()) /
static_cast<float>(m_camera.height());
if (m_camera.projectionType() == Perspective) {
m_camera.calculatePerspective(40.0f, std::max(2.0f, distance - m_radius),
distance + m_radius);
m_perspectiveFrustum[0] = m_perspectiveFrustum[2] * aspectRatio;
m_perspectiveFrustum[1] = m_perspectiveFrustum[3] * aspectRatio;
m_perspectiveFrustum[5] = distance + m_radius;
m_camera.calculatePerspective(
m_perspectiveFrustum[0], m_perspectiveFrustum[1], m_perspectiveFrustum[2],
m_perspectiveFrustum[3], m_perspectiveFrustum[4],
m_perspectiveFrustum[5]);
} else {
// Renders the orthographic projection of the molecule
const double halfHeight = m_radius;
const double halfWidth = halfHeight * m_camera.width() / m_camera.height();
m_camera.calculateOrthographic(
-halfWidth, halfWidth, -halfHeight, halfHeight,
std::max(2.0f, distance - m_radius), distance + m_radius);
m_orthographicFrustum[0] = m_orthographicFrustum[2] * aspectRatio;
m_orthographicFrustum[1] = m_orthographicFrustum[3] * aspectRatio;
m_orthographicFrustum[5] = distance + m_radius;
m_orthographicFrustum[4] = -m_orthographicFrustum[5];
m_camera.calculateOrthographic(m_orthographicFrustum[0], // L
m_orthographicFrustum[1], // R
m_orthographicFrustum[2], // B
m_orthographicFrustum[3], // T
m_orthographicFrustum[4], // N
m_orthographicFrustum[5]); // F
}
m_overlayCamera.calculateOrthographic(
0.f, static_cast<float>(m_overlayCamera.width()), 0.f,
Expand Down Expand Up @@ -258,6 +305,16 @@ Array<Identifier> GLRenderer::hits(const GroupNode* group,
return result;
}

float GLRenderer::hit(const Vector3f& rayOrigin, const Vector3f& rayEnd,
const Vector3f& rayDirection) const
{
std::multimap<float, Identifier> results =
hits(&m_scene.rootNode(), rayOrigin, rayEnd, rayDirection);
if (results.size())
return results.begin()->first;
return std::numeric_limits<float>::max();
}

Array<Identifier> GLRenderer::hits(int x1, int y1, int x2, int y2) const
{
// Figure out where the corners of our rectangle are.
Expand Down
15 changes: 15 additions & 0 deletions avogadro/rendering/glrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ class AVOGADRORENDERING_EXPORT GLRenderer
*/
Identifier hit(int x, int y) const;

/** Return the depth of provided ray - geometry hit test.
*/
float hit(const Vector3f& rayOrigin, const Vector3f& rayEnd,
const Vector3f& rayDirection) const;

/** Return the primitives in the rectangular area provided. */
Core::Array<Identifier> hits(int x1, int y1, int x2, int y2) const;

Expand Down Expand Up @@ -104,6 +109,16 @@ class AVOGADRORENDERING_EXPORT GLRenderer
void setTextRenderStrategy(TextRenderStrategy* tren);
/** @} */

std::array<float, 6> m_perspectiveFrustum; // L, R, B, T, N, F (planes order)
std::array<float, 6> m_orthographicFrustum; // L, R, B, T, N, F (planes order)
#ifdef _3DCONNEXION
bool m_drawIcon;
void* m_iconData;
uint32_t m_iconWidth;
uint32_t m_iconHeight;
Eigen::Vector3f m_iconPosition;
#endif

private:
/**
* Apply the projection matrix.
Expand Down
2 changes: 1 addition & 1 deletion avogadro/rendering/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ void Scene::clear()
m_dirty = true;
}

} // End Avogadro namespace
} // namespace Avogadro::Rendering