TopologyPlugin.cc 33.8 KB
Newer Older
1
/*===========================================================================*\
Jan Möbius's avatar
Jan Möbius committed
2 3
*                                                                            *
*                              OpenFlipper                                   *
Martin Schultz's avatar
Martin Schultz committed
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 37 38
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
Jan Möbius's avatar
Jan Möbius committed
39
*                                                                            *
40 41
\*===========================================================================*/

Jan Möbius's avatar
 
Jan Möbius committed
42 43 44

#include "TopologyPlugin.hh"

Dirk Wilden's avatar
Dirk Wilden committed
45 46 47 48 49 50
#define EDGE_FLIP_POPUP "<B>Flip Edge</B><br>Rotate an edge"
#define EDGE_COLLAPSE_POPUP "<B>Collapse Edge</B><br>Collapse an edge into one of its vertices."
#define EDGE_SPLIT_POPUP "<B>Split Edge</B><br>Split an edge at the clicked point."
#define FACE_ADD_POPUP "<B>Add Face</B><br>Insert a face between clicked vertices."
#define FACE_SPLIT_POPUP "<B>Split Face</B><br>Split a face at a clicked point."
#define FACE_DELETE_POPUP "<B>Delete Face</B><br>Remove a clicked face."
Jan Möbius's avatar
 
Jan Möbius committed
51

52 53


Jan Möbius's avatar
Jan Möbius committed
54 55 56 57 58 59 60 61 62 63 64 65 66
//******************************************************************************

TopologyPlugin::TopologyPlugin() :
        toolbar_(0),
        edgeFlipAction_(0),
        edgeSplitAction_(0),
        edgeCollapseAction_(0),
        faceAddAction_(0),
        faceDeleteAction_(0),
        faceSplitAction_(0)
{

}
Dirk Wilden's avatar
Dirk Wilden committed
67 68 69 70

//******************************************************************************

/** \brief initialize the Plugin
71
 *
Dirk Wilden's avatar
Dirk Wilden committed
72
 */
Jan Möbius's avatar
 
Jan Möbius committed
73 74 75 76 77 78 79 80
void TopologyPlugin::pluginsInitialized() {
   emit addHiddenPickMode(EDGE_FLIP_POPUP);
   emit addHiddenPickMode(EDGE_SPLIT_POPUP);
   emit addHiddenPickMode(EDGE_COLLAPSE_POPUP);
   emit addHiddenPickMode(FACE_ADD_POPUP);
   emit addHiddenPickMode(FACE_SPLIT_POPUP);
   emit addHiddenPickMode(FACE_DELETE_POPUP);

Dirk Wilden's avatar
Dirk Wilden committed
81 82 83

  toolbar_ = new QToolBar("Topology");

Jan Möbius's avatar
 
Jan Möbius committed
84
  QActionGroup* group = new QActionGroup(0);
85 86 87

  QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();

88 89 90 91
  const QString baseHelpURL = "<a href='qthelp://org.openflipper.plugin-topology/Plugin-Topology/index.html";
  const QString clickText = tr("Click for more information</a>");


92 93 94
  edgeFlipAction_ = toolbar_->addAction( QIcon(iconPath + "topology-edgeFlip.png"), EDGE_FLIP_POPUP );
  edgeFlipAction_->setCheckable( true);
  edgeFlipAction_->setActionGroup(group);
95 96
  edgeFlipAction_->setWhatsThis(tr("Flip edge. ") + baseHelpURL+ "#flip_edge'>" + clickText);

97 98 99
  edgeSplitAction_ = toolbar_->addAction( QIcon(iconPath + "topology-edgeSplit.png"), EDGE_SPLIT_POPUP );
  edgeSplitAction_->setCheckable( true);
  edgeSplitAction_->setActionGroup(group);
100 101 102
  edgeSplitAction_->setWhatsThis(tr("Split edge. ") + baseHelpURL+ "#split_edge'>" + clickText);


103 104 105
  edgeCollapseAction_ = toolbar_->addAction( QIcon(iconPath + "topology-edgeCollapse.png"), EDGE_COLLAPSE_POPUP );
  edgeCollapseAction_->setCheckable( true);
  edgeCollapseAction_->setActionGroup(group);
106 107 108
  edgeCollapseAction_->setWhatsThis(tr("Collapse edge. ") + baseHelpURL+ "#collapse_edge'>" + clickText);


Dirk Wilden's avatar
Dirk Wilden committed
109
  toolbar_->addSeparator();
110 111 112
  faceAddAction_ = toolbar_->addAction( QIcon(iconPath + "topology-addFace.png"), FACE_ADD_POPUP );
  faceAddAction_->setCheckable( true);
  faceAddAction_->setActionGroup(group);
113 114 115
  faceAddAction_->setWhatsThis(tr("Add face.") + baseHelpURL+ "#add_face'>" + clickText);


116 117 118
  faceDeleteAction_ = toolbar_->addAction( QIcon(iconPath + "topology-deleteFace.png"), FACE_DELETE_POPUP );
  faceDeleteAction_->setCheckable( true);
  faceDeleteAction_->setActionGroup(group);
119 120 121
  faceDeleteAction_->setWhatsThis(tr("Delete face. ") + baseHelpURL+ "#delete_face'>" + clickText);


122 123 124
  faceSplitAction_ = toolbar_->addAction( QIcon(iconPath + "topology-splitFace.png"), FACE_SPLIT_POPUP );
  faceSplitAction_->setCheckable( true);
  faceSplitAction_->setActionGroup(group);
125
  faceSplitAction_->setWhatsThis(tr("Split face. ") + baseHelpURL+ "#split_face'>" + clickText);
Jan Möbius's avatar
 
Jan Möbius committed
126 127 128

  group->setExclusive(true);

Dirk Wilden's avatar
Dirk Wilden committed
129
  connect( toolbar_,  SIGNAL( actionTriggered(QAction*) ), this, SLOT( toolBarTriggered(QAction*) ));
Jan Möbius's avatar
 
Jan Möbius committed
130

Dirk Wilden's avatar
Dirk Wilden committed
131 132
  emit addToolbar( toolbar_ );
}
Jan Möbius's avatar
 
Jan Möbius committed
133 134


Dirk Wilden's avatar
Dirk Wilden committed
135
//******************************************************************************
Jan Möbius's avatar
 
Jan Möbius committed
136 137


Dirk Wilden's avatar
Dirk Wilden committed
138
/** \brief Toolbar action was triggered
139
 *
Dirk Wilden's avatar
Dirk Wilden committed
140 141 142
 * @param _action the action that was triggered
 */
void TopologyPlugin::toolBarTriggered(QAction* _action){
Jan Möbius's avatar
 
Jan Möbius committed
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
  if ( _action->text() == EDGE_FLIP_POPUP)
    PluginFunctions::pickMode(EDGE_FLIP_POPUP);
  else if ( _action->text() == EDGE_SPLIT_POPUP)
    PluginFunctions::pickMode(EDGE_SPLIT_POPUP);
  else if ( _action->text() == EDGE_COLLAPSE_POPUP)
    PluginFunctions::pickMode(EDGE_COLLAPSE_POPUP);
  else if ( _action->text() == FACE_ADD_POPUP)
    PluginFunctions::pickMode(FACE_ADD_POPUP);
  else if ( _action->text() == FACE_SPLIT_POPUP)
    PluginFunctions::pickMode(FACE_SPLIT_POPUP);
  else if ( _action->text() == FACE_DELETE_POPUP)
    PluginFunctions::pickMode(FACE_DELETE_POPUP);

  PluginFunctions::actionMode(Viewer::PickingMode);
}


160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
//******************************************************************************

/** \brief Toggle actions when the PickMode changes
 *
 * @param _mode the new PickMode
 */
void TopologyPlugin::slotPickModeChanged( const std::string& _mode) {

  edgeFlipAction_->setChecked(     _mode == EDGE_FLIP_POPUP );
  edgeSplitAction_->setChecked(    _mode == EDGE_SPLIT_POPUP );
  edgeCollapseAction_->setChecked( _mode == EDGE_COLLAPSE_POPUP );
  faceAddAction_->setChecked(      _mode == FACE_ADD_POPUP );
  faceDeleteAction_->setChecked(   _mode == FACE_DELETE_POPUP );
  faceSplitAction_->setChecked(    _mode == FACE_SPLIT_POPUP );
}

Dirk Wilden's avatar
Dirk Wilden committed
176
//******************************************************************************
Jan Möbius's avatar
 
Jan Möbius committed
177

Dirk Wilden's avatar
Dirk Wilden committed
178
/** \brief this is called when a mouse event occurred
179
 *
Dirk Wilden's avatar
Dirk Wilden committed
180 181
 * @param _event the event that occurred
 */
Jan Möbius's avatar
 
Jan Möbius committed
182 183 184 185 186 187 188 189 190 191 192 193
void TopologyPlugin::slotMouseEvent( QMouseEvent* _event ) {
    if ( _event->buttons() == Qt::RightButton )
      return;

   if ( PluginFunctions::pickMode() == EDGE_FLIP_POPUP ) { flip_edge(_event); } else
   if ( PluginFunctions::pickMode() == EDGE_COLLAPSE_POPUP ) { collapse_edge(_event); } else
   if ( PluginFunctions::pickMode() == EDGE_SPLIT_POPUP ) { split_edge(_event); } else
   if ( PluginFunctions::pickMode() == FACE_ADD_POPUP ) { add_face(_event); } else
   if ( PluginFunctions::pickMode() == FACE_SPLIT_POPUP ) { split_face(_event); } else
   if ( PluginFunctions::pickMode() == FACE_DELETE_POPUP ) { delete_face(_event); }
}

Dirk Wilden's avatar
Dirk Wilden committed
194 195 196 197

//******************************************************************************

/** \brief Deselect the vertices from AddFace mode
198
 *
Dirk Wilden's avatar
Dirk Wilden committed
199
 */
Jan Möbius's avatar
 
Jan Möbius committed
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
void TopologyPlugin::clearAddFaceVertices() {
  for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
    BaseObjectData* object;
    if ( ! PluginFunctions::getObject( addFaceVertices_[i].first , object ) )
      continue;

    if ( object->dataType(DATA_TRIANGLE_MESH) ) {
      TriMesh* m = PluginFunctions::triMesh(object);
      TriMesh::VertexHandle vh = m->vertex_handle( addFaceVertices_[i].second );
      if ( vh.is_valid()) {
        m->status(vh).set_selected(false);
      }
    }

    if ( object->dataType(DATA_POLY_MESH) ) {
      PolyMesh* m = PluginFunctions::polyMesh(object);
      PolyMesh::VertexHandle vh = m->vertex_handle( addFaceVertices_[i].second );
      if ( vh.is_valid()) {
        m->status(vh).set_selected(false);
      }
    }
Jan Möbius's avatar
Jan Möbius committed
221 222
    
    emit updatedObject(object->id(),UPDATE_SELECTION);
Jan Möbius's avatar
 
Jan Möbius committed
223 224 225 226 227 228
  }

  addFaceVertices_.clear();
  emit updateView();
}

Dirk Wilden's avatar
Dirk Wilden committed
229 230 231 232

//******************************************************************************

/** \brief Add a face
233
 *
Dirk Wilden's avatar
Dirk Wilden committed
234 235
 * @param _event mouse position where one of the vertices is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
236 237 238 239
void TopologyPlugin::add_face(QMouseEvent* _event) {
  if (( _event->type() != QEvent::MouseButtonPress) && (_event->type() != QEvent::MouseButtonDblClick))
    return;

240
  size_t           node_idx, target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
241 242 243 244 245 246 247 248 249 250 251 252 253
  ACG::Vec3d       hit_point;

  if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {

      BaseObjectData* object;
      if ( PluginFunctions::getPickedObject(node_idx, object) ) {

         //--- Add Face for TriMesh
         if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH) ) {
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);

            TriMesh::FaceVertexIter fv_it(m,fh);
Matthias Möller's avatar
Matthias Möller committed
254
            TriMesh::VertexHandle closest = *fv_it;
Jan Möbius's avatar
Jan Möbius committed
255
            float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
Jan Möbius's avatar
 
Jan Möbius committed
256 257

            ++fv_it;
Matthias Möller's avatar
Matthias Möller committed
258
            if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
259
               shortest_distance = (m.point(*fv_it) - hit_point).sqrnorm();
Matthias Möller's avatar
Matthias Möller committed
260
               closest = *fv_it;
Jan Möbius's avatar
 
Jan Möbius committed
261 262 263
            }

            ++fv_it;
Matthias Möller's avatar
Matthias Möller committed
264
            if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
Jan Möbius's avatar
Jan Möbius committed
265
               //shortest_distance = (m.point(*fv_it) - hit_point).sqrnorm();  Unnecessary. Not used anymore after this point
Matthias Möller's avatar
Matthias Möller committed
266
               closest = *fv_it;
Jan Möbius's avatar
 
Jan Möbius committed
267 268 269 270 271 272 273 274 275 276
            }


            std::pair<int,int> newVertex(object->id(), closest.idx() );

            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
              if ( ( addFaceVertices_[i].first  == newVertex.first  ) &&
                   ( addFaceVertices_[i].second == newVertex.second ) ) {
                addFaceVertices_.erase(addFaceVertices_.begin()+i);
                m.status(closest).set_selected(false);
277
                emit updatedObject(object->id(),UPDATE_SELECTION);
Jan Möbius's avatar
 
Jan Möbius committed
278 279 280 281 282 283 284 285 286 287 288
                emit updateView();
                return;
              }
            }

            // New Vertex so add it to the list
            addFaceVertices_.push_back( std::pair<int,int>(object->id(), closest.idx() ) );
            m.status(closest).set_selected(true);

            // We need 3 in the list to proceed
            if ( addFaceVertices_.size() < 3 ) {
289
              emit updatedObject(object->id(),UPDATE_SELECTION);
Jan Möbius's avatar
 
Jan Möbius committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
              emit updateView();
              return;
            }

            // check if the objects are of same type
            DataType dt = object->dataType();
            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
              BaseObjectData* tmpObject;
              if ( ! PluginFunctions::getObject( addFaceVertices_[i].first , tmpObject ) ) {
                emit log(LOGERR,"Unable to get object for adding face");
                clearAddFaceVertices();
                return;
              }

              if ( tmpObject->dataType() != dt ) {
                emit log(LOGERR,"Adding faces between different type of meshes is not supported!");
                clearAddFaceVertices();
                return;
              }
            }

            // check if we add a face between multiple objects
            ///@todo: Support adding faces between objects ( and merging them into one )
            int objectId = addFaceVertices_[0].first;
            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
              if ( addFaceVertices_[i].first != objectId ) {
                 emit log(LOGERR,"Adding faces between different objects!");
                 clearAddFaceVertices();
                 return;
              }
            }

            TriMesh::VertexHandle vh0 = m.vertex_handle( addFaceVertices_[0].second );
            TriMesh::VertexHandle vh1 = m.vertex_handle( addFaceVertices_[1].second );
            TriMesh::VertexHandle vh2 = m.vertex_handle( addFaceVertices_[2].second );

            // store state and disable output
            bool errlog = omerr().is_enabled();
            omerr().disable();

            fh = m.add_face(vh0,vh1,vh2);
            if ( !fh.is_valid() ) {
              fh = m.add_face(vh2,vh1,vh0);
            }
334 335 336
            
            emit updatedObject(object->id(),UPDATE_ALL);
            emit updateView();
Jan Möbius's avatar
 
Jan Möbius committed
337 338 339 340 341 342 343 344

            // reenable output if it was enabled
            if (errlog)
              omerr().enable();

            clearAddFaceVertices();

            if ( fh.is_valid() )
Dirk Wilden's avatar
Dirk Wilden committed
345
              emit createBackup(object->id(),"Add Face", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
            else
              emit log(LOGERR,"Unable to add face!");

         }

        //--- Add Face for PolyMesh
         if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH) ) {

            PolyMesh& m = *PluginFunctions::polyMesh(object);
            PolyMesh::FaceHandle fh = m.face_handle(target_idx);

            //find the closest vertex in the picked face
            PolyMesh::VertexHandle closest;
            float shortest_distance = FLT_MAX;

Matthias Möller's avatar
Matthias Möller committed
361 362
            for (PolyMesh::FaceVertexIter fv_it(m,fh); fv_it.is_valid(); ++fv_it){
              float distance = (m.point( *fv_it ) - hit_point).sqrnorm();
Jan Möbius's avatar
 
Jan Möbius committed
363 364 365

              if (distance < shortest_distance){
                shortest_distance = distance;
Matthias Möller's avatar
Matthias Möller committed
366
                closest = *fv_it;
Jan Möbius's avatar
 
Jan Möbius committed
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
              }
            }

            if (!closest.is_valid())
              return;

            if (_event->type() != QEvent::MouseButtonDblClick){

              std::pair<int,int> newVertex(object->id(), closest.idx() );

              for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
                if ( ( addFaceVertices_[i].first  == newVertex.first  ) &&
                      ( addFaceVertices_[i].second == newVertex.second ) ) {
                  addFaceVertices_.erase(addFaceVertices_.begin()+i);
                  m.status(closest).set_selected(false);
382
                  emit updatedObject(object->id(),UPDATE_SELECTION);
Jan Möbius's avatar
 
Jan Möbius committed
383 384 385 386 387 388 389 390 391 392 393 394
                  emit updateView();
                  return;
                }
              }

              // New Vertex so add it to the list
              addFaceVertices_.push_back( std::pair<int,int>(object->id(), closest.idx() ) );
              m.status(closest).set_selected(true);
            }

            // We need at least 3 in the list to proceed
            if ( (addFaceVertices_.size() < 3) || (_event->type() != QEvent::MouseButtonDblClick) ) {
395
              emit updatedObject(object->id(),UPDATE_SELECTION);
Jan Möbius's avatar
 
Jan Möbius committed
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
              emit updateView();
              return;
            }

            // check if the objects are of same type
            DataType dt = object->dataType();
            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
              BaseObjectData* tmpObject;
              if ( ! PluginFunctions::getObject( addFaceVertices_[i].first , tmpObject ) ) {
                emit log(LOGERR,"Unable to get object for adding face");
                clearAddFaceVertices();
                return;
              }

              if ( tmpObject->dataType() != dt ) {
                emit log(LOGERR,"Adding faces between different type of meshes is not supported!");
                clearAddFaceVertices();
                return;
              }
            }

            // check if we add a face between multiple objects
            ///@todo: Support adding faces between objects ( and merging them into one )
            int objectId = addFaceVertices_[0].first;
            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
              if ( addFaceVertices_[i].first != objectId ) {
                  emit log(LOGERR,"Adding faces between different objects!");
                  clearAddFaceVertices();
                  return;
              }
            }

            std::vector< PolyMesh::VertexHandle > vhs;
            for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i )
              vhs.push_back( m.vertex_handle( addFaceVertices_[i].second ) );

            // store state and disable output
            bool errlog = omerr().is_enabled();
            omerr().disable();

            fh = m.add_face(vhs);

            if (!fh.is_valid()){
              std::vector< PolyMesh::VertexHandle > rvhs;
              //reverse vector
              while (!vhs.empty()){
                rvhs.push_back( vhs.back() );
                vhs.pop_back();
              }
445
              
Jan Möbius's avatar
 
Jan Möbius committed
446
              fh = m.add_face(rvhs);
447
              
Jan Möbius's avatar
 
Jan Möbius committed
448
            }
449 450 451
            
            emit updatedObject(object->id(),UPDATE_ALL);
            emit updateView();
Jan Möbius's avatar
 
Jan Möbius committed
452 453 454 455 456 457 458 459

            // reenable output if it was enabled
            if (errlog)
              omerr().enable();

            clearAddFaceVertices();

            if ( fh.is_valid() )
Dirk Wilden's avatar
Dirk Wilden committed
460
              emit createBackup(object->id(),"Add Face", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
461 462 463 464 465 466 467 468
            else
              emit log(LOGERR,"Unable to add face!");

         }
      }
  }
}

Dirk Wilden's avatar
Dirk Wilden committed
469 470 471 472

//******************************************************************************

/** \brief Split a face at the given point
473
 *
Dirk Wilden's avatar
Dirk Wilden committed
474 475
 * @param _event mouse position where the face is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
476 477 478 479
void TopologyPlugin::split_face(QMouseEvent* _event) {
   if ( _event->type() != QEvent::MouseButtonPress )
      return;

480
   size_t           target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
481 482
   ACG::Vec3d       hit_point;

Jan Möbius's avatar
Jan Möbius committed
483
   BaseObjectData* object = 0;
484
   if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),object, target_idx, true, &hit_point)) {
Jan Möbius's avatar
 
Jan Möbius committed
485

486 487
       if ( object != 0 ) {
         if ( object->dataType(DATA_TRIANGLE_MESH) ) {
Jan Möbius's avatar
 
Jan Möbius committed
488 489 490
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);

Jan Möbius's avatar
Jan Möbius committed
491 492 493 494
            emit log(LOGOUT,"Picked Face " + QString::number(fh.idx()) + ", normal (" +
                                             QString::number(m.normal(fh)[0]) + "," +
                                             QString::number(m.normal(fh)[1]) + "," +
                                             QString::number(m.normal(fh)[2]) + ") ") ;
Jan Möbius's avatar
 
Jan Möbius committed
495 496 497

            TriMesh::VertexHandle vh = m.add_vertex(hit_point);
            m.split(fh,vh);
David Bommes's avatar
David Bommes committed
498
            m.garbage_collection();
Jan Möbius's avatar
 
Jan Möbius committed
499 500
            m.update_normals();

501
            emit updatedObject(object->id(), UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
502
            emit updateView();
Dirk Wilden's avatar
Dirk Wilden committed
503
            emit createBackup(object->id(),"Split Face", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
504 505
         }

506
         if ( object->dataType(DATA_POLY_MESH)  ) {
David Bommes's avatar
David Bommes committed
507 508 509
           PolyMesh& m = *PluginFunctions::polyMesh(object);
           PolyMesh::FaceHandle fh = m.face_handle(target_idx);

Jan Möbius's avatar
Jan Möbius committed
510 511 512 513
           emit log(LOGOUT,"Picked Face " + QString::number(fh.idx()) + ", normal (" +
                                            QString::number(m.normal(fh)[0]) + "," +
                                            QString::number(m.normal(fh)[1]) + "," +
                                            QString::number(m.normal(fh)[2]) + ") ") ;
David Bommes's avatar
David Bommes committed
514 515 516 517 518 519 520 521 522

           PolyMesh::VertexHandle vh = m.add_vertex(hit_point);
           m.split(fh,vh);
           m.garbage_collection();
           m.update_normals();

           emit updatedObject(object->id(), UPDATE_TOPOLOGY);
           emit updateView();
           emit createBackup(object->id(),"Split Face", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
523 524 525 526 527
         }
      } else return;
   }
}

Dirk Wilden's avatar
Dirk Wilden committed
528 529 530 531

//******************************************************************************

/** \brief Delete a face at the given position
532
 *
Dirk Wilden's avatar
Dirk Wilden committed
533 534
 * @param _event mouse position where the face is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
535 536 537 538
void TopologyPlugin::delete_face(QMouseEvent* _event) {
   if ( _event->type() != QEvent::MouseButtonPress )
      return;

539
   size_t           node_idx, target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
540 541 542 543 544 545 546 547 548
   ACG::Vec3d       hit_point;

   if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
      BaseObjectData* object;

      if ( PluginFunctions::getPickedObject(node_idx, object) ) {
         if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH)  ) {
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);
Jan Möbius's avatar
Jan Möbius committed
549 550 551 552
            emit log(LOGOUT,"Picked Face " + QString::number(fh.idx()) + ", normal (" +
                                             QString::number(m.normal(fh)[0]) + "," +
                                             QString::number(m.normal(fh)[1]) + "," +
                                             QString::number(m.normal(fh)[2]) + ") ") ;
Jan Möbius's avatar
 
Jan Möbius committed
553 554 555 556 557 558 559 560

            m.delete_face(fh);
            m.garbage_collection();
         }

         if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH)  ) {
            PolyMesh& m = *PluginFunctions::polyMesh(object);
            PolyMesh::FaceHandle fh = m.face_handle(target_idx);
Jan Möbius's avatar
Jan Möbius committed
561 562 563 564
            emit log(LOGOUT,"Picked Face " + QString::number(fh.idx()) + ", normal (" +
                                             QString::number(m.normal(fh)[0]) + "," +
                                             QString::number(m.normal(fh)[1]) + "," +
                                             QString::number(m.normal(fh)[2]) + ") ") ;
Jan Möbius's avatar
 
Jan Möbius committed
565 566 567 568 569

            m.delete_face(fh);
            m.garbage_collection();
         }

570
         emit updatedObject(object->id(), UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
571
         emit updateView();
Dirk Wilden's avatar
Dirk Wilden committed
572
         emit createBackup(object->id(),"Delete Face", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
573 574 575 576
      } else return;
   }
}

Dirk Wilden's avatar
Dirk Wilden committed
577 578 579 580

//******************************************************************************

/** \brief Flip an edge at the given position
581
 *
Dirk Wilden's avatar
Dirk Wilden committed
582 583
 * @param _event mouse position where the edge is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
584 585 586 587
void TopologyPlugin::flip_edge(QMouseEvent* _event) {
   if ( _event->type() != QEvent::MouseButtonPress )
      return;

588
   size_t           node_idx, target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
589 590 591 592 593 594 595 596 597 598
   ACG::Vec3d       hit_point;

   if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
      BaseObjectData* object;
      if ( PluginFunctions::getPickedObject(node_idx, object) ) {
         if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH)  ) {
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);

            TriMesh::FaceEdgeIter fe_it(m,fh);
Matthias Möller's avatar
Matthias Möller committed
599
            TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
600 601

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
602
            TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
603 604

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
605
            TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
606

607
            double min_dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e1 )), m.point(m.from_vertex_handle( e1 )));
Jan Möbius's avatar
 
Jan Möbius committed
608 609
            TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);

610 611 612
            double dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e2 )), m.point(m.from_vertex_handle( e2 )));
            if ( dist < min_dist ) {
               min_dist = dist;
Jan Möbius's avatar
 
Jan Möbius committed
613 614 615
               closest_edge = m.edge_handle(e2);
            }

616 617
            dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e3 )),m.point(m.from_vertex_handle( e3 )));
            if ( dist < min_dist) {
Jan Möbius's avatar
Jan Möbius committed
618
               // min_dist = dist; Unnecessary. Not used after this point
Jan Möbius's avatar
 
Jan Möbius committed
619 620 621 622 623 624 625 626 627 628
               closest_edge = m.edge_handle(e3);
            }

            if ( m.is_flip_ok(closest_edge) )
               m.flip(closest_edge);
            else
              emit log(LOGERR,"Flip is not allowed here!");

            emit log(LOGOUT,"Picked Edge " + QString::number(closest_edge.idx()));

629
            emit updatedObject(object->id(), UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
630
            emit updateView();
Dirk Wilden's avatar
Dirk Wilden committed
631
            emit createBackup(object->id(),"Edge Flip", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
632 633 634 635 636 637 638 639 640 641
         }

         if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH)  ) {
            emit log(LOGWARN,"Edge Flips not supported for Poly Meshes");
         }

      } else return;
   }
}

Dirk Wilden's avatar
Dirk Wilden committed
642 643 644 645

//******************************************************************************

/** \brief Collapse an edge at the given position
646
 *
Dirk Wilden's avatar
Dirk Wilden committed
647 648
 * @param _event mouse position where the edge is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
649 650 651 652
void TopologyPlugin::collapse_edge(QMouseEvent* _event) {
   if ( _event->type() != QEvent::MouseButtonPress )
      return;

653
   size_t           node_idx, target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
654 655 656 657 658 659 660 661 662 663
   ACG::Vec3d       hit_point;

   if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
      BaseObjectData* object;
      if ( PluginFunctions::getPickedObject(node_idx, object) ) {
         if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH)  ) {
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);

            TriMesh::FaceEdgeIter fe_it(m,fh);
Matthias Möller's avatar
Matthias Möller committed
664
            TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
665 666

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
667
            TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
668 669

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
670
            TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
671

672 673
            double min_dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e1 )), m.point(m.from_vertex_handle( e1 )));
            TriMesh::HalfedgeHandle closest_halfedge = e1;
Jan Möbius's avatar
 
Jan Möbius committed
674

675 676 677 678
            double dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e2 )), m.point(m.from_vertex_handle( e2 )));
            if ( dist < min_dist ) {
               min_dist = dist;
               closest_halfedge = e2;
Jan Möbius's avatar
 
Jan Möbius committed
679 680
            }

681 682
            dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e3 )),m.point(m.from_vertex_handle( e3 )));
            if ( dist < min_dist) {
Jan Möbius's avatar
Jan Möbius committed
683
               //min_dist = dist; Unnecessary. Not used after this point
684
               closest_halfedge = e3;
Jan Möbius's avatar
 
Jan Möbius committed
685 686 687
            }

            // collapse into to point which is closer to hitpoint
688 689
            TriMesh::Point to = m.point( m.to_vertex_handle(closest_halfedge) );
            TriMesh::Point from = m.point( m.from_vertex_handle(closest_halfedge) );
Jan Möbius's avatar
 
Jan Möbius committed
690 691

            if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
692
               closest_halfedge = m.opposite_halfedge_handle(closest_halfedge);
Jan Möbius's avatar
 
Jan Möbius committed
693

694
            if ( m.is_collapse_ok(closest_halfedge) ){
Jan Möbius's avatar
 
Jan Möbius committed
695
   //             m.point(m.to_vertex_handle(closest_edge)) = hit_point;
696
               m.collapse(closest_halfedge );
David Bommes's avatar
David Bommes committed
697
               m.garbage_collection();
Jan Möbius's avatar
 
Jan Möbius committed
698 699 700
            } else
              emit log(LOGERR,"Collapse is not allowed here!");

701
            emit log(LOGOUT,"Picked Edge " + QString::number(closest_halfedge.idx()));
Jan Möbius's avatar
 
Jan Möbius committed
702

703
            emit updatedObject(object->id(), UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
704
            emit updateView();
Dirk Wilden's avatar
Dirk Wilden committed
705
            emit createBackup(object->id(),"Edge Collapse", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
706 707
         }

David Bommes's avatar
David Bommes committed
708
         // Poly Meshes
Jan Möbius's avatar
 
Jan Möbius committed
709
         if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH)  ) {
David Bommes's avatar
David Bommes committed
710 711 712 713 714 715 716 717
           PolyMesh& m = *PluginFunctions::polyMesh(object);
           PolyMesh::FaceHandle fh = m.face_handle(target_idx);

           // find closest edge
           PolyMesh::HalfedgeHandle closest_edge(-1);
           double min_dist = FLT_MAX;

           PolyMesh::FaceEdgeIter fe_it(m,fh);
Matthias Möller's avatar
Matthias Möller committed
718
           for(; fe_it.is_valid(); ++fe_it)
David Bommes's avatar
David Bommes committed
719
           {
Matthias Möller's avatar
Matthias Möller committed
720
             PolyMesh::HalfedgeHandle heh = m.halfedge_handle(*fe_it,0);
David Bommes's avatar
David Bommes committed
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
             double dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( heh )), m.point(m.from_vertex_handle( heh )));

             if( dist < min_dist)
             {
               min_dist = dist;
               closest_edge = heh;
             }
           }

           // collapse into to point which is closer to hitpoint
           PolyMesh::Point to = m.point( m.to_vertex_handle(closest_edge) );
           PolyMesh::Point from = m.point( m.from_vertex_handle(closest_edge) );

           if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
              closest_edge = m.opposite_halfedge_handle(closest_edge);

//           if ( m.is_collapse_ok(closest_edge) ){
  //             m.point(m.to_vertex_handle(closest_edge)) = hit_point;
              m.collapse(closest_edge );
              m.garbage_collection();
//           } else
//             emit log(LOGERR,"Collapse is not allowed here!");

           emit log(LOGOUT,"Picked Edge " + QString::number(closest_edge.idx()));

           emit updatedObject(object->id(), UPDATE_TOPOLOGY);
           emit updateView();
           emit createBackup(object->id(),"Edge Collapse", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
749 750 751 752 753 754
         }

      } else return;
   }
}

Dirk Wilden's avatar
Dirk Wilden committed
755 756 757 758

//******************************************************************************

/** \brief Split an edge at the given position
759
 *
Dirk Wilden's avatar
Dirk Wilden committed
760 761
 * @param _event mouse position where the edge is picked
 */
Jan Möbius's avatar
 
Jan Möbius committed
762 763 764 765
void TopologyPlugin::split_edge(QMouseEvent* _event) {
   if ( _event->type() != QEvent::MouseButtonPress )
      return;

766
   size_t           node_idx, target_idx;
Jan Möbius's avatar
 
Jan Möbius committed
767 768 769 770 771 772 773 774 775 776
   ACG::Vec3d       hit_point;

   if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
      BaseObjectData* object;
      if ( PluginFunctions::getPickedObject(node_idx, object) ) {
         if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH)  ) {
            TriMesh& m = *PluginFunctions::triMesh(object);
            TriMesh::FaceHandle fh = m.face_handle(target_idx);

            TriMesh::FaceEdgeIter fe_it(m,fh);
Matthias Möller's avatar
Matthias Möller committed
777
            TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
778 779

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
780
            TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
781 782

            ++fe_it;
Matthias Möller's avatar
Matthias Möller committed
783
            TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
Jan Möbius's avatar
 
Jan Möbius committed
784

785
            double min_dist = ACG::Geometry::distPointLineSquared(hit_point,m.point(m.to_vertex_handle( e1 )), m.point(m.from_vertex_handle( e1 )));
Jan Möbius's avatar
 
Jan Möbius committed
786 787
            TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);

788 789 790 791 792 793 794
            double dist = ACG::Geometry::distPointLineSquared(
                     hit_point,
                     m.point(m.to_vertex_handle(e2)),
                     m.point(m.from_vertex_handle(e2)));

            if (dist < min_dist) {
               min_dist = dist;
Jan Möbius's avatar
 
Jan Möbius committed
795 796
               closest_edge = m.edge_handle(e2);
            }
797 798 799 800
            dist = ACG::Geometry::distPointLineSquared(
                     hit_point,
                     m.point(m.to_vertex_handle(e3)),
                     m.point(m.from_vertex_handle(e3)));
Jan Möbius's avatar
 
Jan Möbius committed
801

802
            if (dist < min_dist) {
Jan Möbius's avatar
Jan Möbius committed
803
               // min_dist = dist; Unnecessary. Not used after this point
Jan Möbius's avatar
 
Jan Möbius committed
804 805 806 807 808
               closest_edge = m.edge_handle(e3);
            }

            m.split(closest_edge,hit_point);

Jan Möbius's avatar
Jan Möbius committed
809
            emit log(LOGOUT,"Picked Edge " + QString::number(closest_edge.idx() ));
Jan Möbius's avatar
 
Jan Möbius committed
810

Mike Kremer's avatar
Mike Kremer committed
811
            emit updatedObject(object->id(), UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
812
            emit updateView();
Dirk Wilden's avatar
Dirk Wilden committed
813
            emit createBackup(object->id(),"Edge Split", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
814 815
         }
         if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH)  ) {
816 817 818
        	 PolyMesh& m = *PluginFunctions::polyMesh(object);
        	 PolyMesh::FaceHandle fh = m.face_handle(target_idx);

819
           PolyMesh::FaceHalfedgeIter fh_it(m,fh);
820 821 822

        	 std::vector<PolyMesh::HalfedgeHandle> halfEdgeHandles;
        	 //get all edges which belongs to the picked face
823
           for (;fh_it.is_valid(); ++fh_it)
824
        	 {
825
             halfEdgeHandles.push_back(*fh_it);
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
        	 }

        	 //search for the nearest edge
        	 PolyMesh::EdgeHandle closest_edge = m.edge_handle(*halfEdgeHandles.begin());
        	 double min_dist = ACG::Geometry::distPointLineSquared(hit_point, m.point(m.to_vertex_handle( *halfEdgeHandles.begin() )), m.point(m.from_vertex_handle( *halfEdgeHandles.begin() )));

        	 for (std::vector<PolyMesh::HalfedgeHandle>::iterator iter = halfEdgeHandles.begin(); iter != halfEdgeHandles.end(); ++iter)
        	 {
        		 double dist = ACG::Geometry::distPointLineSquared(hit_point, m.point(m.to_vertex_handle( *iter )), m.point(m.from_vertex_handle( *iter )));
        		 if (dist < min_dist)
        		 {
        			 closest_edge = m.edge_handle(*iter);
        			 min_dist = dist;
        		 }
        	 }

        	 m.split(closest_edge,hit_point);

Jan Möbius's avatar
Jan Möbius committed
844
        	 emit log(LOGOUT,"Picked Edge " + QString::number(closest_edge.idx()) );
845 846 847 848

        	 emit updatedObject(object->id(), UPDATE_TOPOLOGY);
        	 emit updateView();
        	 emit createBackup(object->id(),"Edge Split", UPDATE_TOPOLOGY);
Jan Möbius's avatar
 
Jan Möbius committed
849 850 851 852 853 854 855
         }

      } else return;
   }
}