MeshComparePlugin.cc 16.4 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
*      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen       *
*                           www.openflipper.org                              *
*                                                                            *
*--------------------------------------------------------------------------- *
*  This file is part of OpenFlipper.                                         *
*                                                                            *
*  OpenFlipper is free software: you can redistribute it and/or modify       *
*  it under the terms of the GNU Lesser General Public License as            *
*  published by the Free Software Foundation, either version 3 of            *
*  the License, or (at your option) any later version with the               *
*  following exceptions:                                                     *
*                                                                            *
*  If other files instantiate templates or use macros                        *
*  or inline functions from this file, or you compile this file and          *
*  link it with other files to produce an executable, this file does         *
*  not by itself cause the resulting executable to be covered by the         *
*  GNU Lesser General Public License. This exception does not however        *
*  invalidate any other reasons why the executable file might be             *
*  covered by the GNU Lesser General Public License.                         *
*                                                                            *
*  OpenFlipper is distributed in the hope that it will be useful,            *
*  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
*  GNU Lesser General Public License for more details.                       *
*                                                                            *
*  You should have received a copy of the GNU LesserGeneral Public           *
*  License along with OpenFlipper. If not,                                   *
*  see <http://www.gnu.org/licenses/>.                                       *
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
Jan Möbius's avatar
Jan Möbius committed
37
38
39
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
*                                                                            *
\*===========================================================================*/



#include "MeshComparePlugin.hh"


#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>

#include "OpenFlipper/BasePlugin/PluginFunctions.hh"

#include <OpenFlipper/common/bsp/TriangleBSPT.hh>
#include <ACG/Geometry/Algorithms.hh>
55
56
#include <ACG/Scenegraph/PointNode.hh>
#include <ACG/Utils/ColorCoder.hh>
57

58
59
60
MeshComparePlugin::MeshComparePlugin() :
  tool_(0),
  maximalDistance_(-1),
61
62
  maxNormalDeviation_(-1),
  maxGaussCurvatureDev_(-1)
63
64
65
66
67
68
69
70
71
72
73
{

}

MeshComparePlugin::~MeshComparePlugin()
{

}

void MeshComparePlugin::initializePlugin()
{
74
75
  if ( OpenFlipper::Options::gui()) {
    tool_ = new MeshCompareToolbarWidget();
76

77
    connect( tool_->compare, SIGNAL(clicked()), this, SLOT(compareButton()) );
78
    connect( tool_->clear, SIGNAL(clicked()), this, SLOT(slotClear()) );
79

80
81
82
    QIcon* toolIcon = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"MeshCompare.png");
    emit addToolbox( tr("Mesh Compare") , tool_ , toolIcon);
  }
83
84
85
86
}

void MeshComparePlugin::pluginsInitialized() {
    
87
88
89
  //===========================================================
  // Describe scrpting slots
  //===========================================================
90
91
92
93
94
95
  emit setSlotDescription(tr("compare(int,int)"), tr("Compare two meshes. Use lastMaximalDistance() and lastMaximalNormalDeviation() to get the results."),
      QStringList(tr("ObjectId,ObjectId")), QStringList(tr("Id of the reference mesh, Id of the comparison mesh")));
  emit setSlotDescription(tr("lastMaximalDistance()"), tr("Get the maximal distance between the meshes of the last comparison."),
      QStringList(tr("")), QStringList(tr("")));
  emit setSlotDescription(tr("lastMaximalNormalDeviation()"), tr("Get the maximal normal deviation in degree between the meshes of the last comparison."),
      QStringList(tr("")), QStringList(tr("")));
96
  emit setSlotDescription(tr("lastMaximalMeanCurvatureDeviation()"), tr("Get the maximal mean curvature deviation between the meshes of the last comparison."),
97
98
99
      QStringList(tr("")), QStringList(tr("")));
  emit setSlotDescription(tr("lastMaximalGaussCurvatureDeviation()"), tr("Get the maximal gauss curvature deviation between the meshes of the last comparison."),
      QStringList(tr("")), QStringList(tr("")));
100

101
  //===========================================================
102
  // Check mean curvature plugin and disable the box in gui mode
103
  //===========================================================
104
105
106
107
108
  bool meanCurvature = false;
  emit pluginExists( "meancurvature" , meanCurvature  );

  if ( OpenFlipper::Options::gui() && !meanCurvature )
    tool_->meanCurvature->setEnabled(false);
109
110
111
112
113
114
115
116
117

  //===========================================================
  // Check gauss curvature plugin and disable the box in gui mode
  //===========================================================
  bool gaussCurvature = false;
  emit pluginExists( "gausscurvature" , gaussCurvature  );

  if ( OpenFlipper::Options::gui() && !gaussCurvature )
    tool_->gaussCurvature->setEnabled(false);
118
119
}

120
void MeshComparePlugin::compareButton() {
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162

  // Get source and target objects
  BaseObjectData* targetObject = 0;
  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {

    if ( o_it->dataType(DATA_TRIANGLE_MESH)  || o_it->dataType(DATA_POLY_MESH) ) {

      // If we found a second target, something is wrong!
      if ( targetObject != 0 ) {
        emit log(LOGERR,tr("Please select one source and one target mesh to compare! Source will be the reference mesh."));
        return;
      }

      targetObject = (*o_it);
    }
  }

  BaseObjectData* sourceObject = 0;
  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::SOURCE_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {

    if ( o_it->dataType(DATA_TRIANGLE_MESH)  || o_it->dataType(DATA_POLY_MESH) ) {

      // If we found a second target, something is wrong!
      if ( sourceObject != 0 ) {
        emit log(LOGERR,tr("Please select one source and one target mesh to compare! Source will be the reference mesh."));
        return;
      }

      sourceObject = (*o_it);
    }
  }


  if ( (targetObject != 0) && (sourceObject != 0)  ) {
    compare(sourceObject->id(),targetObject->id());
  } else {
    emit log(LOGERR,tr("Please select one source and one target mesh to compare! Source will be the reference mesh."));
  }


}

163
164
165
166
167
168
169
170
171
172
173
174
175
176
void MeshComparePlugin::slotObjectUpdated( int _identifier, const UpdateType& _type ) {
  // Get source and target objects
  BaseObjectData* object = 0;

  PluginFunctions::getObject(_identifier,object);

  if ( object ) {
    ACG::SceneGraph::MaterialNode *pMatNode = 0;
    if ( object->getAdditionalNode(pMatNode,name(), "MeshCompareDistanceMaterial" ) )
      object->removeAdditionalNode(pMatNode,name(),"MeshCompareDistanceMaterial");
  }

}

177
178
179
180
181
182
183
184
185
186
187
188
void MeshComparePlugin::slotClear() {

  for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS) ; o_it != PluginFunctions::objectsEnd(); ++o_it) {

    ACG::SceneGraph::MaterialNode *pMatNode = 0;
    if ( o_it->getAdditionalNode(pMatNode,name(), "MeshCompareDistanceMaterial" ) )
      o_it->removeAdditionalNode(pMatNode,name(),"MeshCompareDistanceMaterial");

  }

}

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
void MeshComparePlugin::compare(int _sourceId,int _targetId) {


  TriMeshObject* source = PluginFunctions::triMeshObject(_sourceId);
  TriMeshObject* target = PluginFunctions::triMeshObject(_targetId);

  if ( (target == 0 ) || (source == 0) ) {
    emit log(LOGERR,tr("Please select one source and one target mesh to compare! Source will be the reference mesh."));
    emit log(LOGERR,tr("Only triangle meshes are currently supported!"));
    return;
  }

  TriMesh* refMesh  = PluginFunctions::triMesh(_sourceId);
  TriMesh* compMesh = PluginFunctions::triMesh(_targetId);

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  ACG::SceneGraph::PointNode *pNode = 0;


  // Check if we already attached a PointNode
  if ( OpenFlipper::Options::gui() ) {

    if ( !target->getAdditionalNode(pNode,name(), "MeshCompareDistance" ) ) {

      ACG::SceneGraph::MaterialNode *pMatNode = 0;
      pMatNode = new ACG::SceneGraph::MaterialNode(target->manipulatorNode(), "MeshCompare distance visualization material");
      target->addAdditionalNode(pMatNode, name(), "MeshCompareDistanceMaterial");
      pMatNode->set_point_size(5);
      pMatNode->applyProperties(ACG::SceneGraph::MaterialNode::PointSize);

      pNode = new ACG::SceneGraph::PointNode(pMatNode, "MeshCompare distance visualization");
      pNode->drawMode(ACG::SceneGraph::DrawModes::POINTS_COLORED);
      target->addAdditionalNode(pNode, name(), "MeshCompareDistance");
    }
222

223
224
225
    // Clear but reserve memory for the required vertices
    pNode->clear();
    pNode->reserve(refMesh->n_vertices(),refMesh->n_vertices(),refMesh->n_vertices() );
226
227
  }

228
229
230
231
  // Get a bsp for the target, as we will project the reference mesh onto the target mesh.
  // It will be build automatically at this point.
  TriMeshObject::OMTriangleBSP* compBSP = target->requestTriangleBsp();

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  // ================================================================
  // Compute mean curvature on both meshes ( if plugin is available )
  // ================================================================
  bool meanCurvature = false;
  emit pluginExists( "meancurvature" , meanCurvature  );

  //
  if ( meanCurvature ) {
    RPC::callFunction("meancurvature","computeMeanCurvature",_sourceId);
    RPC::callFunction("meancurvature","computeMeanCurvature",_targetId);
  }

  OpenMesh::VPropHandleT< double > meanRef;
  OpenMesh::VPropHandleT< double > meanComp;

  if( meanCurvature &&
248
     ((!refMesh->get_property_handle(  meanRef , "Mean Curvature") ) ||
249
250
251
252
      (!compMesh->get_property_handle( meanComp, "Mean Curvature") ))) {
    meanCurvature = false;
  }

253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  // ================================================================
  // Compute mean curvature on both meshes ( if plugin is available )
  // ================================================================
  bool gaussCurvature = false;
  emit pluginExists( "gausscurvature" , gaussCurvature  );

  //
  if ( gaussCurvature ) {
    RPC::callFunction("gausscurvature","computeGaussCurvature",_sourceId);
    RPC::callFunction("gausscurvature","computeGaussCurvature",_targetId);
  }

  OpenMesh::VPropHandleT< double > gaussRef;
  OpenMesh::VPropHandleT< double > gaussComp;

  if( gaussCurvature &&
     ((!refMesh->get_property_handle(  gaussRef , "Gaussian Curvature") ) ||
      (!compMesh->get_property_handle( gaussComp, "Gaussian Curvature") ))) {
    gaussCurvature = false;
  }


275
276

  // ================================================================
277
  // Remember the maximal values as output and for specifying color coding range
278
  // ================================================================
279
280
281
282
  maximalDistance_      = -1.0;
  maxNormalDeviation_   = -1.0;
  maxMeanCurvatureDev_  = -1.0;
  maxGaussCurvatureDev_ = -1.0;
283
284
285
286
287


  // Remember distances for colorCoding after we know the maximal distance
  std::vector<double> distances;
  std::vector<double> normalAngles;
288
  std::vector<double> meanCurvatures;
289
  std::vector<double> gaussCurvatures;
290
291
292
293
294
295
296

  for ( TriMesh::VertexIter v_it = refMesh->vertices_begin() ; v_it != refMesh->vertices_end(); ++ v_it) {

    TriMeshObject::OMTriangleBSP::NearestNeighbor nearest = compBSP->nearest( refMesh->point(v_it) );
    TriMesh::FaceHandle closestFace = nearest.handle;

    // Remember the maximal distance between the meshes
297
298
    if ( nearest.dist > maximalDistance_ )
      maximalDistance_ = nearest.dist;
299

300
301
    // Remember distance for color coding
    distances.push_back(nearest.dist);
302
303
304
305

    // Get the vertices around that face and their properties
    TriMesh::CFVIter        fv_it = compMesh->cfv_iter(closestFace);

306
307
308
    const TriMesh::Point&        p0    = compMesh->point(fv_it);
    const TriMesh::Normal        n0    = compMesh->normal(fv_it);
    const TriMesh::VertexHandle& v0    = fv_it.handle();
309

310
311
312
    const TriMesh::Point&        p1    = compMesh->point(++fv_it);
    const TriMesh::Normal        n1    = compMesh->normal(fv_it);
    const TriMesh::VertexHandle& v1    = fv_it.handle();
313

314
315
316
    const TriMesh::Point&        p2    = compMesh->point(++fv_it);
    const TriMesh::Normal        n2    = compMesh->normal(fv_it);
    const TriMesh::VertexHandle& v2    = fv_it.handle();
317
318
319
320
321

    // project original point to current mesh
    TriMesh::Point projectedPoint;
    ACG::Geometry::distPointTriangle(refMesh->point(v_it), p0, p1, p2, projectedPoint);

322
323
324
325
    // Add the position to the point node
    if (pNode)
      pNode->add_point(projectedPoint);

326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
    // compute Barycentric coordinates
    ACG::Geometry::baryCoord(projectedPoint, p0, p1, p2, projectedPoint);

    // interpolate normal on the compare mesh at the projected point via barycentric coordinates.
    TriMesh::Normal normal;
    normal  = n0 * projectedPoint[0];
    normal += n1 * projectedPoint[1];
    normal += n2 * projectedPoint[2];
    normal.normalize();

    // Compute normal deviation in degrees
    double normalDeviation = (refMesh->normal(v_it) | normal);

    if (normalDeviation < -1.0)
      normalDeviation = -1.0;
    else if (normalDeviation > 1.0)
      normalDeviation = 1.0;

    normalDeviation = 180.0 / M_PI * acos(normalDeviation);

346
347
    // Remember normal deviation for color coding
    normalAngles.push_back(normalDeviation);
348

349
350
    if (normalDeviation > maxNormalDeviation_)
      maxNormalDeviation_ = normalDeviation;
351

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

    if (meanCurvature) {

      TriMesh::Scalar curvature = 0.0;
      curvature  = compMesh->property(meanComp,v0) * projectedPoint[0];
      curvature += compMesh->property(meanComp,v1) * projectedPoint[1];
      curvature += compMesh->property(meanComp,v2) * projectedPoint[2];

      const double curvatureDev = fabs( refMesh->property(meanRef,v_it) - curvature );

      meanCurvatures.push_back( curvatureDev );

      if ( curvatureDev > maxMeanCurvatureDev_ )
        maxMeanCurvatureDev_ = curvatureDev;

    }

369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    if (gaussCurvature) {

          TriMesh::Scalar curvature = 0.0;
          curvature  = compMesh->property(gaussComp,v0) * projectedPoint[0];
          curvature += compMesh->property(gaussComp,v1) * projectedPoint[1];
          curvature += compMesh->property(gaussComp,v2) * projectedPoint[2];

          const double curvatureDev = fabs( refMesh->property(gaussRef,v_it) - curvature );

          gaussCurvatures.push_back( curvatureDev );

          if ( curvatureDev > maxGaussCurvatureDev_ )
            maxGaussCurvatureDev_ = curvatureDev;

        }

385
386
  }

387
388
389
390
391
392
393
394
395
  // Generate the colors
  if ( pNode ) {

    if ( tool_->distance->isChecked() ) {
      ACG::ColorCoder cCoder(0,maximalDistance_);

      for ( unsigned int i = 0 ; i < distances.size() ; ++i) {
        pNode->add_color(cCoder.color_float4(distances[i]));
      }
396
    } else if ( tool_->normalAngle->isChecked() ) {
397
398
399
400
401
      ACG::ColorCoder cCoder(0,maxNormalDeviation_);

      for ( unsigned int i = 0 ; i < normalAngles.size() ; ++i) {
        pNode->add_color(cCoder.color_float4(normalAngles[i]));
      }
402
403
404
405
406
407
408
    } else if ( tool_->meanCurvature->isChecked() ) {
      ACG::ColorCoder cCoder(0,maxMeanCurvatureDev_);

      for ( unsigned int i = 0 ; i < meanCurvatures.size() ; ++i) {
        pNode->add_color(cCoder.color_float4(meanCurvatures[i]));
      }

409
410
411
412
413
414
415
    } else if ( tool_->gaussCurvature->isChecked() ) {
      ACG::ColorCoder cCoder(0,maxGaussCurvatureDev_);

      for ( unsigned int i = 0 ; i < gaussCurvatures.size() ; ++i) {
        pNode->add_color(cCoder.color_float4(gaussCurvatures[i]));
      }

416
417
    }

418
419


420
421
    emit updateView();
  }
422
423
424
425
426
427

}


Q_EXPORT_PLUGIN2( meshcompareplugin , MeshComparePlugin );