/CGAL-4.0.2/demo/Triangulation_3/Viewer.cpp

# · C++ · 1298 lines · 886 code · 151 blank · 261 comment · 297 complexity · 1815f5b15f638176a8aac3c816ce439f MD5 · raw file

  1. #include "Viewer.h"
  2. #include <CGAL/glu.h>
  3. using namespace std;
  4. #include "Viewer.moc" // .moc will be the output from moc preprocessor
  5. void Viewer::init()
  6. {
  7. /* Initial timer for playing incremental construction */
  8. m_pTimer = new QTimer(this);
  9. connect(m_pTimer, SIGNAL(timeout()), this, SLOT(incremental_insert()));
  10. /* Scene inits */
  11. setBackgroundColor(::Qt::white);
  12. // scene are defined by a sphere of 2.0, camera at the center, i.e. (0, 0, 0)
  13. setSceneCenter( qglviewer::Vec(-0.,-0.,-0.) );
  14. setSceneRadius( 2. );
  15. // show text message
  16. setTextIsEnabled(true);
  17. setForegroundColor(::Qt::red);
  18. setFont(QFont("Arial Black", 16, QFont::Bold));
  19. /* OpenGL inits */
  20. // Increase the material shininess, so that the difference between
  21. // the two versions of the spiral is more visible.
  22. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 50.0);
  23. GLfloat specular_color[4] = { 0.8f, 0.8f, 0.8f, 1.0 };
  24. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular_color);
  25. // Set Smooth Shading
  26. ::glShadeModel(GL_SMOOTH);
  27. // depth buffer setup
  28. ::glClearDepth(1.0f);
  29. ::glEnable(GL_DEPTH_TEST);
  30. ::glDepthFunc(GL_LEQUAL);
  31. ::glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  32. // enable semi-transparent culling planes
  33. ::glEnable(GL_BLEND);
  34. ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  35. // anti-aliasing, i.e. reduce jaggedness (if the OpenGL driver permits that)
  36. ::glEnable(GL_POINT_SMOOTH);
  37. ::glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  38. ::glEnable(GL_LINE_SMOOTH);
  39. ::glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  40. /* Add mouse and key description */
  41. setKeyDescription( Qt::CTRL + Qt::Key_G, tr("Generate points") );
  42. setKeyDescription( Qt::CTRL + Qt::Key_O, tr("Load points") );
  43. setKeyDescription( Qt::CTRL + Qt::Key_S, tr("Save points") );
  44. setKeyDescription( Qt::CTRL + Qt::Key_Comma, tr("Preference") );
  45. setKeyDescription( Qt::CTRL + Qt::Key_H, tr("Hide Kernel Demo") );
  46. setKeyDescription( Qt::CTRL + Qt::Key_Q, tr("Quit Kernel Demo") );
  47. setKeyDescription( Qt::Key_Return,
  48. tr("Insert new point to triangulation in <u>Input-Point</u> mode") );
  49. setKeyDescription( Qt::Key_Escape,
  50. tr("Cancel insertion in <u>Input-Point</u> mode;<br>")
  51. + tr("Cancel current selection in <u>Select</u> mode") );
  52. setKeyDescription( Qt::Key_Delete, tr("Delete selected vertices in <u>Select</u> mode") );
  53. setMouseBindingDescription( Qt::LeftButton,
  54. tr("Hold to move new point in <u>Input-Point</u> mode;<br>")
  55. + tr("Hold to move a vertex in <u>Move</u> mode") );
  56. setMouseBindingDescription( Qt::SHIFT + Qt::LeftButton,
  57. tr("Click to insert a vertex in <u>Input-Vertex</u> mode;<br>")
  58. + tr("Click to insert a point in <u>Input-Point</u> mode;<br>")
  59. + tr("Click or Drag to select multiple points in <u>Select</u> mode;<br>")
  60. + tr("Click to place a query point in <u>Find-Nearest-Neighbor</u> mode;<br>")
  61. + tr("Click to place a query point in <u>Show-Empty-Sphere</u> mode") );
  62. setMouseBindingDescription( Qt::CTRL + Qt::LeftButton,
  63. tr("Drag to add vertices to current selection in <u>Select</u> mode") );
  64. }
  65. QString Viewer::helpString() const
  66. {
  67. QString text("<h1>3D Triangulation Demo</h1>");
  68. text += "This example illustrates a generic interactive demo for 3D Triangulation in CGAL. ";
  69. text += "This demo could be used as a simple skeleton ";
  70. text += "for potential demos of other 3D packages or for teaching CGAL.<br><br>";
  71. text += "The key feature is to edit vertices/points with mouse.";
  72. text += "There are several modes:<br><br>";
  73. text += " - <u>Normal Mode</u>: ";
  74. text += "Rotate, zoom, or translate camera using mouse.<br>";
  75. text += " - <u>Insert Vertex</u>: ";
  76. text += "Insert a vertex on the surface of the trackball ";
  77. text += "and the triangulation will be updated correspondingly.<br>";
  78. text += " - <u>Insert Point</u>: ";
  79. text += "Insert a point on the surface of the trackball. ";
  80. text += "Its conflict region will be highlighted. ";
  81. text += "When the new point is moving, ";
  82. text += "its conflict region will be updated correspondingly.<br>";
  83. text += " - <u>Select</u>: ";
  84. text += "Click or drag mouse left button to select multiple points.<br>";
  85. text += " - <u>Move</u>: Hold mouse left button to move a vertex ";
  86. text += "and the triangulation will be updated correspondingly.<br>";
  87. text += " - <u>Find Nearest Neighbor</u>: ";
  88. text += "Place a query point and its nearest neighbor will be highlighted.<br>";
  89. text += " - <u>Show Empty Sphere</u>: ";
  90. text += "Place a query point, locate the point in a cell ";
  91. text += "and then show the empty sphere of that cell. ";
  92. text += "An empty sphere of a cell is a sphere ";
  93. text += "with all four vertices of the cell lying on it ";
  94. text += "and no other vertices inside it.<br><br>";
  95. text += "<b>Shift+Wheel</b> to resize the trackball when it exists. ";
  96. text += "See <b>Mouse</b> page for more details.<br><br>";
  97. text += "Other basic features include:<br>";
  98. text += " - Randomly generate points,<br>";
  99. text += " - Read/Write files,<br>";
  100. text += " - Show vertices, Voronoi edges, Delaunay edges, and/or facets,<br>";
  101. text += " - Incremental Construct: ";
  102. text += "Re-construct the current triangulation incrementally. ";
  103. text += "If no triangulation exists yet, randomly generate 100 points ";
  104. text += "and construct a Delaunay triangulation of those points.<br>";
  105. return text;
  106. }
  107. /*************************************************************/
  108. /* Draw functions */
  109. void Viewer::draw()
  110. {
  111. if( m_pScene == NULL ) return;
  112. QFont fontPrompt("Arial", 14);
  113. if( m_showAxis ) {
  114. qglColor(::Qt::black);
  115. drawAxis( sceneRadius() );
  116. }
  117. /* Draw vertices */
  118. if ( m_showVertex && m_pScene->m_dt.number_of_vertices()>0 ) {
  119. for(QList<Vertex_handle>::iterator vit = m_pScene->m_vhArray.begin();
  120. vit < m_pScene->m_vhArray.end(); ++vit) {
  121. if( m_curMode == SELECT && (*vit)->isSeled() ) continue;
  122. if( (*vit) == m_nearestNb ) continue;
  123. drawVertex( (*vit)->point(), m_colorVertex, m_fSizeVertex );
  124. }//end-for-points
  125. }//end-if-points
  126. /* Draw all points during incremental mode */
  127. if( !m_incrementalPts.isEmpty() ) {
  128. /* draw the rest to-be-inserted vertices */
  129. for(QList<Point_3>::iterator pit=m_incrementalPts.begin();
  130. pit < m_incrementalPts.end(); ++pit) {
  131. drawVertex( (*pit), ::Qt::gray, m_fSizeVertex );
  132. }
  133. switch( m_curStep ) {
  134. case NEWPT:
  135. /* Show prompt messages */
  136. qglColor( ::Qt::black );
  137. drawText( 10, 20, tr("Highlight the next-to-insert point"), fontPrompt );
  138. /* Highlight the next-to-insert point */
  139. drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex );
  140. break;
  141. case CELL: // show the tetrahedron that contains the point
  142. /* Show prompt messages */
  143. qglColor( ::Qt::black );
  144. drawText( 10, 20, tr("Show the tetrahedron containing the point"), fontPrompt );
  145. drawText( 10, 40, tr("(Only finite facets are drawn)"), fontPrompt );
  146. /* Highlight the next-to-insert vertex */
  147. drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex );
  148. /* Draw the cell containing that point */
  149. for(int i=0; i<4; ++i) {
  150. if( m_pScene->m_dt.is_infinite(m_cellContain, i) ) continue;
  151. drawFacet( m_pScene->m_dt.triangle( m_cellContain, i ), m_colorFacet );
  152. }//end-for-facets
  153. break;
  154. case CONFLICT: // show the conflict region
  155. /* Show prompt messages */
  156. qglColor( ::Qt::black );
  157. drawText( 10, 20, tr("Show the conflict region"), fontPrompt );
  158. /* Highlight the next-to-insert vertex */
  159. drawVertex( m_curIncPt, ::Qt::red, m_fSizeVertex );
  160. /* Draw conflict region */
  161. for(QList<Facet>::iterator fit = m_boundaryFacets.begin();
  162. fit < m_boundaryFacets.end(); ++fit) {
  163. if( m_pScene->m_dt.is_infinite(*fit) ) continue;
  164. drawFacet( m_pScene->m_dt.triangle(*fit), QColor(215, 80, 0, 96) ); //semi-transparent purple
  165. }//end-for-facets
  166. break;
  167. default:
  168. break;
  169. }//end-of=switch
  170. }//end-if-incpts
  171. /* Draw Delaunay edges */
  172. if( m_showDEdge ) {
  173. for(edges_iterator eit = m_pScene->m_dt.finite_edges_begin();
  174. eit != m_pScene->m_dt.finite_edges_end(); ++eit) {
  175. Segment_3 seg = m_pScene->m_dt.segment(*eit);
  176. drawEdge( seg.vertex(0), seg.vertex(1), m_colorDEdge, m_fSizeDEdge );
  177. }//end-for-edges
  178. }//end-if-dt
  179. /* Draw Voronoi edges */
  180. if( m_showVEdge ) {
  181. for(facets_iterator fit = m_pScene->m_dt.finite_facets_begin();
  182. fit != m_pScene->m_dt.finite_facets_end(); ++fit) {
  183. Object_3 o = m_pScene->m_dt.dual(*fit);
  184. if (const Segment_3 *s = CGAL::object_cast<Segment_3>(&o)) {
  185. drawEdge( s->vertex(0), s->vertex(1), m_colorVEdge, m_fSizeVEdge );
  186. } else if (const Ray_3 *r = CGAL::object_cast<Ray_3>(&o)) {
  187. drawEdge( r->point(0), // the source of the ray
  188. r->point(1), // another point on the ray, different from the source
  189. m_colorVEdge, m_fSizeVEdge );
  190. }
  191. }//end-for-edges
  192. }//end-if-vd
  193. /* Draw facets */
  194. if( m_showFacet ) {
  195. for(facets_iterator fit = m_pScene->m_dt.finite_facets_begin();
  196. fit != m_pScene->m_dt.finite_facets_end(); ++fit) {
  197. drawFacet( m_pScene->m_dt.triangle(*fit), m_colorFacet );
  198. }//end-for-facets
  199. }//end-if-facets
  200. /* Insert vertex mode */
  201. if( m_curMode == INSERT_V ) {
  202. /* Show prompt messages */
  203. qglColor( ::Qt::black );
  204. drawText( width()-200, 20, tr("Shift+Left: Insert a vertex"), fontPrompt );
  205. drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt );
  206. /* Draw the trackball */
  207. drawSphere( m_fRadius, m_colorTrackball );
  208. }//end-if-insv
  209. /* Insert point mode */
  210. else if( m_curMode == INSERT_PT ) {
  211. /* Show prompt messages */
  212. qglColor( ::Qt::black );
  213. drawText( width()-200, 20, tr("Shift+Left: Insert a point"), fontPrompt );
  214. drawText( width()-200, 40, tr("Hold Left: Move the point"), fontPrompt );
  215. drawText( width()-200, 60, tr("Return: Insert to DT"), fontPrompt );
  216. drawText( width()-200, 80, tr("Escape: Cancel insertion"), fontPrompt );
  217. drawText( width()-200, 100, tr("Shift+Wheel: Resize trackball"), fontPrompt );
  218. /* Draw the trackball */
  219. drawSphere( m_fRadius, m_colorTrackball );
  220. if( m_hasNewPt ) {
  221. /* Draw the newly inserted point */
  222. drawVertex( m_newPt, ::Qt::red, m_fSizeVertex );
  223. /* Draw conflict region */
  224. for(QList<Facet>::iterator fit = m_boundaryFacets.begin();
  225. fit < m_boundaryFacets.end(); ++fit) {
  226. if( m_pScene->m_dt.is_infinite(*fit) ) continue;
  227. drawFacet( m_pScene->m_dt.triangle(*fit), QColor(215, 80, 0, 96) ); //semi-transparent purple
  228. }//end-for-facets
  229. }//end-if-shown
  230. }//end-if-inspt
  231. /* Select mode */
  232. else if( m_curMode == SELECT) {
  233. /* Show prompt messages */
  234. qglColor( ::Qt::black );
  235. drawText( width()-200, 20, tr("Shift+Left: Select"), fontPrompt );
  236. drawText( width()-200, 40, tr("Ctrl+Left: Add selection"),
  237. QFont("Arial", 14) );
  238. drawText( width()-200, 60, tr("Escape: Cancel selection"), fontPrompt );
  239. drawText( width()-200, 80, tr("DEL: Delete selected"), fontPrompt );
  240. /* Highlight the selected vertices */
  241. for(QList<int>::iterator vit=m_vidSeled.begin(); vit<m_vidSeled.end(); ++vit) {
  242. drawVertex( m_pScene->m_vhArray.at(*vit)->point(), ::Qt::red, m_fSizeVertex );
  243. }//end-for-seledpts
  244. /* Draw the multiple selection window */
  245. if( m_isPress ) {
  246. ::glDisable( GL_LIGHTING );
  247. startScreenCoordinatesSystem();
  248. qglColor( QColor(80, 180, 180, 64) );
  249. ::glBegin(GL_QUADS);
  250. ::glVertex2i(m_rectSel.left(), m_rectSel.top());
  251. ::glVertex2i(m_rectSel.right(), m_rectSel.top());
  252. ::glVertex2i(m_rectSel.right(), m_rectSel.bottom());
  253. ::glVertex2i(m_rectSel.left(), m_rectSel.bottom());
  254. ::glEnd();
  255. stopScreenCoordinatesSystem();
  256. ::glEnable( GL_LIGHTING );
  257. }//end-if-press
  258. }//end-if-sel
  259. /* Move mode */
  260. else if( m_curMode == MOVE ) {
  261. /* Show prompt messages */
  262. qglColor( ::Qt::black );
  263. drawText( width()-200, 20, tr("Left Click: Select"), fontPrompt );
  264. if( m_isMoving ) {
  265. drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt );
  266. /* Draw the trackball */
  267. drawSphere( m_fRadius, m_colorTrackball );
  268. /* Highlight the moving point */
  269. drawVertex( m_pScene->m_vhArray.at( m_vidMoving )->point(), ::Qt::red, m_fSizeVertex );
  270. }//end-if-v
  271. }//end-if-move
  272. /* FindNb mode */
  273. else if( m_curMode == FINDNB ) {
  274. /* Show prompt messages */
  275. qglColor( ::Qt::black );
  276. drawText( width()-200, 20, tr("Shift+Left: Place query point"), fontPrompt );
  277. drawText( width()-200, 40, tr("Shift+Wheel: Resize trackball"), fontPrompt );
  278. /* Draw the trackball */
  279. drawSphere( m_fRadius, m_colorTrackball );
  280. /* Draw the nearest neighbor */
  281. if( m_nearestNb != NULL ) {
  282. drawVertex( m_queryPt, ::Qt::red, m_fSizeVertex );
  283. drawVertex( m_nearestNb->point(), ::Qt::red, m_fSizeVertex );
  284. }
  285. }//end-if-findnb
  286. /* EmptySphere mode */
  287. else if( m_curMode == EMPTYSPH ) {
  288. /* Show prompt messages */
  289. qglColor( ::Qt::black );
  290. drawText( width()-200, 20, tr("Shift+Left: Place query point"), fontPrompt );
  291. drawText( width()-200, 40, tr("Press S: Show/Hide trackball"), fontPrompt );
  292. drawText( width()-200, 60, tr("Shift+Wheel: Resize trackball"), fontPrompt );
  293. /* Draw the trackball */
  294. if( m_showTrackball )
  295. drawSphere( m_fRadius, m_colorTrackball );
  296. if( m_hasEmptyS ) {
  297. /* Draw the query point */
  298. drawVertex( m_queryPt, ::Qt::red, m_fSizeVertex );
  299. /* Draw the cell containing that point */
  300. for(int i=0; i<4; ++i) {
  301. if( m_pScene->m_dt.is_infinite(m_cellContain, i) ) continue;
  302. drawFacet( m_pScene->m_dt.triangle( m_cellContain, i ), m_colorFacet );
  303. }//end-for-facets
  304. /* Draw the sphere */
  305. drawSphere( m_fREmptyS, m_colorEmptySphere, m_centerPt );
  306. }
  307. }//end-if-emptyS
  308. }
  309. void Viewer::drawVertex(const Point_3& p, const QColor& clr, float r)
  310. {
  311. /* Draw regular points */
  312. if( m_isFlat ) {
  313. // disable lighting
  314. ::glDisable( GL_LIGHTING );
  315. ::glPointSize(8.0);
  316. qglColor( clr );
  317. ::glBegin(GL_POINTS);
  318. ::glVertex3f( p.x(), p.y(), p.z() );
  319. ::glEnd();
  320. // resume lighting
  321. ::glEnable( GL_LIGHTING );
  322. return;
  323. }
  324. /* Draw vertices as 3D balls */
  325. GLboolean lighting, colorMaterial;
  326. ::glGetBooleanv( GL_LIGHTING, &lighting );
  327. ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial );
  328. ::glEnable( GL_LIGHTING );
  329. ::glDisable(GL_COLOR_MATERIAL);
  330. float color[4];
  331. color[0] = clr.redF();
  332. color[1] = clr.greenF();
  333. color[2] = clr.blueF();
  334. color[3] = clr.alphaF();
  335. // move to the point
  336. ::glPushMatrix();
  337. ::glTranslatef( p.x(), p.y(), p.z() );
  338. // draw
  339. GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object
  340. ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals
  341. ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color );
  342. ::gluSphere( quadratic, r, 16, 16 );
  343. // move back to origin
  344. ::glPopMatrix();
  345. if ( colorMaterial )
  346. ::glEnable( GL_COLOR_MATERIAL );
  347. if ( !lighting )
  348. ::glDisable( GL_LIGHTING );
  349. }
  350. void Viewer::drawEdge(const Point_3& from, const Point_3& to, const QColor& clr, float r)
  351. {
  352. /* Draw regular lines */
  353. if( m_isFlat ) {
  354. // disable lighting
  355. ::glDisable( GL_LIGHTING );
  356. ::glLineWidth(1.0);
  357. qglColor( clr );
  358. ::glBegin(GL_LINES);
  359. ::glVertex3f( from.x(), from.y(), from.z() );
  360. ::glVertex3f( to.x(), to.y(), to.z() );
  361. ::glEnd();
  362. // resume lighting
  363. ::glEnable( GL_LIGHTING );
  364. return;
  365. }
  366. /* Draw edges as 3D cylinders */
  367. GLboolean lighting, colorMaterial;
  368. ::glGetBooleanv( GL_LIGHTING, &lighting );
  369. ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial );
  370. ::glEnable( GL_LIGHTING );
  371. ::glDisable(GL_COLOR_MATERIAL);
  372. float color[4];
  373. color[0] = clr.redF();
  374. color[1] = clr.greenF();
  375. color[2] = clr.blueF();
  376. color[3] = clr.alphaF();
  377. Vector_3 v = to - from;
  378. // compute the length of the edge
  379. // method 1:
  380. // float length = sqrt( CGAL::squared_distance( from, to ) );
  381. // method 2:
  382. float length = sqrt( v.squared_length() );
  383. // normalize
  384. v = v / length;
  385. // compute the angle: cos theta = v.z/1.0
  386. GLfloat angle = acos( v.z() ) / 3.1415927 * 180;
  387. ::glPushMatrix();
  388. // move to "from" point
  389. ::glTranslatef( from.x(), from.y(), from.z() );
  390. // rotate from z-axis to from-->to
  391. // axis: cross product of z-axis and from-->to
  392. ::glRotatef( angle, -v.y(), v.x(), 0.0f );
  393. // draw
  394. GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object
  395. ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals
  396. ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color );
  397. // gluCylinder draws a cylinder oriented along the z-axis
  398. ::gluCylinder( quadratic, r, r, length, 16, 4 );
  399. // move back to origin
  400. ::glPopMatrix();
  401. if ( colorMaterial )
  402. ::glEnable( GL_COLOR_MATERIAL );
  403. if ( !lighting )
  404. ::glDisable( GL_LIGHTING );
  405. }
  406. void Viewer::drawFacet(const Triangle_3& t, const QColor& /*clr*/)
  407. {
  408. // disable lighting
  409. ::glDisable( GL_LIGHTING );
  410. // disable depth buffer writing
  411. ::glDepthMask( GL_FALSE );
  412. qglColor( m_colorFacet );
  413. ::glBegin(GL_TRIANGLES);
  414. Point_3 p0 = t.vertex(0);
  415. Point_3 p1 = t.vertex(1);
  416. Point_3 p2 = t.vertex(2);
  417. ::glVertex3f( p0.x(), p0.y(), p0.z() );
  418. ::glVertex3f( p1.x(), p1.y(), p1.z() );
  419. ::glVertex3f( p2.x(), p2.y(), p2.z() );
  420. ::glEnd();
  421. // resume depth buffer writing
  422. ::glDepthMask( GL_TRUE );
  423. // resume lighting
  424. ::glEnable( GL_LIGHTING );
  425. }
  426. void Viewer::drawSphere(float r, const QColor& clr, const Point_3& center)
  427. {
  428. GLboolean lighting, colorMaterial;
  429. ::glGetBooleanv( GL_LIGHTING, &lighting );
  430. ::glGetBooleanv( GL_COLOR_MATERIAL, &colorMaterial );
  431. ::glEnable( GL_LIGHTING );
  432. ::glDisable(GL_COLOR_MATERIAL);
  433. float color[4];
  434. color[0] = clr.redF();
  435. color[1] = clr.greenF();
  436. color[2] = clr.blueF();
  437. color[3] = clr.alphaF();
  438. ::glPushMatrix();
  439. // move to the point
  440. if( center != CGAL::ORIGIN ) ::glTranslatef( center.x(), center.y(), center.z() );
  441. // disable depth buffer writing
  442. ::glDepthMask( GL_FALSE );
  443. // draw
  444. GLUquadricObj* quadratic = ::gluNewQuadric(); // Create A Pointer To The Quadric Object
  445. ::gluQuadricNormals( quadratic, GLU_SMOOTH ); // Create Smooth Normals
  446. ::glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color );
  447. ::gluSphere( quadratic, r, 32, 32 );
  448. // resume depth buffer writing
  449. ::glDepthMask( GL_TRUE );
  450. // move back to origin
  451. ::glPopMatrix();
  452. if ( colorMaterial )
  453. ::glEnable( GL_COLOR_MATERIAL );
  454. if ( !lighting )
  455. ::glDisable( GL_LIGHTING );
  456. }
  457. /*************************************************************/
  458. /* Select functions */
  459. void Viewer::drawWithNames()
  460. {
  461. for(int i=0; i<m_pScene->m_vhArray.size(); ++i) {
  462. // push a name for each point onto the name stack
  463. // note: it can NOT be used between glBegin and glEnd
  464. ::glPushName( i );
  465. // draw the point
  466. ::glBegin(GL_POINTS);
  467. Point_3& p = m_pScene->m_vhArray.at(i)->point();
  468. ::glVertex3f(p.x(), p.y(), p.z());
  469. ::glEnd();
  470. // pop one name off the top of the name stack
  471. ::glPopName();
  472. }//end-for-points
  473. // push a name for the newly inserted point
  474. if( m_curMode == INSERT_PT && m_hasNewPt ) {
  475. ::glPushName( ::GLuint(-1) );
  476. ::glBegin(GL_POINTS);
  477. ::glVertex3f(m_newPt.x(), m_newPt.y(), m_newPt.z());
  478. ::glEnd();
  479. ::glPopName();
  480. }//end-if-newPt
  481. }
  482. void Viewer::endSelection(const QPoint& /*point*/)
  483. {
  484. // flush GL buffers
  485. ::glFlush();
  486. // reset GL_RENDER mode (was GL_SELECT) and get the number of selected points
  487. size_t nSel = ::glRenderMode(GL_RENDER);
  488. /* No selection */
  489. if( nSel <= 0 ) {
  490. if( m_curMode == SELECT )
  491. m_isPress = false;
  492. }//end-if-notselected
  493. // each hit record has 4 data: # of names in name stack, min and max depth of old hits,
  494. // name stack contents [see glSelectBuffer man page for more details]
  495. // i.e. (selectBuffer())[4*i+3] is the id pushed on the stack
  496. /* Check whether the new point is clicked on */
  497. else if( m_curMode == INSERT_PT ) {
  498. if( m_hasNewPt && (selectBuffer())[3] == ::GLuint(-1) )
  499. m_isMoving = true;
  500. }//end-if-inspt
  501. /* Check whether vertex is clicked on */
  502. else if( m_curMode == MOVE ) {
  503. m_isMoving = true;
  504. m_vidMoving = (selectBuffer())[3];
  505. // compute the corresponding size of trackball, i.e. selectedV is on the ball
  506. Point_3 p = m_pScene->m_vhArray.at( m_vidMoving )->point();
  507. m_fRadius = sqrt( p.x()*p.x() + p.y()*p.y() + p.z()*p.z() );
  508. }//end-if-move
  509. /* Store current selections */
  510. else { // m_curMode == SELECT
  511. if( m_selMode == NORMAL ) {
  512. // remove the old selections
  513. for(QList<int>::iterator vit=m_vidSeled.begin();
  514. vit < m_vidSeled.end(); ++vit) {
  515. m_pScene->m_vhArray.at(*vit)->setSeled( false );
  516. }
  517. m_vidSeled.clear();
  518. // record the new selections
  519. for(std::size_t i=0; i<nSel; ++i) {
  520. m_vidSeled.push_back( (selectBuffer())[4*i+3] );
  521. m_pScene->m_vhArray.at( m_vidSeled.back() )->setSeled();
  522. }
  523. } else {
  524. for(std::size_t i=0; i<nSel; ++i) {
  525. if( !m_vidSeled.contains( (selectBuffer())[4*i+3] ) ) {
  526. m_vidSeled.push_back( (selectBuffer())[4*i+3] );
  527. m_pScene->m_vhArray.at( (selectBuffer())[4*i+3] )->setSeled();
  528. }//end-if-contain
  529. }//end-for
  530. }//end-if-add
  531. }//end-if-sel
  532. }
  533. /*************************************************************/
  534. /* Mouse and Keyboard functions */
  535. void Viewer::mousePressEvent(QMouseEvent *event)
  536. {
  537. // button() holds the button that caused the event
  538. // note: for mouse move event, button() always return Qt::NoButton
  539. // modifiers() holds the keyboard modifier flags at the time of the event
  540. // buttons() holds the button state when the event was generated,
  541. // i.e. all buttons that are pressed down
  542. // pos() holds the mouse cursor's position relative to the receiving widget
  543. // Get event modifiers key
  544. #if QT_VERSION < 0x040000
  545. // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1
  546. const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask);
  547. #else
  548. const Qt::KeyboardModifiers modifiers = event->modifiers();
  549. #endif
  550. if( m_curMode == INSERT_V
  551. && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) {
  552. m_isPress = true;
  553. }//end-if-insv
  554. else if(m_curMode == INSERT_PT && event->button() == Qt::LeftButton ) {
  555. /* shift+left to insert */
  556. if( modifiers == Qt::SHIFT ) {
  557. if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 )
  558. m_isPress = true;
  559. else
  560. displayMessage( tr("There exists no triangulation yet.") );
  561. m_hasNewPt = false;
  562. } else { /* left button to move */
  563. m_isMoving = false;
  564. // define selection window (default was 3)
  565. setSelectRegionWidth( 10 );
  566. setSelectRegionHeight( 10 );
  567. // perform the selection
  568. select( event->pos() );
  569. if( m_isMoving )
  570. // redraw window
  571. updateGL();
  572. else
  573. // if no point is selected, then regular action (rotation) will be performed
  574. QGLViewer::mousePressEvent(event);
  575. }//end-if-shift
  576. }//end-if-inspt
  577. else if( m_curMode == SELECT && event->button() == Qt::LeftButton ) {
  578. // set the selection mode
  579. switch( modifiers ) {
  580. case Qt::SHIFT : // select
  581. m_isPress = true;
  582. m_selMode = NORMAL;
  583. // initialize multiple selection window
  584. m_rectSel = QRect( event->pos(), event->pos() );
  585. // redraw window
  586. updateGL();
  587. break;
  588. case Qt::CTRL : // add selection
  589. m_isPress = true;
  590. m_selMode = ADD;
  591. // initialize multiple selection window
  592. m_rectSel = QRect( event->pos(), event->pos() );
  593. // redraw window
  594. updateGL();
  595. break;
  596. default: // rotate
  597. QGLViewer::mousePressEvent(event);
  598. break;
  599. }
  600. }//end-if-select
  601. else if(m_curMode == MOVE && event->button() == Qt::LeftButton ) {
  602. m_isMoving = false;
  603. // define selection window (default was 3)
  604. setSelectRegionWidth( 10 );
  605. setSelectRegionHeight( 10 );
  606. // perform the selection
  607. select( event->pos() );
  608. if( m_isMoving ) // redraw window
  609. updateGL();
  610. else // if no point is selected, then regular action (rotation) will be performed
  611. QGLViewer::mousePressEvent(event);
  612. }//end-if-move
  613. else if( m_curMode == FINDNB
  614. && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) {
  615. if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 )
  616. m_isPress = true;
  617. else
  618. displayMessage( tr("There exists no triangulation yet.") );
  619. }//end-if-findnb
  620. else if( m_curMode == EMPTYSPH
  621. && event->button() == Qt::LeftButton && modifiers == Qt::SHIFT ) {
  622. if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 )
  623. m_isPress = true;
  624. else
  625. displayMessage( tr("There exists no triangulation yet.") );
  626. m_hasEmptyS = false;
  627. }//end-if-emptyS
  628. else
  629. QGLViewer::mousePressEvent(event);
  630. }
  631. void Viewer::mouseMoveEvent(QMouseEvent *event)
  632. {
  633. if( m_curMode == INSERT_PT && m_isMoving ) {
  634. Vec pt;
  635. if( computeIntersect( event->pos(), pt ) ) {
  636. m_newPt = Point_3(pt.x, pt.y, pt.z);
  637. // compute the conflict hole induced by point p
  638. computeConflict( m_newPt );
  639. }//end-if-compute
  640. // redraw
  641. updateGL();
  642. }//end-if-inspt
  643. else if( m_curMode == SELECT && m_isPress ) {
  644. // update multiple selection window
  645. m_rectSel.setBottomRight( event->pos() );
  646. // redraw
  647. updateGL();
  648. }//end-if-sel
  649. else if( m_curMode == MOVE && m_isMoving ) {
  650. Vec pt;
  651. if( computeIntersect( event->pos(), pt ) ) {
  652. // note: QList::operator[] return a modifiable reference;
  653. // while QList::at return a const reference
  654. #if CGAL_VERSION_NR < 1030700000
  655. // move_point moves the point stored in v to p while preserving the Delaunay property
  656. // it calls remove(v) followed by insert(p) and return the new handle
  657. // it supposely faster when the point has not moved much
  658. m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision(
  659. m_pScene->m_vhArray.at( m_vidMoving ),
  660. Point_3( pt.x, pt.y, pt.z ) );
  661. #else
  662. // move_if_no_collision moves the point stored in v to pt
  663. // if there is not already another vertex placed on pt,
  664. // the triangulation is modified s.t. the new position of v is pt;
  665. // otherwise, the vertex at point pt is returned.
  666. Vertex_handle vh = m_pScene->m_dt.move_if_no_collision(
  667. m_pScene->m_vhArray.at( m_vidMoving ),
  668. Point_3( pt.x, pt.y, pt.z ) );
  669. int id1 = m_pScene->m_vhArray.indexOf( vh );
  670. int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 );
  671. // remove the duplicate in vhArray
  672. if( id1 != m_vidMoving )
  673. m_pScene->m_vhArray.removeAt( id1 );
  674. else if( id2 != -1 )
  675. m_pScene->m_vhArray.removeAt( id2 );
  676. m_pScene->m_vhArray[m_vidMoving] = vh;
  677. #endif
  678. }//end-if-compute
  679. // redraw
  680. updateGL();
  681. }//end-if-move
  682. else
  683. QGLViewer::mouseMoveEvent(event);
  684. }
  685. void Viewer::mouseReleaseEvent(QMouseEvent *event)
  686. {
  687. /* INS_V mode - Shift+Left: compute and insert a vertex */
  688. if( m_curMode == INSERT_V && m_isPress ) {
  689. m_isPress = false;
  690. Vec pt;
  691. if( computeIntersect( event->pos(), pt ) ) {
  692. m_pScene->m_vhArray.push_back( m_pScene->m_dt.insert( Point_3( pt.x, pt.y, pt.z ) ) );
  693. }//end-if-compute
  694. // redraw
  695. updateGL();
  696. }//end-if-ins
  697. /* INS_PT mode - Shift+Left: compute and insert a point */
  698. else if( m_curMode == INSERT_PT && m_isPress ) {
  699. m_isPress = false;
  700. Vec pt;
  701. if( computeIntersect( event->pos(), pt ) ) {
  702. m_hasNewPt = true;
  703. m_newPt = Point_3(pt.x, pt.y, pt.z);
  704. // compute the conflict hole induced by point p
  705. computeConflict( m_newPt );
  706. }//end-if-compute
  707. // redraw
  708. updateGL();
  709. }//end-if-inspt
  710. /* INS_PT mode - Left: compute and insert a point */
  711. else if( m_curMode == INSERT_PT && m_isMoving ) {
  712. m_isMoving = false;
  713. Vec pt;
  714. if( computeIntersect( event->pos(), pt ) ) {
  715. m_newPt = Point_3(pt.x, pt.y, pt.z);
  716. // compute the conflict hole induced by point p
  717. computeConflict( m_newPt );
  718. }//end-if-compute
  719. // redraw
  720. updateGL();
  721. }//end-if-inspt
  722. /* SEL mode - Left: terminate multiple point selection */
  723. else if( m_curMode == SELECT && m_isPress ) {
  724. // might swap left/right and top/bottom to make rectanle valid
  725. #if QT_VERSION < 0x040000
  726. m_rectSel = m_rectSel.normalize();
  727. #else
  728. m_rectSel = m_rectSel.normalized();
  729. #endif
  730. if( m_rectSel.width() == 1 && m_rectSel.height() == 1 ) { /* select a point */
  731. // set a default selection window
  732. setSelectRegionWidth( 10 );
  733. setSelectRegionHeight( 10 );
  734. // compute rectangle center and perform selection
  735. select( m_rectSel.center() );
  736. if( m_isPress ) {
  737. m_isPress = false;
  738. } else {
  739. displayMessage( tr("No point is selected.") );
  740. }
  741. } else { /* select multiple points, ie. selection window > 1 */
  742. // define selection window
  743. if( m_rectSel.width() < 10 )
  744. setSelectRegionWidth( 10 );
  745. else
  746. setSelectRegionWidth( m_rectSel.width() );
  747. if( m_rectSel.height() < 10 )
  748. setSelectRegionHeight( 10 );
  749. else
  750. setSelectRegionHeight( m_rectSel.height() );
  751. // compute rectangle center and perform selection
  752. select( m_rectSel.center() );
  753. if( m_isPress ) {
  754. m_isPress = false;
  755. displayMessage( QString::number(m_vidSeled.size()) + tr(" points are selected") );
  756. } else { // empty window will cancel the current selection
  757. for(QList<int>::iterator iit = m_vidSeled.begin(); iit < m_vidSeled.end(); ++iit)
  758. m_pScene->m_vhArray.at(*iit)->setSeled( false );
  759. m_vidSeled.clear();
  760. }
  761. }//end-if-selwindow
  762. // update display to show
  763. updateGL();
  764. }//end-if-select
  765. /* MOVE mode - Left: terminate point moving */
  766. else if( m_curMode == MOVE && m_isMoving ) {
  767. Vec pt;
  768. if( computeIntersect( event->pos(), pt ) ) {
  769. // note: QList::operator[] return a modifiable reference;
  770. // while QList::at return a const reference
  771. #if CGAL_VERSION_NR < 1030700000
  772. // move_point moves the point stored in v to p while preserving the Delaunay property
  773. // it calls remove(v) followed by insert(p) and return the new handle
  774. // it supposely faster when the point has not moved much
  775. m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision(
  776. m_pScene->m_vhArray.at( m_vidMoving ),
  777. Point_3( pt.x, pt.y, pt.z ) );
  778. #else
  779. // move_if_no_collision moves the point stored in v to pt
  780. // if there is not already another vertex placed on pt,
  781. // the triangulation is modified s.t. the new position of v is pt;
  782. // otherwise, the vertex at point pt is returned.
  783. Vertex_handle vh = m_pScene->m_dt.move_if_no_collision(
  784. m_pScene->m_vhArray.at( m_vidMoving ),
  785. Point_3( pt.x, pt.y, pt.z ) );
  786. int id1 = m_pScene->m_vhArray.indexOf( vh );
  787. int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 );
  788. // remove the duplicate in vhArray
  789. if( id1 != m_vidMoving )
  790. m_pScene->m_vhArray.removeAt( id1 );
  791. else if( id2 != -1 )
  792. m_pScene->m_vhArray.removeAt( id2 );
  793. m_pScene->m_vhArray[m_vidMoving] = vh;
  794. #endif
  795. }//end-if-compute
  796. // redraw
  797. updateGL();
  798. }//end-if-move
  799. /* FindNb mode - Shift+Left: find the nearest neighbor of the point */
  800. else if( m_curMode == FINDNB && m_isPress ) {
  801. m_isPress = false;
  802. Vec pt;
  803. if( computeIntersect( event->pos(), pt ) ) {
  804. m_queryPt = Point_3( pt.x, pt.y, pt.z );
  805. m_nearestNb = m_pScene->m_dt.nearest_vertex( m_queryPt );
  806. }//end-if-compute
  807. // redraw
  808. updateGL();
  809. }//end-if-findnb
  810. /* EmptySphere mode - Shift+Left: show the empty sphere of the cell */
  811. else if( m_curMode == EMPTYSPH && m_isPress ) {
  812. m_isPress = false;
  813. Vec pt;
  814. m_hasEmptyS = computeIntersect( event->pos(), pt );
  815. if( m_hasEmptyS ) {
  816. m_queryPt = Point_3( pt.x, pt.y, pt.z );
  817. // find the cell that contains point p in its interior
  818. m_cellContain = m_pScene->m_dt.locate( m_queryPt );
  819. // show error if point is outside the convex hull
  820. if( m_pScene->m_dt.is_infinite( m_cellContain ) ) {
  821. m_hasEmptyS = false;
  822. displayMessage( tr("Query point is outside the convex hull!") );
  823. } else { /* compute the empty sphere */
  824. // find the circumcenter of the four vertices of c
  825. m_centerPt = m_pScene->m_dt.dual( m_cellContain );
  826. // compute the radius of the empty sphere
  827. m_fREmptyS = sqrt( CGAL::squared_distance( m_centerPt,
  828. m_cellContain->vertex(0)->point() ) );
  829. }
  830. }//end-if-compute
  831. // redraw
  832. updateGL();
  833. }//end-if-emptysphere
  834. else
  835. QGLViewer::mouseReleaseEvent(event);
  836. }
  837. void Viewer::wheelEvent(QWheelEvent *event)
  838. {
  839. // Get event modifiers key
  840. #if QT_VERSION < 0x040000
  841. // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1
  842. const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask);
  843. #else
  844. const Qt::KeyboardModifiers modifiers = event->modifiers();
  845. #endif
  846. if( (m_curMode == INSERT_V || m_curMode == FINDNB || m_curMode == EMPTYSPH )
  847. && modifiers == Qt::SHIFT ) {
  848. // delta() returns the distance that the wheel is rotated, in eighths of a degree.
  849. // note: most mouse types work in steps of 15 degrees
  850. // positive value: rotate forwards away from the user;
  851. // negative value: rotate backwards toward the user.
  852. m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step
  853. if( m_fRadius < 0.1 )
  854. m_fRadius = 0.1;
  855. // redraw
  856. updateGL();
  857. }//end-if-insv
  858. else if( m_curMode == INSERT_PT && modifiers == Qt::SHIFT ) {
  859. // delta() returns the distance that the wheel is rotated, in eighths of a degree.
  860. // note: most mouse types work in steps of 15 degrees
  861. // positive value: rotate forwards away from the user;
  862. // negative value: rotate backwards toward the user.
  863. float origR = m_fRadius;
  864. m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step
  865. if( m_fRadius < 0.1 )
  866. m_fRadius = 0.1;
  867. // update the new point and its conflict region
  868. if( m_hasNewPt ) {
  869. origR = m_fRadius / origR;
  870. m_newPt = Point_3( m_newPt.x()*origR, m_newPt.y()*origR, m_newPt.z()*origR );
  871. // compute the conflict hole induced by point p
  872. computeConflict( m_newPt );
  873. }//end-if-conflict
  874. // redraw
  875. updateGL();
  876. }//end-if-inspt
  877. // resize the trackball when moving a point
  878. else if( m_curMode == MOVE && modifiers == Qt::SHIFT && m_isMoving ) {
  879. float origR = m_fRadius;
  880. m_fRadius += (event->delta()*1. / m_iStep ); // inc-/decrease by 0.1 per step
  881. if( m_fRadius < 0.1 )
  882. m_fRadius = 0.1;
  883. origR = m_fRadius / origR;
  884. Point_3 pt = m_pScene->m_vhArray.at( m_vidMoving )->point();
  885. // note: QList::operator[] return a modifiable reference;
  886. // while QList::at return a const reference
  887. #if CGAL_VERSION_NR < 1030700000
  888. // move_point moves the point stored in v to p while preserving the Delaunay property
  889. // it calls remove(v) followed by insert(p) and return the new handle
  890. // it supposely faster when the point has not moved much
  891. m_pScene->m_vhArray[m_vidMoving] = m_pScene->m_dt.move_if_no_collision(
  892. m_pScene->m_vhArray.at( m_vidMoving ),
  893. Point_3( pt.x()*origR, pt.y()*origR, pt.z()*origR ) );
  894. #else
  895. // move_if_no_collision moves the point stored in v to pt
  896. // if there is not already another vertex placed on pt,
  897. // the triangulation is modified s.t. the new position of v is pt;
  898. // otherwise, the vertex at point pt is returned.
  899. Vertex_handle vh = m_pScene->m_dt.move_if_no_collision(
  900. m_pScene->m_vhArray.at( m_vidMoving ),
  901. Point_3( pt.x()*origR, pt.y()*origR, pt.z()*origR ) );
  902. int id1 = m_pScene->m_vhArray.indexOf( vh );
  903. int id2 = m_pScene->m_vhArray.indexOf( vh, m_vidMoving+1 );
  904. // remove the duplicate in vhArray
  905. if( id1 != m_vidMoving )
  906. m_pScene->m_vhArray.removeAt( id1 );
  907. else if( id2 != -1 )
  908. m_pScene->m_vhArray.removeAt( id2 );
  909. m_pScene->m_vhArray[m_vidMoving] = vh;
  910. #endif
  911. // redraw
  912. updateGL();
  913. }//end-if-move
  914. else
  915. QGLViewer::wheelEvent(event);
  916. }
  917. void Viewer::keyPressEvent(QKeyEvent *event)
  918. {
  919. // Get event modifiers key
  920. #if QT_VERSION < 0x040000
  921. // Bug in Qt : use 0x0f00 instead of Qt::KeyButtonMask with Qt versions < 3.1
  922. const Qt::ButtonState modifiers = (Qt::ButtonState)(event->state() & Qt::KeyButtonMask);
  923. #else
  924. const Qt::KeyboardModifiers modifiers = event->modifiers();
  925. #endif
  926. /* Insert the newly inserted point as a vertex */
  927. if( m_curMode == INSERT_PT && m_hasNewPt
  928. && ( event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter )
  929. && modifiers==Qt::NoButton ) {
  930. Facet& f = m_boundaryFacets.first(); // a boundary facet, i.e. a pair (cell_handle, i)
  931. // insert_in_hole will create a new vertex by starring a hole
  932. // i.e. delete all conflict cells, create a new vertex,
  933. // and for each boundary facet, create a new cell with the new vertex
  934. // it takes in an iterator range of conflict cells which specifies a hole
  935. // and (begin, i) is a boundary facet that begin is one of the conflict cell
  936. // but begin->neighbor(i) is not
  937. // it returns the handle of the new vertex
  938. m_pScene->m_vhArray.push_back( m_pScene->m_dt.insert_in_hole( m_newPt, // the point
  939. m_conflictCells.begin(), // cell_begin
  940. m_conflictCells.end(), // cell_end
  941. f.first, // cell_handle begin
  942. f.second ) ); // integer i
  943. m_hasNewPt = false;
  944. // erase old conflict hole info
  945. m_boundaryFacets.clear();
  946. m_conflictCells.clear();
  947. // redraw
  948. updateGL();
  949. }//end-if-insVertex
  950. /* Cancel the newly inserted point and its conflict region */
  951. else if( m_curMode == INSERT_PT && m_hasNewPt
  952. && event->key()==Qt::Key_Escape && modifiers==Qt::NoButton ) {
  953. m_hasNewPt = false;
  954. // erase old conflict hole info
  955. m_boundaryFacets.clear();
  956. m_conflictCells.clear();
  957. // redraw
  958. updateGL();
  959. }//end-if-escapeIns
  960. /* Delete selected points */
  961. else if( m_curMode == SELECT
  962. && event->key()==Qt::Key_Delete && modifiers==Qt::NoButton ) {
  963. // sort selected id's in descending order
  964. qSort(m_vidSeled.begin(), m_vidSeled.end(), qGreater<int>());
  965. for(QList<int>::iterator vit=m_vidSeled.begin(); vit<m_vidSeled.end(); ++vit) {
  966. // remove the selected point from DT and vertex_handle_array
  967. // note: QList::takeAt will removes the item at index position i and returns it.
  968. m_pScene->m_dt.remove( m_pScene->m_vhArray.takeAt( *vit ) );
  969. }
  970. // clear the selection buffer
  971. m_vidSeled.clear();
  972. // redraw
  973. updateGL();
  974. }//end-if-del
  975. /* Cancel the selection */
  976. else if( m_curMode == SELECT
  977. && event->key()==Qt::Key_Escape && modifiers==Qt::NoButton ) {
  978. // clear the selection buffer
  979. for(QList<int>::iterator iit=m_vidSeled.begin(); iit<m_vidSeled.end(); ++iit) {
  980. m_pScene->m_vhArray.at(*iit)->setSeled( false );
  981. }
  982. m_vidSeled.clear();
  983. // redraw
  984. updateGL();
  985. }//end-if-escapeSel
  986. /* Show/hide the trackball when drawing the empty sphere */
  987. else if( m_curMode == EMPTYSPH
  988. && event->key()==Qt::Key_S && modifiers==Qt::NoButton ) {
  989. m_showTrackball = !m_showTrackball;
  990. // redraw
  991. updateGL();
  992. }//end-if-showBall
  993. else
  994. QGLViewer::keyPressEvent(event);
  995. }
  996. /*************************************************************/
  997. /* Computation functions */
  998. bool Viewer::computeIntersect( const QPoint & pos, Vec & pt )
  999. {
  1000. Vec eye, dir;
  1001. // Compute eye position and direction to the clicked point,
  1002. // used to draw a representation of the intersecting line
  1003. camera()->convertClickToLine( pos, eye, dir );
  1004. // Compute the intersection point with the sphere
  1005. // note that the center of the sphere is at the origin (0, 0, 0)
  1006. // thus, (1) pt = eye + t*dir and (2) dist( pt, origin ) = radius
  1007. // i.e. (x_eye + t*x_dir)^2 + (y_eye + t*y_dir)^2 + (z_eye + t*z_dir)^2 = r^2
  1008. // --> t^2( dir*dir ) + 2t( eye*dir ) + eye*eye - r^2 = 0
  1009. // where "dir*dir" is the dot product of vector dir
  1010. // we need to solve t and the smaller t (nearer to eye position) is what we want
  1011. float a = dir*dir;
  1012. float b = eye*dir;
  1013. float c = eye*eye - m_fRadius*m_fRadius;
  1014. float delta = b*b - a*c;
  1015. if( delta < 0 ) {
  1016. displayMessage( tr("Point is not on the sphere!") );
  1017. return false;
  1018. } else {
  1019. float t = ( (-1.)*b - sqrt(delta) ) / a;
  1020. pt = eye + t*dir;
  1021. return true;
  1022. }
  1023. }
  1024. void Viewer::computeConflict( Point_3 pt )
  1025. {
  1026. // find the cell that contains point p in its interior
  1027. m_cellContain = m_pScene->m_dt.locate( pt );
  1028. // erase old conflict hole info
  1029. m_boundaryFacets.clear();
  1030. m_conflictCells.clear();
  1031. // show msg if point is outside the convex hull
  1032. if( m_pScene->m_dt.is_infinite( m_cellContain ) )
  1033. displayMessage( tr("Note: point is outside the convex hull.") );
  1034. // compute the conflict hole induced by point p
  1035. m_pScene->m_dt.find_conflicts( pt, // the point
  1036. m_cellContain, // starting cell that must be in conflict
  1037. std::back_inserter(m_boundaryFacets), // the facets on the boundary
  1038. std::back_inserter(m_conflictCells) ); // the cells in conflict
  1039. }
  1040. /*************************************************************/
  1041. /* Animation functions */
  1042. void Viewer::toggleIncremental(bool on) {
  1043. if( on ) { // play
  1044. if( m_incrementalPts.isEmpty() ) {
  1045. /* start play */
  1046. if( m_pScene->m_dt.number_of_vertices() == 0 ) {
  1047. CGAL::Random_points_in_cube_3<Point_3> pts_generator(1.0);
  1048. CGAL::cpp0x::copy_n( pts_generator, 100, std::back_inserter(m_incrementalPts) );
  1049. } else {
  1050. for(QList<Vertex_handle>::iterator vit = m_pScene->m_vhArray.begin();
  1051. vit < m_pScene->m_vhArray.end(); ++vit) {
  1052. m_incrementalPts.push_back( (*vit)->point() );
  1053. }//end-for
  1054. // erase existing vertices
  1055. initClean();
  1056. }//end-if-pts
  1057. // sorts points in a way that improves space locality
  1058. CGAL::spatial_sort( m_incrementalPts.begin(), m_incrementalPts.end() );
  1059. // set the current to "hightlight the new point"
  1060. m_curStep = INIT;
  1061. }/* else resume play */
  1062. // set up the timer
  1063. m_pTimer->start(1000);
  1064. } else { // pause
  1065. m_pTimer->stop();
  1066. }
  1067. // redraw
  1068. updateGL();
  1069. }
  1070. void Viewer::stopIncremental() {
  1071. if( !m_incrementalPts.isEmpty() ) {
  1072. // will call toggleIncremental to stop the timer
  1073. emit( stopIncAnimation() );
  1074. // insert the rest points
  1075. for(QList<Point_3>::iterator pit=m_incrementalPts.begin();
  1076. pit < m_incrementalPts.end(); ++pit) {
  1077. Vertex_handle hint;
  1078. if( m_pScene->m_vhArray.isEmpty() ) {
  1079. hint = m_pScene->m_dt.insert( *pit );
  1080. } else {
  1081. hint = m_pScene->m_vhArray.last();
  1082. hint = m_pScene->m_dt.insert( *pit, hint );
  1083. }
  1084. m_pScene->m_vhArray.push_back( hint );
  1085. }
  1086. m_incrementalPts.clear();
  1087. }
  1088. // redraw
  1089. updateGL();
  1090. }
  1091. void Viewer::incremental_insert() {
  1092. Vertex_handle hint;
  1093. if( !m_incrementalPts.isEmpty() ) {
  1094. switch( m_curStep ) {
  1095. case INIT: // end of INIT: get the next-to-insert point
  1096. m_curIncPt = m_incrementalPts.at(0);
  1097. m_curStep = NEWPT;
  1098. break;
  1099. case NEWPT: // end of NEWPT: locate the cell containing the point
  1100. if( m_pScene->m_dt.is_valid() && m_pScene->m_dt.dimension() == 3 ) {
  1101. computeConflict( m_curIncPt );
  1102. m_curStep = CELL;
  1103. }
  1104. else {
  1105. // popup the first point and insert it
  1106. m_curIncPt = m_incrementalPts.takeFirst();
  1107. if( m_pScene->m_vhArray.isEmpty() ) {
  1108. hint = m_pScene->m_dt.insert( m_curIncPt );
  1109. }
  1110. else {
  1111. hint = m_pScene->m_vhArray.last();
  1112. hint = m_pScene->m_dt.insert( m_curIncPt, hint );
  1113. }
  1114. m_pScene->m_vhArray.push_back( hint );
  1115. m_curStep = INIT;
  1116. }
  1117. break;
  1118. case CELL: // end of CELL: compute the conflict region
  1119. m_curStep = CONFLICT;
  1120. break;
  1121. case CONFLICT: // end of CONFLICT: do the insertion and go back to INIT
  1122. // popup the first point and insert it
  1123. m_curIncPt = m_incrementalPts.takeFirst();
  1124. if( m_pScene->m_vhArray.isEmpty() ) {
  1125. hint = m_pScene->m_dt.insert( m_curIncPt );
  1126. } else {
  1127. hint = m_pScene->m_vhArray.last();
  1128. hint = m_pScene->m_dt.insert( m_curIncPt, hint );
  1129. }
  1130. m_pScene->m_vhArray.push_back( hint );
  1131. m_curStep = INIT;
  1132. break;
  1133. }//end-of-switch
  1134. } else {
  1135. /* if finished, then start over */
  1136. for(QList<Vertex_handle>::iterator vit = m_pScene->m_vhArray.begin();
  1137. vit < m_pScene->m_vhArray.end(); ++vit) {
  1138. m_incrementalPts.push_back( (*vit)->point() );
  1139. }//end-for
  1140. // erase existing vertices
  1141. initClean();
  1142. // set the current to "hightlight the new point"
  1143. m_curStep = INIT;
  1144. }
  1145. // redraw
  1146. updateGL();
  1147. }