| 1 | /*
 | 
|---|
| 2 |  * Project: MoleCuilder
 | 
|---|
| 3 |  * Description: creates and alters molecular systems
 | 
|---|
| 4 |  * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 | 
|---|
| 5 |  * Copyright (C)  2013 Frederik Heber. All rights reserved.
 | 
|---|
| 6 |  *
 | 
|---|
| 7 |  *
 | 
|---|
| 8 |  *   This file is part of MoleCuilder.
 | 
|---|
| 9 |  *
 | 
|---|
| 10 |  *    MoleCuilder is free software: you can redistribute it and/or modify
 | 
|---|
| 11 |  *    it under the terms of the GNU General Public License as published by
 | 
|---|
| 12 |  *    the Free Software Foundation, either version 2 of the License, or
 | 
|---|
| 13 |  *    (at your option) any later version.
 | 
|---|
| 14 |  *
 | 
|---|
| 15 |  *    MoleCuilder is distributed in the hope that it will be useful,
 | 
|---|
| 16 |  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 17 |  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 18 |  *    GNU General Public License for more details.
 | 
|---|
| 19 |  *
 | 
|---|
| 20 |  *    You should have received a copy of the GNU General Public License
 | 
|---|
| 21 |  *    along with MoleCuilder.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 22 |  */
 | 
|---|
| 23 | 
 | 
|---|
| 24 | /*
 | 
|---|
| 25 |  * GLMoleculeObject_shape.cpp
 | 
|---|
| 26 |  *
 | 
|---|
| 27 |  *  Created on: Aug 3, 2012
 | 
|---|
| 28 |  *      Author: ankele
 | 
|---|
| 29 |  */
 | 
|---|
| 30 | 
 | 
|---|
| 31 | 
 | 
|---|
| 32 | 
 | 
|---|
| 33 | // include config.h
 | 
|---|
| 34 | #ifdef HAVE_CONFIG_H
 | 
|---|
| 35 | #include <config.h>
 | 
|---|
| 36 | #endif
 | 
|---|
| 37 | 
 | 
|---|
| 38 | #include "GLMoleculeObject_shape.hpp"
 | 
|---|
| 39 | 
 | 
|---|
| 40 | #include <Qt3D/qglview.h>
 | 
|---|
| 41 | #include <Qt3D/qglscenenode.h>
 | 
|---|
| 42 | #include <Qt3D/qglpainter.h>
 | 
|---|
| 43 | #include <Qt3D/qglmaterial.h>
 | 
|---|
| 44 | #include <Qt3D/qglbuilder.h>
 | 
|---|
| 45 | #include <Qt3D/qglsphere.h>
 | 
|---|
| 46 | 
 | 
|---|
| 47 | //#include "CodePatterns/MemDebug.hpp"
 | 
|---|
| 48 | 
 | 
|---|
| 49 | #include "CodePatterns/Assert.hpp"
 | 
|---|
| 50 | #include "CodePatterns/Log.hpp"
 | 
|---|
| 51 | 
 | 
|---|
| 52 | #include "Shapes/ShapeFactory.hpp"
 | 
|---|
| 53 | #include "LinearAlgebra/Vector.hpp"
 | 
|---|
| 54 | #include "LinkedCell/PointCloudAdaptor.hpp"
 | 
|---|
| 55 | #include "LinkedCell/linkedcell.hpp"
 | 
|---|
| 56 | #include "Tesselation/tesselation.hpp"
 | 
|---|
| 57 | #include "Tesselation/BoundaryLineSet.hpp"
 | 
|---|
| 58 | #include "Tesselation/BoundaryTriangleSet.hpp"
 | 
|---|
| 59 | #include "Tesselation/CandidateForTesselation.hpp"
 | 
|---|
| 60 | #include "Atom/TesselPoint.hpp"
 | 
|---|
| 61 | 
 | 
|---|
| 62 | typedef QGLSceneNode *MeshList[GLMoleculeObject::DETAILTYPES_MAX];
 | 
|---|
| 63 | 
 | 
|---|
| 64 | static QGLSceneNode *createShapeMesh(Shape &shape, QObject *parent)
 | 
|---|
| 65 | {
 | 
|---|
| 66 |   size_t NumPointsonSurface = 200;
 | 
|---|
| 67 |   // guess the surface area which divided by 200 determines rolling sphere's size
 | 
|---|
| 68 |   const double surfacearea = shape.getSurfaceArea();
 | 
|---|
| 69 |   const size_t EstimatedNumberTriangles = NumPointsonSurface*1;
 | 
|---|
| 70 |   const double MeanAreaPerTriangle = surfacearea/((double)EstimatedNumberTriangles);
 | 
|---|
| 71 |   // assume two triangles to form a square and take its diameter as the radius
 | 
|---|
| 72 |   double minradius = sqrt(2. * 2.*MeanAreaPerTriangle);
 | 
|---|
| 73 |   LOG(3, "DEBUG: Surface area is " << surfacearea << ", minradius is " << minradius << ".");
 | 
|---|
| 74 |   if (minradius < 1.)
 | 
|---|
| 75 |     minradius = 1.;
 | 
|---|
| 76 |   LOG(2, "DEBUG: Tesselating shape " << shape.getName() << " with sphere of radius " << minradius << ".");
 | 
|---|
| 77 | 
 | 
|---|
| 78 |   // Create some points on our shape.
 | 
|---|
| 79 |   std::vector<Vector> points = shape.getHomogeneousPointsOnSurface(NumPointsonSurface);
 | 
|---|
| 80 | 
 | 
|---|
| 81 |   QGeometryData geo;
 | 
|---|
| 82 |   // we need at least three points for tesselation
 | 
|---|
| 83 |   if (points.size() >= 3) {
 | 
|---|
| 84 |     // Fill the points into a tesselate-able container.
 | 
|---|
| 85 |     TesselPointSTLList Corners;
 | 
|---|
| 86 |     for (size_t i=0;i<points.size();++i){
 | 
|---|
| 87 |       TesselPoint *Walker = new TesselPoint;
 | 
|---|
| 88 |       Walker->setPosition(points[i]);
 | 
|---|
| 89 |       Walker->setName(toString(i));
 | 
|---|
| 90 |       Walker->setNr(i);
 | 
|---|
| 91 |       Corners.push_back(Walker);
 | 
|---|
| 92 |     }
 | 
|---|
| 93 |   
 | 
|---|
| 94 |     // Tesselate the points.
 | 
|---|
| 95 |     Tesselation T;
 | 
|---|
| 96 |     PointCloudAdaptor<TesselPointSTLList> cloud(&Corners, "TesselPointSTLList");
 | 
|---|
| 97 |     T(cloud, minradius);
 | 
|---|
| 98 |   
 | 
|---|
| 99 |     // Fill the points into a Qt geometry.
 | 
|---|
| 100 |     LinkedCell_deprecated LinkedList(cloud, minradius);
 | 
|---|
| 101 |     std::vector<Vector> normals;
 | 
|---|
| 102 |     normals.resize(points.size(), zeroVec);
 | 
|---|
| 103 |     for(size_t i=0;i<points.size();++i){
 | 
|---|
| 104 |       // add data to the primitive
 | 
|---|
| 105 |       geo.appendVertex(QVector3D(points[i][0], points[i][1], points[i][2]));
 | 
|---|
| 106 |       if (ShapeFactory::getInstance().isSimpleShape(shape.getType()))
 | 
|---|
| 107 |         normals[i] = shape.getNormal(points[i]);
 | 
|---|
| 108 |       else
 | 
|---|
| 109 |         normals[i] = T.getNormal(points[i], &LinkedList);
 | 
|---|
| 110 |       geo.appendNormal(QVector3D(normals[i][0], normals[i][1], normals[i][2]));
 | 
|---|
| 111 |       geo.appendColor(QColor(1, 1, 1, 1));
 | 
|---|
| 112 |       geo.appendTexCoord(QVector2D(0, 0));
 | 
|---|
| 113 |     }
 | 
|---|
| 114 |   
 | 
|---|
| 115 |     // Fill the tesselated triangles into the geometry.
 | 
|---|
| 116 |     for (TriangleMap::const_iterator runner = T.TrianglesOnBoundary.begin(); runner != T.TrianglesOnBoundary.end(); runner++) {
 | 
|---|
| 117 |       int v[3];
 | 
|---|
| 118 |       for (size_t i=0; i<3; ++i)
 | 
|---|
| 119 |         v[i] = runner->second->endpoints[i]->node->getNr();
 | 
|---|
| 120 |   
 | 
|---|
| 121 |       // Sort the vertices so the triangle is clockwise (relative to the normal vector).
 | 
|---|
| 122 |       Vector cross = points[v[1]] - points[v[0]];
 | 
|---|
| 123 |       cross.VectorProduct(points[v[2]] - points[v[0]]);
 | 
|---|
| 124 |       if (cross.ScalarProduct(normals[v[0]] + normals[v[1]] + normals[v[2]]) > 0)
 | 
|---|
| 125 |         geo.appendIndices(v[0], v[1], v[2]);
 | 
|---|
| 126 |       else
 | 
|---|
| 127 |         geo.appendIndices(v[0], v[2], v[1]);
 | 
|---|
| 128 |     }
 | 
|---|
| 129 |   }
 | 
|---|
| 130 | 
 | 
|---|
| 131 |   // Build a mesh from the geometry.
 | 
|---|
| 132 |   QGLBuilder builder;
 | 
|---|
| 133 |   builder.addTriangles(geo);
 | 
|---|
| 134 |   QGLSceneNode *mesh = builder.finalizedSceneNode();
 | 
|---|
| 135 |   return mesh;
 | 
|---|
| 136 | }
 | 
|---|
| 137 | 
 | 
|---|
| 138 | GLMoleculeObject_shape::GLMoleculeObject_shape(Shape &shape, QObject *parent) :
 | 
|---|
| 139 |     GLMoleculeObject(createShapeMesh(shape, parent), parent),
 | 
|---|
| 140 |     m_shape(shape)
 | 
|---|
| 141 | {
 | 
|---|
| 142 |   // Create the material.
 | 
|---|
| 143 |   QGLMaterial *material = new QGLMaterial(NULL);
 | 
|---|
| 144 |   material->setAmbientColor( QColor(50, 60, 100, 255) );
 | 
|---|
| 145 |   material->setDiffuseColor( QColor(150, 160, 200, 180) );
 | 
|---|
| 146 |   material->setSpecularColor( QColor(60, 60, 60) );
 | 
|---|
| 147 |   material->setShininess( 128 );
 | 
|---|
| 148 |   setMaterial(material);
 | 
|---|
| 149 | 
 | 
|---|
| 150 |   m_enabled = false;
 | 
|---|
| 151 | }
 | 
|---|
| 152 | 
 | 
|---|
| 153 | GLMoleculeObject_shape::~GLMoleculeObject_shape()
 | 
|---|
| 154 | {
 | 
|---|
| 155 | }
 | 
|---|
| 156 | 
 | 
|---|
| 157 | void GLMoleculeObject_shape::enable(bool enabled)
 | 
|---|
| 158 | {
 | 
|---|
| 159 |   m_enabled = enabled;
 | 
|---|
| 160 | }
 | 
|---|
| 161 | 
 | 
|---|
| 162 | 
 | 
|---|
| 163 | void GLMoleculeObject_shape::draw(QGLPainter *painter, const QVector4D &cameraPlane)
 | 
|---|
| 164 | {
 | 
|---|
| 165 |   if (!m_enabled)
 | 
|---|
| 166 |     return;
 | 
|---|
| 167 |   painter->modelViewMatrix().push();
 | 
|---|
| 168 | 
 | 
|---|
| 169 |   painter->setColor(m_material->diffuseColor());
 | 
|---|
| 170 |   painter->setFaceMaterial(QGL::AllFaces, m_material);
 | 
|---|
| 171 | 
 | 
|---|
| 172 |   // Draw the transparent cube.
 | 
|---|
| 173 |   painter->setStandardEffect(QGL::LitMaterial);
 | 
|---|
| 174 |   glCullFace(GL_BACK);
 | 
|---|
| 175 |   glEnable(GL_CULL_FACE);
 | 
|---|
| 176 |   glEnable(GL_BLEND);
 | 
|---|
| 177 |   glDepthMask(0);
 | 
|---|
| 178 |   glDisable(GL_DEPTH_TEST);
 | 
|---|
| 179 |   m_mesh[0]->draw(painter);
 | 
|---|
| 180 |   glEnable(GL_DEPTH_TEST);
 | 
|---|
| 181 |   glDepthMask(1);
 | 
|---|
| 182 |   glDisable(GL_BLEND);
 | 
|---|
| 183 |   glDisable(GL_CULL_FACE);
 | 
|---|
| 184 | 
 | 
|---|
| 185 | 
 | 
|---|
| 186 |   painter->modelViewMatrix().pop();
 | 
|---|
| 187 | }
 | 
|---|