RINGMesh  Version 5.0.0
A programming library for geological model meshes
gfx_application.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2012-2017, Association Scientifique pour la Geologie et ses
3  * Applications (ASGA). All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of ASGA nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ASGA BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  * http://www.ring-team.org
28  *
29  * RING Project
30  * Ecole Nationale Superieure de Geologie - GeoRessources
31  * 2 Rue du Doyen Marcel Roubault - TSA 70605
32  * 54518 VANDOEUVRE-LES-NANCY
33  * FRANCE
34  */
35 
42 
43 #ifdef RINGMESH_WITH_GRAPHICS
44 
45 #include <geogram/basic/command_line.h>
46 #include <geogram/basic/file_system.h>
47 
48 #include <geogram/mesh/mesh_io.h>
49 
50 #include <geogram_gfx/basic/GL.h>
51 
52 #include <geogram_gfx/glup_viewer/glup_viewer.h>
53 
54 #include <geogram_gfx/third_party/quicktext/glQuickText.h>
55 
57 
62 
63 #include <ringmesh/io/io.h>
64 
65 namespace
66 {
67  using namespace RINGMesh;
68 
69  typedef std::vector< std::vector< ImColor > > ColorTable;
70 
71  ImColor black( 0, 0, 0 );
72  ImColor dark_grey( 128, 128, 128 );
73  ImColor grey( 192, 192, 192 );
74  ImColor white( 255, 255, 255 );
75 
76  ImColor violet( 71, 61, 139 );
77  ImColor blue( 0, 0, 255 );
78  ImColor other_blue( 100, 151, 237 );
79  ImColor light_blue( 136, 207, 235 );
80 
81  ImColor grass_green( 85, 107, 47 );
82  ImColor green( 50, 205, 50 );
83  ImColor light_green( 175, 255, 47 );
84  ImColor brown( 160, 81, 45 );
85 
86  ImColor red( 255, 0, 0 );
87  ImColor orange( 255, 162, 0 );
88  ImColor yellow( 255, 255, 0 );
89  ImColor pink( 255, 0, 255 );
90 
91  ColorTable create_color_table()
92  {
93  ColorTable color_table_init( 4 );
94  color_table_init[0].push_back( black );
95  color_table_init[0].push_back( dark_grey );
96  color_table_init[0].push_back( grey );
97  color_table_init[0].push_back( white );
98 
99  color_table_init[1].push_back( violet );
100  color_table_init[1].push_back( blue );
101  color_table_init[1].push_back( other_blue );
102  color_table_init[1].push_back( light_blue );
103 
104  color_table_init[2].push_back( grass_green );
105  color_table_init[2].push_back( green );
106  color_table_init[2].push_back( light_green );
107  color_table_init[2].push_back( brown );
108 
109  color_table_init[3].push_back( red );
110  color_table_init[3].push_back( orange );
111  color_table_init[3].push_back( yellow );
112  color_table_init[3].push_back( pink );
113  return color_table_init;
114  }
115 
116  std::string path_to_label(
117  const std::string& viewer_path, const std::string& path )
118  {
119  if( GEO::String::string_starts_with( path, viewer_path ) )
120  {
121  return path.substr(
122  viewer_path.length(), path.length() - viewer_path.length() );
123  }
124  return path;
125  }
126 
127  bool GetChar( void* data, int idx, const char** out_text )
128  {
129  *out_text = static_cast< const std::vector< std::string >* >(
130  data )->at( static_cast< long unsigned int >( idx ) )
131  .c_str();
132  return true;
133  }
134 
135  template < index_t DIMENSION >
136  void compute_mesh_entity_bbox(
138  {
139  for( auto v : range( entity.nb_vertices() ) )
140  {
141  bbox.add_point( entity.vertex( v ) );
142  }
143  }
144 }
145 namespace RINGMesh
146 {
147  template < index_t DIMENSION >
148  RINGMeshApplication::GeoModelViewerBase< DIMENSION >::GeoModelViewerBase(
149  RINGMeshApplication& app, const std::string& filename )
150  : app_( app )
151  {
152  corner_style_.color_ = red;
153  corner_style_.size_ = 1;
154  corner_style_.visible_vertices_ = false;
155  corner_style_.vertex_color_ = pink;
156  corner_style_.vertex_size_ = 0;
157 
158  line_style_.color_ = black;
159  line_style_.size_ = 1;
160  line_style_.visible_vertices_ = false;
161  line_style_.vertex_color_ = orange;
162  line_style_.vertex_size_ = 3;
163 
164  surface_style_.color_ = grey;
165  surface_style_.size_ = 1;
166  surface_style_.visible_vertices_ = false;
167  surface_style_.vertex_color_ = light_blue;
168  surface_style_.vertex_size_ = 3;
169 
170  mesh_color_ = black;
171  reset_attribute_name();
172 
173  geomodel_load( GM_, filename );
174  // Computation of the BBox is set with surface vertices
175  // or with those of lines and corners if the model has no surface
176  if( GM_.nb_surfaces() > 0 )
177  {
178  for( const auto& surface : GM_.surfaces() )
179  {
180  compute_mesh_entity_bbox( surface, bbox_ );
181  }
182  }
183  else if( GM_.nb_lines() > 0 )
184  {
185  for( const auto& line : GM_.lines() )
186  {
187  compute_mesh_entity_bbox( line, bbox_ );
188  }
189  }
190  else
191  {
192  for( const auto& corner : GM_.corners() )
193  {
194  compute_mesh_entity_bbox( corner, bbox_ );
195  }
196  }
197 
198  const std::vector< MeshEntityType >& types =
199  GM_.entity_type_manager().mesh_entity_manager.mesh_entity_types();
200  entity_types_.reserve( types.size() + 1 );
201  entity_types_.emplace_back( "All" );
202  for( const MeshEntityType& type : types )
203  {
204  entity_types_.emplace_back( type.string() );
205  }
206  for( auto i : range( GM_.nb_geological_entity_types() ) )
207  {
208  entity_types_.emplace_back(
209  GM_.geological_entity_type( i ).string() );
210  }
211  GM_gfx_.set_geomodel( GM_ );
212  if( !app.colormaps_.empty() )
213  {
214  GM_gfx_.attribute.set_colormap( app.colormaps_[0].texture );
215  }
216  }
217 
218  template < index_t DIMENSION >
219  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
220  reset_attribute_name()
221  {
222  GM_gfx_.attribute.set_name( "name" );
223  }
224 
225  template < index_t DIMENSION >
226  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::draw_scene()
227  {
228  if( selected_entity_type_ != 0 )
229  {
230  index_t selected_entity_type_casted =
231  static_cast< index_t >( selected_entity_type_ );
232  const std::string& type =
233  entity_types_[selected_entity_type_casted];
234 
235  if( selected_entity_type_casted
236  < GM_.entity_type_manager()
237  .mesh_entity_manager.nb_mesh_entity_types()
238  + 1 )
239  {
240  MeshEntityType mesh_type{ type };
241  selected_entity_id_ = std::min(
242  static_cast< int >( GM_.nb_mesh_entities( mesh_type ) - 1 ),
243  selected_entity_id_ );
244  gmme_id entity_id(
245  mesh_type, static_cast< index_t >( selected_entity_id_ ) );
246  toggle_mesh_entity_and_boundaries_visibility( entity_id );
247  }
248  else
249  {
250  GeologicalEntityType geol_type{ type };
251  selected_entity_id_ =
252  std::min( static_cast< int >(
253  GM_.nb_geological_entities( geol_type ) - 1 ),
254  selected_entity_id_ );
255  gmge_id entity_id(
256  geol_type, static_cast< index_t >( selected_entity_id_ ) );
257  toggle_geological_entity_visibility( entity_id );
258  }
259  }
260 
261  if( show_attributes_ )
262  {
263  GM_gfx_.attribute.bind_attribute();
264  }
265  else
266  {
267  GM_gfx_.attribute.unbind_attribute();
268  }
269 
270  if( show_corners_ )
271  {
272  GM_gfx_.corners.set_vertex_color( corner_style_.color_.Value.x,
273  corner_style_.color_.Value.y, corner_style_.color_.Value.z );
274  GM_gfx_.corners.set_vertex_size(
275  static_cast< index_t >( corner_style_.size_ ) );
276  GM_gfx_.corners.draw();
277  }
278 
279  if( show_lines_ )
280  {
281  GM_gfx_.lines.set_line_color( line_style_.color_.Value.x,
282  line_style_.color_.Value.y, line_style_.color_.Value.z );
283  GM_gfx_.lines.set_line_size(
284  static_cast< index_t >( line_style_.size_ ) );
285  if( selected_entity_type_ == 0 )
286  {
287  GM_gfx_.lines.set_vertex_visibility(
288  line_style_.visible_vertices_ );
289  }
290  if( line_style_.visible_vertices_ )
291  {
292  GM_gfx_.lines.set_vertex_size(
293  static_cast< index_t >( line_style_.vertex_size_ ) );
294  GM_gfx_.lines.set_vertex_color(
295  line_style_.vertex_color_.Value.x,
296  line_style_.vertex_color_.Value.y,
297  line_style_.vertex_color_.Value.z );
298  }
299  GM_gfx_.lines.draw();
300  }
301 
302  if( show_surface_ )
303  {
304  GM_gfx_.surfaces.set_mesh_visibility( mesh_visible_ );
305  GM_gfx_.surfaces.set_mesh_color(
306  mesh_color_.Value.x, mesh_color_.Value.y, mesh_color_.Value.z );
307  GM_gfx_.surfaces.set_surface_color( surface_style_.color_.Value.x,
308  surface_style_.color_.Value.y, surface_style_.color_.Value.z );
309  GM_gfx_.surfaces.set_mesh_size(
310  static_cast< index_t >( surface_style_.size_ ) );
311  if( selected_entity_type_ == 0 )
312  {
313  GM_gfx_.surfaces.set_vertex_visibility(
314  surface_style_.visible_vertices_ );
315  }
316  if( surface_style_.visible_vertices_ )
317  {
318  GM_gfx_.surfaces.set_vertex_size(
319  static_cast< index_t >( surface_style_.vertex_size_ ) );
320  GM_gfx_.surfaces.set_vertex_color(
321  surface_style_.vertex_color_.Value.x,
322  surface_style_.vertex_color_.Value.y,
323  surface_style_.vertex_color_.Value.z );
324  }
325  if( selected_entity_type_ == 0 )
326  {
327  for( const auto& surface : GM_.surfaces() )
328  {
329  if( surface.is_on_voi() )
330  {
331  GM_gfx_.surfaces.set_surface_visibility(
332  surface.index(), show_voi_ );
333  }
334  }
335  }
336  GM_gfx_.surfaces.draw();
337  }
338  }
339 
340  template < index_t DIMENSION >
341  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
342  set_attribute_names( const std::vector< std::string >& names )
343  {
344  for( const std::string& name : names )
345  {
346  if( ImGui::Button( name.c_str() ) )
347  {
348  GM_gfx_.attribute.set_name( name );
349  GM_gfx_.attribute.set_coordinate( 0 );
350  autorange();
351  ImGui::CloseCurrentPopup();
352  }
353  }
354  }
355 
356  template < index_t DIMENSION >
357  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::autorange()
358  {
359  GM_gfx_.attribute.compute_range();
360  attribute_max_ = static_cast< float >( GM_gfx_.attribute.maximum() );
361  attribute_min_ = static_cast< float >( GM_gfx_.attribute.minimum() );
362  }
363 
364  template < index_t DIMENSION >
365  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
366  update_all_entity_visibility( bool value )
367  {
368  GM_gfx_.corners.set_vertex_visibility( value );
369  GM_gfx_.lines.set_line_visibility( value );
370  GM_gfx_.surfaces.set_surface_visibility( value );
371  if( !value || line_style_.visible_vertices_ )
372  {
373  GM_gfx_.lines.set_vertex_visibility( value );
374  }
375  if( !value || surface_style_.visible_vertices_ )
376  {
377  GM_gfx_.surfaces.set_vertex_visibility( value );
378  }
379  }
380 
381  template < index_t DIMENSION >
382  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
383  update_entity_visibility()
384  {
385  index_t selected_entity_type_casted =
386  static_cast< index_t >( selected_entity_type_ );
387  const std::string& type = entity_types_[selected_entity_type_casted];
388  if( selected_entity_type_ == 0 )
389  {
390  update_all_entity_visibility( true );
391  }
392  else
393  {
394  update_all_entity_visibility( false );
395  if( selected_entity_type_casted
396  < GM_.entity_type_manager()
397  .mesh_entity_manager.nb_mesh_entity_types()
398  + 1 )
399  {
400  MeshEntityType mesh_type{ type };
401  selected_entity_id_ = std::min(
402  static_cast< int >( GM_.nb_mesh_entities( mesh_type ) - 1 ),
403  selected_entity_id_ );
404  gmme_id entity_id(
405  mesh_type, static_cast< index_t >( selected_entity_id_ ) );
406  toggle_mesh_entity_and_boundaries_visibility( entity_id );
407  }
408  else
409  {
410  GeologicalEntityType geol_type{ type };
411  selected_entity_id_ =
412  std::min( static_cast< int >(
413  GM_.nb_geological_entities( geol_type ) - 1 ),
414  selected_entity_id_ );
415  gmge_id entity_id(
416  geol_type, static_cast< index_t >( selected_entity_id_ ) );
417  toggle_geological_entity_visibility( entity_id );
418  }
419  }
420  }
421 
422  template < index_t DIMENSION >
423  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
424  toggle_mesh_entity_and_boundaries_visibility( const gmme_id& entity_id )
425  {
426  const MeshEntityTypeManager< DIMENSION >& manager =
427  GM_.entity_type_manager().mesh_entity_manager;
428  if( manager.is_corner( entity_id.type() ) )
429  {
430  toggle_corner_visibility( entity_id.index() );
431  }
432  else if( manager.is_line( entity_id.type() ) )
433  {
434  toggle_line_and_boundaries_visibility( entity_id.index() );
435  }
436  else if( manager.is_surface( entity_id.type() ) )
437  {
438  toggle_surface_and_boundaries_visibility( entity_id.index() );
439  }
440  else
441  {
443  }
444  }
445 
446  template < index_t DIMENSION >
447  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
448  toggle_corner_visibility( index_t corner_id )
449  {
450  GM_gfx_.corners.set_vertex_visibility( corner_id, true );
451  }
452 
453  template < index_t DIMENSION >
454  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
455  toggle_line_and_boundaries_visibility( index_t line_id )
456  {
457  GM_gfx_.lines.set_line_visibility( line_id, true );
458  GM_gfx_.lines.set_vertex_visibility(
459  line_id, line_style_.visible_vertices_ );
460  const Line< DIMENSION >& line = GM_.line( line_id );
461  for( auto i : range( line.nb_boundaries() ) )
462  {
463  toggle_corner_visibility( line.boundary_gmme( i ).index() );
464  }
465  }
466 
467  template < index_t DIMENSION >
468  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
469  toggle_surface_and_boundaries_visibility( index_t surface_id )
470  {
471  GM_gfx_.surfaces.set_surface_visibility( surface_id, true );
472  GM_gfx_.surfaces.set_vertex_visibility(
473  surface_id, surface_style_.visible_vertices_ );
474  const Surface< DIMENSION >& surface = GM_.surface( surface_id );
475  for( auto i : range( surface.nb_boundaries() ) )
476  {
477  toggle_line_and_boundaries_visibility(
478  surface.boundary_gmme( i ).index() );
479  }
480  }
481 
482  template < index_t DIMENSION >
483  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
484  toggle_geological_entity_visibility( const gmge_id& entity_id )
485  {
487  GM_.geological_entity( entity_id );
488  for( auto i : range( entity.nb_children() ) )
489  {
490  const gmme_id& child_id = entity.child_gmme( i );
491  toggle_mesh_entity_and_boundaries_visibility( child_id );
492  }
493  }
494 
495  template < index_t DIMENSION >
496  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
497  draw_object_properties()
498  {
499  if( ImGui::Combo( "Type", &selected_entity_type_, GetChar,
500  static_cast< void* >( &entity_types_ ),
501  static_cast< int >( entity_types_.size() ) ) )
502  {
503  update_entity_visibility();
504  }
505  if( selected_entity_type_ > 0 )
506  {
507  if( ImGui::InputInt( "Id", &selected_entity_id_, 1 ) )
508  {
509  selected_entity_id_ = std::max( 0, selected_entity_id_ );
510  update_entity_visibility();
511  }
512  }
513  ImGui::Separator();
514  ImGui::Checkbox( "Attributes", &show_attributes_ );
515  if( show_attributes_ )
516  {
517  if( ImGui::Button( GM_gfx_.attribute.location_name().c_str(),
518  ImVec2( -1, 0 ) ) )
519  {
520  ImGui::OpenPopup( "##Locations" );
521  }
522  if( ImGui::BeginPopup( "##Locations" ) )
523  {
524  std::vector< std::string > locations =
525  GM_gfx_.attribute.registered_locations();
526  for( const std::string& location : locations )
527  {
528  if( ImGui::Button( location.c_str() ) )
529  {
530  GM_gfx_.attribute.set_location( location );
531  reset_attribute_name();
532  ImGui::CloseCurrentPopup();
533  }
534  }
535  ImGui::EndPopup();
536  }
537 
538  if( ImGui::Button(
539  GM_gfx_.attribute.name().c_str(), ImVec2( -1, 0 ) ) )
540  {
541  ImGui::OpenPopup( "##Attributes" );
542  }
543  if( ImGui::BeginPopup( "##Attributes" ) )
544  {
545  set_attribute_names( GM_gfx_.attribute.get_attribute_names() );
546  ImGui::EndPopup();
547  }
548  if( GM_gfx_.attribute.location_name() != "location"
549  && GM_gfx_.attribute.nb_coordinates() > 1 )
550  {
551  if( ImGui::Button(
552  std::to_string( GM_gfx_.attribute.coordinate() )
553  .c_str(),
554  ImVec2( -1, 0 ) ) )
555  {
556  ImGui::OpenPopup( "##Coordinates" );
557  }
558  if( ImGui::BeginPopup( "##Coordinates" ) )
559  {
560  for( auto i : range( GM_gfx_.attribute.nb_coordinates() ) )
561  {
562  if( ImGui::Button( std::to_string( i ).c_str() ) )
563  {
564  GM_gfx_.attribute.set_coordinate( i );
565  autorange();
566  ImGui::CloseCurrentPopup();
567  }
568  }
569  ImGui::EndPopup();
570  }
571  }
572  if( ImGui::InputFloat( "min", &attribute_min_ ) )
573  {
574  GM_gfx_.attribute.set_minimum(
575  static_cast< double >( attribute_min_ ) );
576  }
577  if( ImGui::InputFloat( "max", &attribute_max_ ) )
578  {
579  GM_gfx_.attribute.set_maximum(
580  static_cast< double >( attribute_max_ ) );
581  }
582  if( ImGui::Button( "autorange", ImVec2( -1, 0 ) ) )
583  {
584  autorange();
585  }
586  if( ImGui::ImageButton(
587  app_.convert_to_ImTextureID( GM_gfx_.attribute.colormap() ),
588  ImVec2( 115, 8 ) ) )
589  {
590  ImGui::OpenPopup( "##Colormap" );
591  }
592  if( ImGui::BeginPopup( "##Colormap" ) )
593  {
594  for( const auto& colormap : app_.colormaps_ )
595  {
596  if( ImGui::ImageButton(
597  app_.convert_to_ImTextureID( colormap.texture ),
598  ImVec2( 100, 8 ) ) )
599  {
600  GM_gfx_.attribute.set_colormap( colormap.texture );
601  ImGui::CloseCurrentPopup();
602  }
603  }
604  ImGui::EndPopup();
605  }
606  ImGui::Checkbox( "Colormap [M]", &show_colormap_ );
607  }
608 
609  ImGui::Separator();
610  ImGui::Checkbox( "VOI [V]", &show_voi_ );
611  ImGui::Checkbox( "Mesh [m]", &mesh_visible_ );
612  ImGui::SameLine();
613  ImGui::PushStyleColor( ImGuiCol_Button, mesh_color_ );
614  if( ImGui::Button( " ##MeshColor" ) )
615  {
616  ImGui::OpenPopup( "##MeshColorTable" );
617  }
618  ImGui::PopStyleColor();
619  if( ImGui::BeginPopup( "##MeshColorTable" ) )
620  {
621  show_color_table_popup( mesh_color_ );
622  }
623 
624  ImGui::Separator();
625  ImGui::Checkbox( "Corner [c]", &show_corners_ );
626  draw_entity_style_editor( "##CornerColor", corner_style_ );
627 
628  ImGui::Separator();
629  ImGui::Checkbox( "Line [e]", &show_lines_ );
630  draw_entity_style_editor( "##LineColor", line_style_ );
631  ImGui::Checkbox( "Vertices##Line", &line_style_.visible_vertices_ );
632  if( line_style_.visible_vertices_ )
633  {
634  draw_entity_vertex_style_editor( "##LineVertexColor", line_style_ );
635  }
636 
637  ImGui::Separator();
638  ImGui::Checkbox( "Surface [s]", &show_surface_ );
639  draw_entity_style_editor( "##SurfaceColor", surface_style_ );
640  ImGui::Checkbox(
641  "Vertices##Surface", &surface_style_.visible_vertices_ );
642  if( surface_style_.visible_vertices_ )
643  {
644  draw_entity_vertex_style_editor(
645  "##SurfaceVertexColor", surface_style_ );
646  }
647  }
648 
649  template < index_t DIMENSION >
650  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
651  draw_entity_style_editor( const std::string& label, EntityStyle& style )
652  {
653  ImGui::PushStyleColor( ImGuiCol_Button, style.color_ );
654  if( ImGui::Button( ( " " + label ).c_str() ) )
655  {
656  ImGui::OpenPopup( label.c_str() );
657  }
658  ImGui::PopStyleColor();
659  if( ImGui::BeginPopup( label.c_str() ) )
660  {
661  show_color_table_popup( style.color_ );
662  }
663  ImGui::SameLine();
664  ImGui::InputInt( "", &style.size_, 1 );
665  style.size_ = std::max( style.size_, 0 );
666  }
667 
668  template < index_t DIMENSION >
669  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::
670  draw_entity_vertex_style_editor(
671  const std::string& label, EntityStyle& style )
672  {
673  ImGui::PushStyleColor( ImGuiCol_Button, style.vertex_color_ );
674  if( ImGui::Button( ( " " + label ).c_str() ) )
675  {
676  ImGui::OpenPopup( label.c_str() );
677  }
678  ImGui::PopStyleColor();
679  if( ImGui::BeginPopup( label.c_str() ) )
680  {
681  show_color_table_popup( style.vertex_color_ );
682  }
683  ImGui::SameLine();
684  ImGui::InputInt( "", &style.vertex_size_, 1 );
685  style.vertex_size_ = std::max( style.vertex_size_, 0 );
686  style.vertex_size_ = std::min( style.vertex_size_, 50 );
687  }
688 
689  template < index_t DIMENSION >
690  void RINGMeshApplication::GeoModelViewerBase< DIMENSION >::draw_colormap()
691  {
692  GLUPboolean clipping_save = glupIsEnabled( GLUP_CLIPPING );
693  glupDisable( GLUP_CLIPPING );
694 
695  glupMatrixMode( GLUP_TEXTURE_MATRIX );
696  glupLoadIdentity();
697 
698  glupMatrixMode( GLUP_PROJECTION_MATRIX );
699  glupPushMatrix();
700  glupLoadIdentity();
701 
702  glupMatrixMode( GLUP_MODELVIEW_MATRIX );
703  glupPushMatrix();
704  glupLoadIdentity();
705 
706  const double z = -1.0;
707  const double w = 0.3;
708  const double h = 0.1;
709  const double x1 = 0.;
710  const double y1 = -0.9;
711  const double tmin = GM_gfx_.attribute.minimum();
712  const double tmax = GM_gfx_.attribute.maximum();
713  GEO::glupMapTexCoords1d( tmin, tmax, 1. );
714 
715  glupColor3d( 1.0, 1.0, 1.0 );
716  glupDisable( GLUP_LIGHTING );
717  glupEnable( GLUP_TEXTURING );
718  glupTextureMode( GLUP_TEXTURE_REPLACE );
719  glupTextureType( GLUP_TEXTURE_1D );
720  glupEnable( GLUP_DRAW_MESH );
721  glupSetColor3d( GLUP_MESH_COLOR, 0.0, 0.0, 0.0 );
722  glupSetMeshWidth( 2 );
723  glupSetCellsShrink( 0.0f );
724 
725  glupBegin( GLUP_QUADS );
726  glupTexCoord1d( tmin );
727  glupVertex3d( x1 - w, y1, z );
728  glupTexCoord1d( tmax );
729  glupVertex3d( x1 + w, y1, z );
730  glupTexCoord1d( tmax );
731  glupVertex3d( x1 + w, y1 + h, z );
732  glupTexCoord1d( tmin );
733  glupVertex3d( x1 - w, y1 + h, z );
734  glupEnd();
735 
736  glupTextureType( GLUP_TEXTURE_2D );
737  glupMatrixMode( GLUP_TEXTURE_MATRIX );
738  glupLoadIdentity();
739  glupMatrixMode( GLUP_MODELVIEW_MATRIX );
740 
741  glupSetColor4d( GLUP_FRONT_AND_BACK_COLOR, 0.0, 0.0, 0.0, 1.0 );
742 
743  const double font_sz = 0.003;
744  const double font_height = 0.4 * glQuickText::getFontHeight( font_sz );
745 
746  std::string min_value = std::to_string( GM_gfx_.attribute.minimum() );
747  const double nb_min_letter = static_cast< double >( min_value.size() );
748  glQuickText::printfAt( x1 - w - font_height * nb_min_letter * 0.3,
749  y1 - font_height, z, font_sz, min_value.c_str() );
750 
751  std::string max_value = std::to_string( GM_gfx_.attribute.maximum() );
752  const double nb_max_letter = static_cast< double >( max_value.size() );
753  glQuickText::printfAt( x1 + w - font_height * nb_max_letter * 0.3,
754  y1 - font_height, z, font_sz, max_value.c_str() );
755 
756  glupMatrixMode( GLUP_PROJECTION_MATRIX );
757  glupPopMatrix();
758 
759  glupMatrixMode( GLUP_MODELVIEW_MATRIX );
760  glupPopMatrix();
761 
762  if( clipping_save )
763  {
764  glupEnable( GLUP_CLIPPING );
765  }
766  }
767 
768  RINGMeshApplication::GeoModelViewer< 2 >::GeoModelViewer(
769  RINGMeshApplication& app, const std::string& filename )
770  : RINGMeshApplication::GeoModelViewerBase< 2 >( app, filename )
771  {
772  }
773 
774  RINGMeshApplication::GeoModelViewer< 3 >::GeoModelViewer(
775  RINGMeshApplication& app, const std::string& filename )
776  : RINGMeshApplication::GeoModelViewerBase< 3 >( app, filename )
777  {
778  volume_style_.color_ = grey;
779  volume_style_.size_ = 1;
780  volume_style_.visible_vertices_ = false;
781  volume_style_.vertex_color_ = light_green;
782  volume_style_.vertex_size_ = 3;
783 
784  if( GM_.nb_regions() > 0 )
785  {
786  meshed_regions_ = GM_.region( 0 ).is_meshed();
787  }
788  if( meshed_regions_ )
789  {
790  show_volume_ = true;
791  }
792  }
793 
794  void RINGMeshApplication::GeoModelViewer< 3 >::toggle_colored_cells()
795  {
796  show_colored_regions_.new_status = false;
797  show_colored_layers_.new_status = false;
798  GM_gfx_.regions.set_cell_colors_by_type();
799  }
800 
801  void RINGMeshApplication::GeoModelViewer< 3 >::toggle_colored_regions()
802  {
803  colored_cells_.new_status = false;
804  show_colored_layers_.new_status = false;
805  for( auto r : range( GM_.nb_regions() ) )
806  {
807  GM_gfx_.regions.set_region_color( r,
808  std::fmod( GEO::Numeric::random_float32(), 1.f ),
809  std::fmod( GEO::Numeric::random_float32(), 1.f ),
810  std::fmod( GEO::Numeric::random_float32(), 1.f ) );
811  }
812  }
813 
814  void RINGMeshApplication::GeoModelViewer< 3 >::toggle_colored_layers()
815  {
816  // To disable the key 'R'. If no layer within the model, layer is not
817  // a valid type.
818  if( !GM_.entity_type_manager().geological_entity_manager.is_valid_type(
819  Layer3D::type_name_static() ) )
820  {
821  show_colored_layers_.new_status = false;
822  return;
823  }
824  colored_cells_.new_status = false;
825  show_colored_regions_.new_status = false;
826  for( auto l :
827  range( GM_.nb_geological_entities( Layer3D::type_name_static() ) ) )
828  {
829  float red = std::fmod( GEO::Numeric::random_float32(), 1.f );
830  float green = std::fmod( GEO::Numeric::random_float32(), 1.f );
831  float blue = std::fmod( GEO::Numeric::random_float32(), 1.f );
832  const GeoModelGeologicalEntity3D& cur_layer =
833  GM_.geological_entity( Layer3D::type_name_static(), l );
834  for( auto r : range( cur_layer.nb_children() ) )
835  GM_gfx_.regions.set_region_color(
836  cur_layer.child( r ).index(), red, green, blue );
837  }
838  }
839 
840  void RINGMeshApplication::GeoModelViewer< 3 >::draw_scene()
841  {
842  GeoModelViewerBase3D::draw_scene();
843 
844  if( show_volume_ && meshed_regions_ )
845  {
846  GM_gfx_.regions.set_mesh_visibility( mesh_visible_ );
847  if( colored_cells_.need_to_update() )
848  {
849  colored_cells_.update();
850  if( colored_cells_.new_status )
851  {
852  toggle_colored_cells();
853  }
854  }
855  else if( show_colored_regions_.need_to_update() )
856  {
857  show_colored_regions_.update();
858  if( show_colored_regions_.new_status )
859  {
860  toggle_colored_regions();
861  }
862  }
863  else if( show_colored_layers_.need_to_update() )
864  {
865  show_colored_layers_.update();
866  if( show_colored_layers_.new_status )
867  {
868  toggle_colored_layers();
869  }
870  }
871  if( !colored_cells_.new_status && !show_colored_regions_.new_status
872  && !show_colored_layers_.new_status )
873  {
874  colored_cells_.update();
875  show_colored_regions_.update();
876  show_colored_layers_.update();
877  GM_gfx_.regions.set_mesh_color( mesh_color_.Value.x,
878  mesh_color_.Value.y, mesh_color_.Value.z );
879  GM_gfx_.regions.set_region_color( volume_style_.color_.Value.x,
880  volume_style_.color_.Value.y,
881  volume_style_.color_.Value.z );
882  }
883  GM_gfx_.regions.set_mesh_size(
884  static_cast< index_t >( volume_style_.size_ ) );
885  if( selected_entity_type_ == 0 )
886  {
887  GM_gfx_.regions.set_vertex_visibility(
888  volume_style_.visible_vertices_ );
889  }
890  if( volume_style_.visible_vertices_ )
891  {
892  GM_gfx_.regions.set_vertex_size(
893  static_cast< index_t >( volume_style_.vertex_size_ ) );
894  GM_gfx_.regions.set_vertex_color(
895  volume_style_.vertex_color_.Value.x,
896  volume_style_.vertex_color_.Value.y,
897  volume_style_.vertex_color_.Value.z );
898  }
899  GM_gfx_.regions.set_draw_cells( CellType::HEXAHEDRON, show_hex_ );
900  GM_gfx_.regions.set_draw_cells( CellType::PRISM, show_prism_ );
901  GM_gfx_.regions.set_draw_cells( CellType::PYRAMID, show_pyramid_ );
902  GM_gfx_.regions.set_draw_cells(
903  CellType::TETRAHEDRON, show_tetra_ );
904  GM_gfx_.regions.set_shrink( static_cast< double >( shrink_ ) );
905  GM_gfx_.regions.draw();
906  }
907  }
908 
909  void RINGMeshApplication::GeoModelViewer< 3 >::update_all_entity_visibility(
910  bool value )
911  {
912  GeoModelViewerBase3D::update_all_entity_visibility( value );
913  GM_gfx_.regions.set_region_visibility( value );
914  if( volume_style_.visible_vertices_ )
915  {
916  GM_gfx_.regions.set_vertex_visibility( value );
917  }
918  }
919 
920  void RINGMeshApplication::GeoModelViewer< 3 >::
921  toggle_region_and_boundaries_visibility( index_t region_id )
922  {
923  GM_gfx_.regions.set_region_visibility( region_id, true );
924  GM_gfx_.regions.set_vertex_visibility(
925  region_id, volume_style_.visible_vertices_ );
926  const Region3D& region = GM_.region( region_id );
927  for( auto i : range( region.nb_boundaries() ) )
928  {
929  toggle_surface_and_boundaries_visibility(
930  region.boundary_gmme( i ).index() );
931  }
932  }
933 
934  void RINGMeshApplication::GeoModelViewer< 3 >::
935  toggle_mesh_entity_and_boundaries_visibility( const gmme_id& entity_id )
936  {
937  const MeshEntityTypeManager3D& manager =
938  GM_.entity_type_manager().mesh_entity_manager;
939  if( manager.is_region( entity_id.type() ) )
940  {
941  toggle_region_and_boundaries_visibility( entity_id.index() );
942  }
943  else
944  {
945  GeoModelViewerBase3D::toggle_mesh_entity_and_boundaries_visibility(
946  entity_id );
947  }
948  }
949 
950  void RINGMeshApplication::GeoModelViewer< 3 >::draw_object_properties()
951  {
952  GeoModelViewerBase3D::draw_object_properties();
953 
954  if( meshed_regions_ )
955  {
956  ImGui::Separator();
957  ImGui::Checkbox( "Region [v]", &show_volume_ );
958  draw_entity_style_editor( "##VolumeColor", volume_style_ );
959  ImGui::Checkbox(
960  "Vertices##Region", &volume_style_.visible_vertices_ );
961  if( volume_style_.visible_vertices_ )
962  {
963  draw_entity_vertex_style_editor(
964  "##VolumeVertexColor", volume_style_ );
965  }
966  if( show_volume_ )
967  {
968  ImGui::Checkbox( "Col. cells [C]", &colored_cells_.new_status );
969  ImGui::Checkbox(
970  "Col. regions [r]", &show_colored_regions_.new_status );
971  if( GM_.entity_type_manager()
972  .geological_entity_manager.is_valid_type(
973  Layer3D::type_name_static() ) )
974  {
975  ImGui::Checkbox(
976  "Col. layers [R]", &show_colored_layers_.new_status );
977  }
978  ImGui::SliderFloat( "Shrk.", &shrink_, 0.0f, 1.0f, "%.1f" );
979  ImGui::Checkbox( "Hex", &show_hex_ );
980  ImGui::Checkbox( "Prism", &show_prism_ );
981  ImGui::Checkbox( "Pyramid", &show_pyramid_ );
982  ImGui::Checkbox( "Tetra", &show_tetra_ );
983  }
984  }
985  }
986  /*****************************************************************/
987 
988  RINGMeshApplication::MeshViewer::MeshViewer(
989  RINGMeshApplication& app, const std::string& filename )
990  : app_( app )
991  {
992  vertices_color_ = green;
993 
994  if( !filename.empty() )
995  {
996  GEO::mesh_load( filename, mesh_ );
997  name_ = GEO::FileSystem::base_name( filename, true );
998  }
999  mesh_gfx_.set_mesh( &mesh_ );
1000 
1001  for( auto v : range( mesh_.vertices.nb() ) )
1002  {
1003  bbox_.add_point( mesh_.vertices.point( v ) );
1004  }
1005  }
1006 
1007  void RINGMeshApplication::MeshViewer::draw_object_properties()
1008  {
1009  ImGui::Checkbox( "attributes", &show_attributes_ );
1010  if( show_attributes_ )
1011  {
1012  if( attribute_min_ == 0.0f && attribute_max_ == 0.0f )
1013  {
1014  autorange();
1015  }
1016  if( ImGui::Button(
1017  ( attribute_ + "##Attribute" ).c_str(), ImVec2( -1, 0 ) ) )
1018  {
1019  ImGui::OpenPopup( "##Attributes" );
1020  }
1021  if( ImGui::BeginPopup( "##Attributes" ) )
1022  {
1023  std::vector< std::string > attributes;
1024  GEO::String::split_string( attribute_names(), ';', attributes );
1025  for( const std::string& att : attributes )
1026  {
1027  if( ImGui::Button( att.c_str() ) )
1028  {
1029  set_attribute( att );
1030  ImGui::CloseCurrentPopup();
1031  }
1032  }
1033  ImGui::EndPopup();
1034  }
1035  ImGui::InputFloat( "min", &attribute_min_ );
1036  ImGui::InputFloat( "max", &attribute_max_ );
1037  if( ImGui::Button( "autorange", ImVec2( -1, 0 ) ) )
1038  {
1039  autorange();
1040  }
1041  if( ImGui::ImageButton(
1042  app_.convert_to_ImTextureID( current_colormap_texture_ ),
1043  ImVec2( 115, 8 ) ) )
1044  {
1045  ImGui::OpenPopup( "##Colormap" );
1046  }
1047  if( ImGui::BeginPopup( "##Colormap" ) )
1048  {
1049  for( const auto& colormap : app_.colormaps_ )
1050  {
1051  if( ImGui::ImageButton(
1052  app_.convert_to_ImTextureID( colormap.texture ),
1053  ImVec2( 100, 8 ) ) )
1054  {
1055  current_colormap_texture_ = colormap.texture;
1056  ImGui::CloseCurrentPopup();
1057  }
1058  }
1059  ImGui::EndPopup();
1060  }
1061  }
1062 
1063  ImGui::Separator();
1064  ImGui::Checkbox( "Vertices [p]", &show_vertices_ );
1065  if( show_vertices_ )
1066  {
1067  ImGui::SliderFloat( "sz.", &vertices_size_, 0.1f, 5.0f, "%.1f" );
1068  ImGui::PushStyleColor( ImGuiCol_Button, vertices_color_ );
1069  if( ImGui::Button( " ##VerticesColor" ) )
1070  {
1071  ImGui::OpenPopup( "##VerticesColorTable" );
1072  }
1073  ImGui::PopStyleColor();
1074  if( ImGui::BeginPopup( "##VerticesColorTable" ) )
1075  {
1076  show_color_table_popup( vertices_color_ );
1077  }
1078  ImGui::SameLine();
1079  ImGui::Text( "color" );
1080  }
1081 
1082  if( mesh_.facets.nb() != 0 )
1083  {
1084  ImGui::Separator();
1085  ImGui::Checkbox( "Surface [S]", &show_surface_ );
1086  if( show_surface_ )
1087  {
1088  ImGui::Checkbox( "colors [c]", &show_surface_colors_ );
1089  ImGui::Checkbox( "mesh [m]", &show_mesh_ );
1090  ImGui::Checkbox( "borders [B]", &show_surface_borders_ );
1091  }
1092  }
1093 
1094  if( mesh_.cells.nb() != 0 )
1095  {
1096  ImGui::Separator();
1097  ImGui::Checkbox( "Volume [V]", &show_volume_ );
1098  if( show_volume_ )
1099  {
1100  ImGui::SliderFloat(
1101  "shrk.", &cells_shrink_, 0.0f, 1.0f, "%.2f" );
1102  if( !mesh_.cells.are_simplices() )
1103  {
1104  ImGui::Checkbox(
1105  "colored cells [C]", &show_colored_cells_ );
1106  ImGui::Checkbox( "hexes [j]", &show_hexes_ );
1107  }
1108  }
1109  }
1110  }
1111 
1112  void RINGMeshApplication::MeshViewer::draw_scene()
1113  {
1114  mesh_gfx_.set_lighting( app_.lighting_ );
1115 
1116  if( show_attributes_ )
1117  {
1118  mesh_gfx_.set_scalar_attribute( attribute_subelements_,
1119  attribute_name_, double( attribute_min_ ),
1120  double( attribute_max_ ), current_colormap_texture_, 1 );
1121  }
1122  else
1123  {
1124  mesh_gfx_.unset_scalar_attribute();
1125  }
1126 
1127  if( show_vertices_ )
1128  {
1129  mesh_gfx_.set_points_size( vertices_size_ );
1130  mesh_gfx_.set_points_color( vertices_color_.Value.x,
1131  vertices_color_.Value.y, vertices_color_.Value.z );
1132  mesh_gfx_.draw_vertices();
1133  }
1134 
1135  if( app_.white_bg_ )
1136  {
1137  mesh_gfx_.set_mesh_color( 0.0, 0.0, 0.0 );
1138  }
1139  else
1140  {
1141  mesh_gfx_.set_mesh_color( 1.0, 1.0, 1.0 );
1142  }
1143 
1144  if( show_surface_colors_ )
1145  {
1146  if( mesh_.cells.nb() == 0 )
1147  {
1148  mesh_gfx_.set_surface_color( 0.5f, 0.75f, 1.0f );
1149  mesh_gfx_.set_backface_surface_color( 1.0f, 0.0f, 0.0f );
1150  }
1151  else
1152  {
1153  mesh_gfx_.set_surface_color( 0.7f, 0.0f, 0.0f );
1154  mesh_gfx_.set_backface_surface_color( 1.0f, 1.0f, 0.0f );
1155  }
1156  }
1157  else
1158  {
1159  if( app_.white_bg_ )
1160  {
1161  mesh_gfx_.set_surface_color( 0.9f, 0.9f, 0.9f );
1162  }
1163  else
1164  {
1165  mesh_gfx_.set_surface_color( 0.1f, 0.1f, 0.1f );
1166  }
1167  }
1168 
1169  mesh_gfx_.set_show_mesh( show_mesh_ );
1170 
1171  if( show_surface_ )
1172  {
1173  mesh_gfx_.draw_surface();
1174  }
1175 
1176  if( show_surface_borders_ )
1177  {
1178  mesh_gfx_.draw_surface_borders();
1179  }
1180 
1181  if( show_mesh_ )
1182  {
1183  mesh_gfx_.draw_edges();
1184  }
1185 
1186  if( show_volume_ )
1187  {
1188  if( glupIsEnabled( GLUP_CLIPPING )
1189  && glupGetClipMode() == GLUP_CLIP_SLICE_CELLS )
1190  {
1191  mesh_gfx_.set_lighting( false );
1192  }
1193 
1194  mesh_gfx_.set_shrink( double( cells_shrink_ ) );
1195  mesh_gfx_.set_draw_cells( GEO::MESH_HEX, show_hexes_ );
1196  if( show_colored_cells_ )
1197  {
1198  mesh_gfx_.set_cells_colors_by_type();
1199  }
1200  else
1201  {
1202  mesh_gfx_.set_cells_color( 0.9f, 0.9f, 0.9f );
1203  }
1204  mesh_gfx_.draw_volume();
1205 
1206  mesh_gfx_.set_lighting( app_.lighting_ );
1207  }
1208  }
1209 
1210  void RINGMeshApplication::MeshViewer::autorange()
1211  {
1212  if( attribute_subelements_ != GEO::MESH_NONE )
1213  {
1214  attribute_min_ = 0.0;
1215  attribute_max_ = 0.0;
1216  const GEO::MeshSubElementsStore& subelements =
1217  mesh_.get_subelements_by_type( attribute_subelements_ );
1218  GEO::ReadOnlyScalarAttributeAdapter attribute(
1219  subelements.attributes(), attribute_name_ );
1220  if( attribute.is_bound() )
1221  {
1222  attribute_min_ = GEO::Numeric::max_float32();
1223  attribute_max_ = GEO::Numeric::min_float32();
1224  for( auto i : range( subelements.nb() ) )
1225  {
1226  attribute_min_ =
1227  GEO::geo_min( attribute_min_, float( attribute[i] ) );
1228  attribute_max_ =
1229  GEO::geo_max( attribute_max_, float( attribute[i] ) );
1230  }
1231  }
1232  }
1233  }
1234 
1235  std::string RINGMeshApplication::MeshViewer::attribute_names()
1236  {
1237  return mesh_.get_scalar_attributes();
1238  }
1239 
1240  void RINGMeshApplication::MeshViewer::set_attribute(
1241  const std::string& attribute )
1242  {
1243  attribute_ = attribute;
1244  std::string subelements_name;
1245  GEO::String::split_string(
1246  attribute_, '.', subelements_name, attribute_name_ );
1247  attribute_subelements_ =
1248  mesh_.name_to_subelements_type( subelements_name );
1249  if( attribute_min_ == 0.0f && attribute_max_ == 0.0f )
1250  {
1251  autorange();
1252  }
1253  }
1254 
1255  /*****************************************************************/
1256 
1257  RINGMeshApplication::RINGMeshApplication( int argc, char** argv )
1258  : GEO::Application( argc, argv, "<filename>" )
1259  {
1260  GEO::CmdLine::declare_arg( "attributes", true, "load mesh attributes" );
1261  GEO::CmdLine::declare_arg(
1262  "single_precision", false, "use single precision vertices (FP32)" );
1264 
1265  auto ringmesh_2d_extensions =
1266  GeoModelIOHandlerFactory2D::list_creators();
1267  auto ringmesh_3d_extensions =
1268  GeoModelIOHandlerFactory3D::list_creators();
1269  ringmesh_file_extensions_ =
1270  GEO::String::join_strings( ringmesh_2d_extensions, ';' )
1271  + GEO::String::join_strings( ringmesh_3d_extensions, ';' );
1272 
1273  std::vector< std::string > geogram_extensions;
1274  GEO::MeshIOHandlerFactory::list_creators( geogram_extensions );
1275  geogram_file_extensions_ =
1276  GEO::String::join_strings( geogram_extensions, ';' );
1277 
1279 
1280  Logger::div( "RINGMesh-View" );
1281  Logger::out( "", "Welcome to RINGMesh-View !" );
1282  }
1283 
1284  void RINGMeshApplication::quit()
1285  {
1286  glup_viewer_exit_main_loop();
1287  Logger::instance()->unregister_client( console_ );
1288  }
1289 
1290  RINGMeshApplication* RINGMeshApplication::instance()
1291  {
1292  RINGMeshApplication* result = dynamic_cast< RINGMeshApplication* >(
1293  GEO::Application::instance() );
1294  ringmesh_assert( result != nullptr );
1295  return result;
1296  }
1297 
1298  void RINGMeshApplication::browse_geogram( const std::string& path )
1299  {
1300  std::vector< std::string > files;
1301  GEO::FileSystem::get_directory_entries( path, files );
1302  std::sort( files.begin(), files.end() );
1303  for( const std::string& file : files )
1304  {
1305  if( GEO::FileSystem::is_directory( file ) )
1306  {
1307  if( ImGui::BeginMenu( path_to_label( path_, file ).c_str() ) )
1308  {
1309  browse_geogram( file );
1310  ImGui::EndMenu();
1311  }
1312  }
1313  else
1314  {
1315  if( can_load_geogram( file ) )
1316  {
1317  if( ImGui::MenuItem(
1318  path_to_label( path_, file ).c_str() ) )
1319  {
1320  load_geogram( file );
1321  }
1322  }
1323  }
1324  }
1325  }
1326 
1327  bool RINGMeshApplication::can_load_geogram( const std::string& filename )
1328  {
1329  std::string extensions_str = supported_geogram_read_file_extensions();
1330  if( extensions_str == "" )
1331  {
1332  return false;
1333  }
1334  if( extensions_str == "*" )
1335  {
1336  return true;
1337  }
1338  std::string extension = GEO::FileSystem::extension( filename );
1339  std::vector< std::string > extensions;
1340  GEO::String::split_string( extensions_str, ';', extensions );
1341  for( const std::string& ext : extensions )
1342  {
1343  if( ext == extension )
1344  {
1345  return true;
1346  }
1347  }
1348  return false;
1349  }
1350 
1351  bool RINGMeshApplication::load_geogram( const std::string& filename )
1352  {
1353  if( !filename.empty() )
1354  {
1355  meshes_.emplace_back( new MeshViewer( *this, filename ) );
1356  current_viewer_ = static_cast< index_t >( meshes_.size() - 1 );
1357  current_viewer_type_ = ViewerType::MESH;
1358  }
1359 
1360  update_region_of_interest();
1361  return true;
1362  }
1363 
1364  void RINGMeshApplication::draw_application_menus()
1365  {
1366  if( ImGui::BeginMenu( "Debug" ) )
1367  {
1368  if( ImGui::BeginMenu( "Load..." ) )
1369  {
1370  ImGui::Selectable( ".." );
1371  if( ImGui::IsItemClicked() )
1372  {
1373  path_ += "/..";
1374  }
1375  browse_geogram( path_ );
1376  ImGui::EndMenu();
1377  }
1378  ImGui::EndMenu();
1379  }
1380  if( ImGui::BeginMenu( "Create..." ) )
1381  {
1382  if( ImGui::MenuItem( "point" ) )
1383  {
1384  GEO::Command::set_current(
1385  "create_point(std::string name=\"debug\","
1386  " double x=0, double y=0, double z=0)",
1387  this, &RINGMeshApplication::create_point );
1388  }
1389  if( ImGui::MenuItem( "AABB" ) )
1390  {
1391  GEO::Command::set_current(
1392  "create_aabbox(std::string name=\"box\","
1393  " double xmin=0, double ymin=0, double zmin=0,"
1394  " double xmax=1, double ymax=1, double zmax=1)",
1395  this, &RINGMeshApplication::create_aabbox );
1396  }
1397  ImGui::EndMenu();
1398  }
1399  }
1400 
1401  void RINGMeshApplication::create_point(
1402  std::string name, double x, double y, double z )
1403  {
1404  MeshViewer* viewer{ nullptr };
1405  for( auto& i : meshes_ )
1406  {
1407  if( i->name_ == name )
1408  {
1409  viewer = i.get();
1410  break;
1411  }
1412  }
1413  if( !viewer )
1414  {
1415  meshes_.emplace_back( new MeshViewer( *this, "" ) );
1416  viewer = meshes_.back().get();
1417  }
1418  vec3 point{ x, y, z };
1419  viewer->mesh_.vertices.create_vertex( point.data() );
1420  viewer->mesh_gfx_.set_mesh( &viewer->mesh_ );
1421  viewer->bbox_.add_point( point );
1422  viewer->name_ = name;
1423  viewer->show_vertices_ = true;
1424  current_viewer_ = static_cast< index_t >( meshes_.size() - 1 );
1425  current_viewer_type_ = ViewerType::MESH;
1426  update_region_of_interest();
1427  }
1428 
1429  void RINGMeshApplication::create_aabbox( std::string name,
1430  double xmin,
1431  double ymin,
1432  double zmin,
1433  double xmax,
1434  double ymax,
1435  double zmax )
1436  {
1437  vec3 min{ xmin, ymin, zmin };
1438  vec3 max{ xmax, ymax, zmax };
1439  MeshViewer* viewer{ nullptr };
1440  for( auto& i : meshes_ )
1441  {
1442  if( i->name_ == name )
1443  {
1444  viewer = i.get();
1445  break;
1446  }
1447  }
1448  if( !viewer )
1449  {
1450  meshes_.emplace_back( new MeshViewer( *this, "" ) );
1451  viewer = meshes_.back().get();
1452  }
1453  const index_t prev_nbv{ viewer->mesh_.vertices.nb() };
1454  vec3 box_other_vertex1{ min[0], min[1], max[2] };
1455  vec3 box_other_vertex2{ min[0], max[1], max[2] };
1456  vec3 box_other_vertex3{ max[0], min[1], max[2] };
1457  vec3 box_other_vertex4{ max[0], max[1], min[2] };
1458  vec3 box_other_vertex5{ max[0], min[1], min[2] };
1459  vec3 box_other_vertex6{ min[0], max[1], min[2] };
1460  viewer->mesh_.vertices.create_vertex( min.data() );
1461  viewer->mesh_.vertices.create_vertex( box_other_vertex1.data() );
1462  viewer->mesh_.vertices.create_vertex( box_other_vertex2.data() );
1463  viewer->mesh_.vertices.create_vertex( box_other_vertex3.data() );
1464  viewer->mesh_.vertices.create_vertex( box_other_vertex4.data() );
1465  viewer->mesh_.vertices.create_vertex( box_other_vertex5.data() );
1466  viewer->mesh_.vertices.create_vertex( box_other_vertex6.data() );
1467  viewer->mesh_.vertices.create_vertex( max.data() );
1468  viewer->mesh_.edges.create_edge( prev_nbv + 0, prev_nbv + 1 );
1469  viewer->mesh_.edges.create_edge( prev_nbv + 0, prev_nbv + 5 );
1470  viewer->mesh_.edges.create_edge( prev_nbv + 0, prev_nbv + 6 );
1471  viewer->mesh_.edges.create_edge( prev_nbv + 1, prev_nbv + 2 );
1472  viewer->mesh_.edges.create_edge( prev_nbv + 1, prev_nbv + 3 );
1473  viewer->mesh_.edges.create_edge( prev_nbv + 2, prev_nbv + 6 );
1474  viewer->mesh_.edges.create_edge( prev_nbv + 2, prev_nbv + 7 );
1475  viewer->mesh_.edges.create_edge( prev_nbv + 3, prev_nbv + 5 );
1476  viewer->mesh_.edges.create_edge( prev_nbv + 3, prev_nbv + 7 );
1477  viewer->mesh_.edges.create_edge( prev_nbv + 4, prev_nbv + 5 );
1478  viewer->mesh_.edges.create_edge( prev_nbv + 4, prev_nbv + 6 );
1479  viewer->mesh_.edges.create_edge( prev_nbv + 4, prev_nbv + 7 );
1480  viewer->mesh_.facets.create_quad(
1481  prev_nbv + 0, prev_nbv + 6, prev_nbv + 4, prev_nbv + 5 );
1482  viewer->mesh_.facets.create_quad(
1483  prev_nbv + 0, prev_nbv + 1, prev_nbv + 2, prev_nbv + 6 );
1484  viewer->mesh_.facets.create_quad(
1485  prev_nbv + 0, prev_nbv + 5, prev_nbv + 3, prev_nbv + 1 );
1486  viewer->mesh_.facets.create_quad(
1487  prev_nbv + 7, prev_nbv + 2, prev_nbv + 1, prev_nbv + 3 );
1488  viewer->mesh_.facets.create_quad(
1489  prev_nbv + 7, prev_nbv + 3, prev_nbv + 5, prev_nbv + 4 );
1490  viewer->mesh_.facets.create_quad(
1491  prev_nbv + 7, prev_nbv + 4, prev_nbv + 6, prev_nbv + 2 );
1492  viewer->mesh_gfx_.set_mesh( &viewer->mesh_ );
1493  viewer->bbox_.add_point( min );
1494  viewer->bbox_.add_point( max );
1495  viewer->name_ = name;
1496  viewer->show_vertices_ = false;
1497  viewer->show_mesh_ = true;
1498  viewer->show_surface_borders_ = false;
1499  viewer->show_surface_colors_ = false;
1500  current_viewer_ = static_cast< index_t >( meshes_.size() - 1 );
1501  current_viewer_type_ = ViewerType::MESH;
1502  update_region_of_interest();
1503  }
1504 
1505  void RINGMeshApplication::init_graphics()
1506  {
1507  GEO::Application::init_graphics();
1508 
1509  init_colormaps();
1510  glup_viewer_disable( GLUP_VIEWER_BACKGROUND );
1511  }
1512 
1513  void RINGMeshApplication::show_color_table_popup( ImColor& color )
1514  {
1515  int id = 0;
1516  for( const auto& colors : color_table_ )
1517  {
1518  for( auto j : range( colors.size() ) )
1519  {
1520  if( j > 0 )
1521  {
1522  ImGui::SameLine();
1523  }
1524  ImGui::PushID( id++ );
1525  ImGui::PushStyleColor( ImGuiCol_Button, colors[j] );
1526  if( ImGui::Button( " " ) )
1527  {
1528  color = colors[j];
1529  ImGui::CloseCurrentPopup();
1530  }
1531  ImGui::PopStyleColor();
1532  ImGui::PopID();
1533  }
1534  }
1535  ImGui::EndPopup();
1536  }
1537 
1538  bool RINGMeshApplication::load( const std::string& filename )
1539  {
1540  if( !filename.empty() && GEO::FileSystem::is_file( filename ) )
1541  {
1542  index_t dimension = find_geomodel_dimension( filename );
1543  if( dimension == 2 )
1544  {
1545  geomodels2d_.emplace_back(
1546  new GeoModelViewer2D( *this, filename ) );
1547  current_viewer_ =
1548  static_cast< index_t >( geomodels2d_.size() - 1 );
1549  current_viewer_type_ = ViewerType::GEOMODEL2D;
1550  }
1551  else if( dimension == 3 )
1552  {
1553  geomodels3d_.emplace_back(
1554  new GeoModelViewer3D( *this, filename ) );
1555  current_viewer_ =
1556  static_cast< index_t >( geomodels3d_.size() - 1 );
1557  current_viewer_type_ = ViewerType::GEOMODEL3D;
1558  }
1559  else
1560  {
1562  }
1563  }
1564 
1565  update_region_of_interest();
1566  return true;
1567  }
1568 
1569  void RINGMeshApplication::update_region_of_interest()
1570  {
1571  Box3D bbox;
1572  for( std::unique_ptr< GeoModelViewer2D >& geomodel : geomodels2d_ )
1573  {
1574  if( geomodel->is_visible_ )
1575  {
1576  vec2 min = geomodel->bbox_.min();
1577  vec2 max = geomodel->bbox_.max();
1578  bbox.add_point( vec3( min.x, min.y, 0. ) );
1579  bbox.add_point( vec3( max.x, max.y, 0. ) );
1580  }
1581  }
1582  for( std::unique_ptr< GeoModelViewer3D >& geomodel : geomodels3d_ )
1583  {
1584  if( geomodel->is_visible_ )
1585  {
1586  bbox.add_box( geomodel->bbox_ );
1587  }
1588  }
1589  for( std::unique_ptr< MeshViewer >& mesh : meshes_ )
1590  {
1591  if( mesh->is_visible_ )
1592  {
1593  bbox.add_box( mesh->bbox_ );
1594  }
1595  }
1596 
1597  if( bbox.initialized() )
1598  {
1599  glup_viewer_set_region_of_interest( float( bbox.min()[0] ),
1600  float( bbox.min()[1] ), float( bbox.min()[2] ),
1601  float( bbox.max()[0] ), float( bbox.max()[1] ),
1602  float( bbox.max()[2] ) );
1603  }
1604  }
1605 
1606  void RINGMeshApplication::draw_scene()
1607  {
1608  if( current_viewer_ == NO_ID )
1609  return;
1610 
1611  for( std::unique_ptr< MeshViewer >& mesh : meshes_ )
1612  {
1613  if( mesh->is_visible_ )
1614  {
1615  mesh->draw_scene();
1616  }
1617  }
1618  for( std::unique_ptr< GeoModelViewer2D >& geomodel : geomodels2d_ )
1619  {
1620  if( geomodel->is_visible_ )
1621  {
1622  geomodel->draw_scene();
1623  }
1624  }
1625  for( std::unique_ptr< GeoModelViewer3D >& geomodel : geomodels3d_ )
1626  {
1627  if( geomodel->is_visible_ )
1628  {
1629  geomodel->draw_scene();
1630  }
1631  }
1632 
1633  if( current_viewer_type_ == ViewerType::GEOMODEL2D )
1634  {
1635  GeoModelViewerBase2D& viewer = *geomodels2d_[current_viewer_];
1636  if( viewer.show_colormap_ )
1637  {
1638  viewer.draw_colormap();
1639  }
1640  }
1641  if( current_viewer_type_ == ViewerType::GEOMODEL3D )
1642  {
1643  GeoModelViewerBase3D& viewer = *geomodels3d_[current_viewer_];
1644  if( viewer.show_colormap_ )
1645  {
1646  viewer.draw_colormap();
1647  }
1648  }
1649  }
1650 
1651  std::string RINGMeshApplication::supported_read_file_extensions()
1652  {
1653  return ringmesh_file_extensions_;
1654  }
1655  std::string RINGMeshApplication::supported_geogram_read_file_extensions()
1656  {
1657  return geogram_file_extensions_;
1658  }
1659 
1660  template < index_t DIMENSION >
1661  void RINGMeshApplication::draw_geomodel_viewer_properties(
1662  std::vector< std::unique_ptr< GeoModelViewer< DIMENSION > > >&
1663  geomodels,
1664  int& id )
1665  {
1666  if( !geomodels.empty() )
1667  {
1668  ImGui::Separator();
1669  std::ostringstream oss;
1670  oss << "GeoModel" << DIMENSION << "D";
1671  ImGui::Text( "%s", oss.str().c_str() );
1672  for( auto i : range( geomodels.size() ) )
1673  {
1674  GeoModelViewer< DIMENSION >& viewer = *geomodels[i];
1675  ImGui::PushID( id++ );
1676  if( ImGui::Checkbox(
1677  viewer.GM_.name().c_str(), &viewer.is_visible_ ) )
1678  {
1679  current_viewer_ = i;
1680  current_viewer_type_ = viewer.type();
1681  update_region_of_interest();
1682  }
1683  ImGui::SameLine( ImGui::GetWindowWidth() - 30 );
1684  if( ImGui::Button( "X" ) )
1685  {
1686  geomodels.erase( geomodels.begin() + i );
1687  if( current_viewer_type_ == viewer.type()
1688  && current_viewer_ >= i )
1689  {
1690  current_viewer_--;
1691  }
1692  if( geomodels.empty() )
1693  {
1694  current_viewer_type_ = ViewerType::NONE;
1695  }
1696  break;
1697  }
1698  ImGui::PopID();
1699  }
1700  }
1701  }
1702 
1703  void RINGMeshApplication::draw_viewer_properties()
1704  {
1705  GEO::Application::draw_viewer_properties();
1706 
1707  int id = 0;
1708  draw_geomodel_viewer_properties( geomodels2d_, id );
1709  draw_geomodel_viewer_properties( geomodels3d_, id );
1710 
1711  if( !meshes_.empty() )
1712  {
1713  ImGui::Separator();
1714  ImGui::Text( "Mesh" );
1715  for( auto i : range( meshes_.size() ) )
1716  {
1717  MeshViewer& viewer = *meshes_[i];
1718  ImGui::PushID( id++ );
1719  if( ImGui::Checkbox(
1720  viewer.name_.c_str(), &viewer.is_visible_ ) )
1721  {
1722  current_viewer_ = i;
1723  current_viewer_type_ = ViewerType::MESH;
1724  update_region_of_interest();
1725  }
1726  ImGui::SameLine( ImGui::GetWindowWidth() - 30 );
1727  if( ImGui::Button( "X" ) )
1728  {
1729  meshes_.erase( meshes_.begin() + i );
1730  if( current_viewer_type_ == ViewerType::MESH
1731  && current_viewer_ >= i )
1732  {
1733  current_viewer_--;
1734  }
1735  if( meshes_.empty() )
1736  {
1737  current_viewer_type_ = ViewerType::NONE;
1738  }
1739  break;
1740  }
1741  ImGui::PopID();
1742  }
1743  }
1744  }
1745 
1746  void RINGMeshApplication::draw_object_properties()
1747  {
1748  if( current_viewer_ == NO_ID )
1749  return;
1750  switch( current_viewer_type_ )
1751  {
1752  case ViewerType::GEOMODEL2D:
1753  ringmesh_assert( current_viewer_ < geomodels2d_.size() );
1754  geomodels2d_[current_viewer_]->draw_object_properties();
1755  return;
1756  case ViewerType::GEOMODEL3D:
1757  ringmesh_assert( current_viewer_ < geomodels3d_.size() );
1758  geomodels3d_[current_viewer_]->draw_object_properties();
1759  return;
1760  case ViewerType::MESH:
1761  ringmesh_assert( current_viewer_ < meshes_.size() );
1762  meshes_[current_viewer_]->draw_object_properties();
1763  return;
1764  default:
1765  return;
1766  }
1767  }
1768 
1769  ColorTable RINGMeshApplication::color_table_ = create_color_table();
1770 } // namespace RINGMesh
1771 
1772 #endif
Abstract base class for GeoModelMeshEntity.
void RINGMESH_API print_header_information()
Definition: common.cpp:106
const vecn< DIMENSION > & vertex(index_t vertex_index) const
Coordinates of the vertex_index.
The GeologicalEntityType described the type of the Geological entities User can defined there own Geo...
Definition: entity_type.h:137
vecn< 3 > vec3
Definition: types.h:76
bool is_line(const MeshEntityType &type) const
const gmme_id & boundary_gmme(index_t x) const
Entity_type_template type() const
Definition: entity_type.h:202
static void div(const std::string &title)
Definition: logger.h:54
bool geomodel_load(GeoModel< DIMENSION > &geomodel, const std::string &filename)
Definition: io.cpp:131
vecn< 2 > vec2
Definition: types.h:78
bool is_surface(const MeshEntityType &type) const
void add_point(const vecn< DIMENSION > &p)
Definition: box.cpp:57
bool is_corner(const MeshEntityType &type) const
static void out(const std::string &feature, const Args &... args)
Definition: logger.h:61
static GEO::Logger * instance()
Definition: logger.h:81
const gmme_id & child_gmme(index_t x) const
const vecn< DIMENSION > & min() const
Definition: box.h:61
index_t RINGMESH_API find_geomodel_dimension(const std::string &filename)
Definition: io.cpp:110
#define ringmesh_assert(x)
The MeshEntityType described the type of the meshed entities There are 4 MeshEntityTypes correspondin...
Definition: entity_type.h:117
This template is a specialization of a gme_id to the GeoModelGeologicalEntity.
Definition: entity_type.h:262
Classes to build GeoModel from various inputs.
Definition: algorithm.h:48
A GeoModelEntity of type LINE.
index_t index() const
Definition: entity_type.h:197
void RINGMESH_API configure_ringmesh()
Definition: common.cpp:84
This template is a specialization of a gme_id to the GeoModelMeshEntity.
Definition: entity_type.h:285
#define ringmesh_assert_not_reached