1 #include "config.h"
2 
3 #include <boost/config.hpp>
4 #if defined(BOOST_MSVC)
5 #  pragma warning( disable : 4503)
6 #endif
7 
8 #include <CGAL/Three/Viewer_interface.h>
9 #include <CGAL/Three/Polyhedron_demo_plugin_interface.h>
10 #include <CGAL/Three/Polyhedron_demo_plugin_helper.h>
11 #include <CGAL/Three/Three.h>
12 
13 #include "Scene_c3t3_item.h"
14 
15 #include <fstream>
16 #include <map>
17 #include <set>
18 #include <cmath>
19 
20 #include <QFileInfo>
21 #include <QFileDialog>
22 #include <QAction>
23 #include <QMainWindow>
24 #include <QColor>
25 #include <QPixmap>
26 #include <QBitmap>
27 #include "ui_Rib_dialog.h"
28 
29 
30 // Constants
31 #define CGAL_RIB_NON_TRANSPARENT_MATERIAL_ALPHA 1
32 using namespace CGAL::Three;
33 
34 class C3t3_rib_exporter_plugin :
35   public QObject,
36   protected Polyhedron_demo_plugin_helper
37 {
38   Q_OBJECT
39   Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface)
40   Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0" FILE "c3t3_rib_exporter_plugin.json")
41 
42 public:
43   C3t3_rib_exporter_plugin();
~C3t3_rib_exporter_plugin()44   virtual ~C3t3_rib_exporter_plugin() {}
45 
46   void init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*);
actions() const47   QList<QAction*> actions() const
48   {
49     return QList<QAction*>() << actionCreateRib;
50   }
applicable(QAction *) const51   bool applicable(QAction*)const{
52     Scene_c3t3_item* item = qobject_cast<Scene_c3t3_item*>(scene->item(scene->mainSelectionIndex()));
53     return item && item->is_valid();}
54 
55 public Q_SLOTS:
56   void create_rib();
57   void height_changed(int i);
58   void width_changed(int i);
59 
60 private:
61   typedef Tr::Bare_point                    Bare_point;
62   typedef Tr::Weighted_point                Weighted_point;
63 
64   typedef Geom_traits::Vector_3             Vector_3;
65   typedef Geom_traits::Plane_3              Plane;
66   typedef Geom_traits::FT                   FT;
67   typedef Geom_traits::Aff_transformation_3 Aff_transformation_3;
68 
69   typedef CGAL::qglviewer::Vec qglVec;
70 
71   enum Rib_exporter_mode { CUT=0, MESH, TRIANGULATION };
72 
73   struct Rib_exporter_parameters
74   {
75     // Materials
76     double sphere_radius;
77     double cylinder_radius;
78 
79     // Lights
80     bool ambientOn;
81     double ambientIntensity;
82     bool shadowOn;
83     double shadowIntensity;
84 
85     // Picture
86     int width;
87     int height;
88     Rib_exporter_mode mode;
89     bool is_preview;
90   };
91 
92 private:
93   void update_mask();
94 
95   bool get_parameters_from_dialog();
96 
97   QStringList nameFilters() const;
98   bool save(const Scene_c3t3_item&, const QFileInfo& fileinfo);
99   void init_maps(const C3t3& c3t3, const QColor& color);
100   void init_point_radius(const C3t3& c3t3);
101   void init_parameters();
102 
103   Bare_point camera_coordinates(const Bare_point& p);
104   void fill_points_and_edges_map(const C3t3& c3t3);
105 
106   void add_edge(const Bare_point& p, const Bare_point& q, const QColor& color);
107   void add_vertex(const Bare_point& p, const QColor& color);
108 
109   void write_header(const std::string& filename, std::ofstream& out);
110 
111   void write_lights(std::ofstream& out);
112   void write_turn_background_light(bool turn_on, std::ofstream& out);
113 
114   void write_facets(const C3t3& c3t3, std::ofstream& out);
115   void write_facets(const C3t3& c3t3, const Plane& plane, std::ofstream& out);
116   void write_surface_cells(const C3t3& c3t3, const Plane& plane, std::ofstream& out);
117   void write_cells_intersecting_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out);
118   void write_cells_on_the_positive_side_of_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out);
119 
120   void write_triangle(const Bare_point& p, const Bare_point& q, const Bare_point& r,
121                       const QColor& color, const QColor& edge_color, std::ofstream& out);
122   void write_tetrahedron (const Bare_point& p, const Bare_point& q, const Bare_point& r, const Bare_point& s,
123                           const QColor& color, const QColor& edge_color, std::ofstream& out);
124 
125   void write_point(const Bare_point& p, std::ofstream& out);
126   void write_point_sphere(const Bare_point& p, std::ofstream& out);
127 
128   void write_edge_cylinder(const Bare_point& p, const Bare_point& q, std::ofstream& out);
129 
130   // Writes data which has been stored during triangle drawing
131   void write_edges_flat(std::ofstream& out);
132   void write_edges_volumic(std::ofstream& out);
133   void write_vertices_volumic(std::ofstream& out);
134 
135   void write_color(const QColor& color, bool use_transparency, std::ofstream& out);
136   void write_opacity(const double alpha, std::ofstream& out);
137 
138   // Background
139   void write_background(const QColor& color, std::ofstream& out);
140 
141 private:
142   QAction* actionCreateRib;
143 
144   // Viewer
145 
146   typedef std::map<C3t3::Surface_patch_index, QColor> Surface_map;
147   typedef std::map<C3t3::Subdomain_index, QColor> Subdomain_map;
148 
149   Surface_map surface_map_;
150   Subdomain_map subdomain_map_;
151 
152   typedef std::map<std::pair<Bare_point, Bare_point>,QColor> Edge_map;
153   typedef std::map<Bare_point, QColor> Vertex_map;
154 
155   Edge_map edges_;
156   Vertex_map vertices_;
157 
158   double zmax_;
159   double diag_;
160 
161   // Cache data to avoid writing too much lines in rib file
162   QColor prev_color_;
163   double prev_alpha_;
164   const Scene_c3t3_item* prev_c3t3_;
165 
166   Rib_exporter_parameters parameters_;
167 };
168 
169 
170 C3t3_rib_exporter_plugin::
C3t3_rib_exporter_plugin()171 C3t3_rib_exporter_plugin()
172   : actionCreateRib(NULL)
173   , zmax_(0)
174   , diag_(0)
175   , prev_color_(0,0,0)
176   , prev_alpha_(1)
177   , prev_c3t3_(NULL)
178 {
179 
180 }
181 
182 
183 void
184 C3t3_rib_exporter_plugin::
init(QMainWindow * mainWindow,Scene_interface * scene_interface,Messages_interface *)185 init(QMainWindow* mainWindow, Scene_interface* scene_interface, Messages_interface*)
186 {
187   this->scene = scene_interface;
188   this->mw = mainWindow;
189 
190   actionCreateRib = new QAction("Export C3t3 to RIB", mw);
191   if( NULL != actionCreateRib )
192   {
193     actionCreateRib->setProperty("subMenuName", "Tetrahedral Mesh Generation");
194     connect(actionCreateRib, SIGNAL(triggered()), this, SLOT(create_rib()));
195   }
196   init_parameters();
197 }
198 
199 
200 void
create_rib()201 C3t3_rib_exporter_plugin::create_rib()
202 {
203   if ( NULL == Three::activeViewer() )
204   {
205     std::cerr << "Can't find viewer" << std::endl;
206     return;
207   }
208 
209   // Get Scene_c3t3_item
210   Scene_interface::Item_id index = scene->mainSelectionIndex();
211 
212   Scene_c3t3_item* c3t3_item =
213     qobject_cast<Scene_c3t3_item*>(scene->item(index));
214 
215   if ( NULL == c3t3_item )
216   {
217     return;
218   }
219 
220   // Init data
221   //if ( c3t3_item != prev_c3t3_ ) // Commented because it was causing problems
222                                    // when changing the color of the c3t3
223   {
224     init_maps(c3t3_item->c3t3(), c3t3_item->color());
225     init_point_radius(c3t3_item->c3t3());
226     init_parameters();
227 
228     prev_c3t3_ = c3t3_item;
229   }
230 
231   // Get parameters from user dialog
232   if ( !get_parameters_from_dialog() )
233   {
234 
235     QBitmap bitmap;
236     bitmap.clear();
237     Three::activeViewer()->setMask(bitmap);
238     return;
239   }
240 
241   // Disable Mask
242   QBitmap bitmap;
243   bitmap.clear();
244   Three::activeViewer()->setMask(bitmap);
245 
246   // Save dialog
247   QStringList filters;
248   filters << nameFilters();
249   filters << tr("All files (*)");
250 
251   QString filename = QFileDialog::getSaveFileName(mw,
252                                                   tr("Save to File..."),
253                                                   QString(),
254                                                   filters.join(";;"));
255 
256   QFileInfo fileinfo(filename);
257 
258   // Save rib file
259   save(*c3t3_item,fileinfo);
260 
261   std::cout << "Rib file created successfully" << std::endl;
262 }
263 
264 
265 void
266 C3t3_rib_exporter_plugin::
height_changed(int i)267 height_changed(int i)
268 {
269   parameters_.height = i;
270   update_mask();
271 }
272 
273 void
274 C3t3_rib_exporter_plugin::
width_changed(int i)275 width_changed(int i)
276 {
277   parameters_.width = i;
278   update_mask();
279 }
280 
281 
282 void
283 C3t3_rib_exporter_plugin::
update_mask()284 update_mask()
285 {
286   double ratio = double(parameters_.width) / double(parameters_.height);
287 
288   if ( NULL == Three::activeViewer() )
289   {
290     std::cerr << "Can't find viewer..." << std::endl;
291     return;
292   }
293   QBitmap bitmap;
294   bitmap.setDevicePixelRatio(ratio);
295   bitmap.fill();
296   Three::activeViewer()->setMask(bitmap);
297 }
298 
299 
300 
301 bool
302 C3t3_rib_exporter_plugin::
get_parameters_from_dialog()303 get_parameters_from_dialog()
304 {
305   QDialog dialog(mw);
306   Ui::Rib_dialog ui;
307   ui.setupUi(&dialog);
308   ui.ambientIntensity->setMaximum(1.0);
309   ui.shadowIntensity->setMaximum(1.0);
310 
311   connect(ui.buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
312   connect(ui.buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
313   connect(ui.resWidth, SIGNAL(valueChanged(int)), this, SLOT(width_changed(int)));
314   connect(ui.resHeight, SIGNAL(valueChanged(int)), this, SLOT(height_changed(int)));
315 
316   // -----------------------------------
317   // Set data
318   // -----------------------------------
319 
320   // Materials
321   ui.sphereRadius->setValue(parameters_.sphere_radius);
322   ui.cylinderRadius->setValue(parameters_.cylinder_radius);
323 
324   // Lights
325   ui.isAmbientOn->setChecked(parameters_.ambientOn);
326   ui.ambientIntensity->setValue(parameters_.ambientIntensity);
327   ui.isShadowOn->setChecked(parameters_.shadowOn);
328   ui.shadowIntensity->setValue(parameters_.shadowIntensity);
329 
330   // Picture
331   QStringList mode_list;
332   mode_list << "Export Cut (draws current cut view)"
333             << "Export Mesh (draws all surface facets)"
334             << "Export Triangulation (draws all points and edges)";
335 
336   ui.exportMode->insertItems(0,mode_list);
337 
338   ui.resWidth->setValue(parameters_.width);
339   ui.resHeight->setValue(parameters_.height);
340   ui.exportMode->setCurrentIndex(static_cast<int>(parameters_.mode));
341   ui.isPreview->setChecked(parameters_.is_preview);
342 
343   // Update mask
344 
345   update_mask();
346 
347   // -----------------------------------
348   // Get data
349   // -----------------------------------
350   int i = dialog.exec();
351   if(i == QDialog::Rejected)
352     return false;
353 
354   // Materials
355   parameters_.sphere_radius = ui.sphereRadius->value();
356   parameters_.cylinder_radius = ui.cylinderRadius->value();
357 
358   // Lights
359   parameters_.ambientOn = ui.isAmbientOn->isChecked();
360   parameters_.ambientIntensity = ui.ambientIntensity->value();
361   parameters_.shadowOn = ui.isShadowOn->isChecked();
362   parameters_.shadowIntensity = ui.shadowIntensity->value();
363 
364   // Picture
365   parameters_.width = ui.resWidth->value();
366   parameters_.height = ui.resHeight->value();
367   parameters_.mode = static_cast<Rib_exporter_mode>(ui.exportMode->currentIndex());
368   parameters_.is_preview = ui.isPreview->isChecked();
369 
370   return true;
371 }
372 
373 
374 QStringList
nameFilters() const375 C3t3_rib_exporter_plugin::nameFilters() const
376 {
377   return QStringList() << "RenderMan file (*.rib)";
378 }
379 
380 
381 bool
382 C3t3_rib_exporter_plugin::
save(const Scene_c3t3_item & c3t3_item,const QFileInfo & fileInfo)383 save(const Scene_c3t3_item& c3t3_item, const QFileInfo& fileInfo)
384 {
385   QString path = fileInfo.absoluteFilePath();
386   std::ofstream rib_file (qPrintable(path));
387   rib_file.precision(8);
388 
389   // Header
390   QString basename = fileInfo.baseName();
391   write_header(qPrintable(basename), rib_file);
392 
393   // Lights
394   write_lights(rib_file);
395 
396   // Triangles
397   switch ( parameters_.mode )
398   {
399     case CUT:
400       rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl;
401       write_facets(c3t3_item.c3t3(), c3t3_item.plane(), rib_file);
402 
403       rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.65 \"Ks\" 0.35 \"roughness\" 0.2" << std::endl;
404       //write_cells_intersecting_a_plane(c3t3_item.c3t3(), c3t3_item.plane(), rib_file);
405       write_cells_on_the_positive_side_of_a_plane(c3t3_item.c3t3(), c3t3_item.plane(), rib_file);
406       break;
407 
408     case MESH:
409       rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl;
410       //write_facets(c3t3_item.c3t3(), rib_file);
411       write_surface_cells(c3t3_item.c3t3(), c3t3_item.plane(), rib_file);
412       break;
413 
414     case TRIANGULATION:
415       fill_points_and_edges_map(c3t3_item.c3t3());
416       break;
417 
418     default:
419       std::cerr << "Unexpected mode found" << std::endl;
420       return false;
421       break;
422   }
423 
424   // Edges and vertices
425   rib_file << "Surface \"plastic\" \"Ka\" 0.65 \"Kd\" 0.85 \"Ks\" 0.25 \"roughness\" 0.1" << std::endl;
426   write_edges_volumic(rib_file);
427   write_vertices_volumic(rib_file);
428 
429   // Background
430   write_background(QColor(255,255,255), rib_file);
431 
432   rib_file << "WorldEnd" << std::endl;
433 
434   return true;
435 }
436 
437 void
init_maps(const C3t3 & c3t3,const QColor & color)438 C3t3_rib_exporter_plugin::init_maps(const C3t3& c3t3, const QColor& color)
439 {
440   surface_map_.clear();
441   subdomain_map_.clear();
442   edges_.clear();
443   vertices_.clear();
444 
445   // Fill maps with 0 as value
446   for ( C3t3::Facets_in_complex_iterator fit = c3t3.facets_in_complex_begin(),
447        fend = c3t3.facets_in_complex_end() ; fit != fend ; ++fit )
448   {
449     surface_map_.insert(std::make_pair(c3t3.surface_patch_index(*fit),QColor(0,0,0)));
450   }
451 
452   for ( C3t3::Cells_in_complex_iterator cit = c3t3.cells_in_complex_begin(),
453        cend = c3t3.cells_in_complex_end() ; cit != cend ; ++cit )
454   {
455     subdomain_map_.insert(std::make_pair(c3t3.subdomain_index(cit),QColor(0,0,0)));
456   }
457 
458   // Fill value of maps
459   size_t nb_colors = subdomain_map_.size(); // + surface_map_.size();
460 
461   // Starting hue
462   double c = color.hueF();
463   int i = 0;
464   for ( Subdomain_map::iterator it = subdomain_map_.begin(), end = subdomain_map_.end();
465        it != end ; ++it, ++i )
466   {
467     double hue = c + 1./nb_colors * i;
468     if ( hue > 1 ) { hue -= 1.; }
469     it->second = QColor::fromHsvF(hue, color.saturationF(), color.valueF());
470   }
471 }
472 
473 
474 void
475 C3t3_rib_exporter_plugin::
init_point_radius(const C3t3 & c3t3)476 init_point_radius(const C3t3& c3t3)
477 {
478   const CGAL::Bbox_3 bbox = c3t3.bbox();
479 
480   const double xdelta = bbox.xmax() - bbox.xmin();
481   const double ydelta = bbox.ymax() - bbox.ymin();
482   const double zdelta = bbox.zmax() - bbox.zmin();
483 
484   diag_ = std::sqrt(xdelta*xdelta + ydelta*ydelta + zdelta*zdelta);
485 
486   parameters_.sphere_radius =  diag_ * 0.0015;
487   parameters_.cylinder_radius =  diag_ * 0.00065;
488 }
489 
490 
491 void
492 C3t3_rib_exporter_plugin::
init_parameters()493 init_parameters()
494 {
495   // Lights
496   parameters_.ambientOn = true;
497   parameters_.ambientIntensity = 0.20;
498   parameters_.shadowOn = true;
499   parameters_.shadowIntensity = 0.85;
500 
501   // Picture
502   parameters_.width = 800;
503   parameters_.height = 800;
504   parameters_.mode = CUT;
505   parameters_.is_preview = false;
506 }
507 
508 
509 C3t3_rib_exporter_plugin::Bare_point
510 C3t3_rib_exporter_plugin::
camera_coordinates(const Bare_point & p)511 camera_coordinates(const Bare_point& p)
512 {
513   qglVec p_vec ( p.x(), p.y(), p.z() );
514   qglVec p_cam = Three::activeViewer()->camera()->cameraCoordinatesOf(p_vec);
515 
516   // Store maximal depth
517   zmax_ = (std::max)(zmax_, double(-p_cam[2]));
518 
519   return Bare_point(p_cam[0],p_cam[1],p_cam[2]);
520 }
521 
522 
523 void
524 C3t3_rib_exporter_plugin::
fill_points_and_edges_map(const C3t3 & c3t3)525 fill_points_and_edges_map(const C3t3& c3t3)
526 {
527   Geom_traits::Construct_point_3 wp2p
528     = c3t3.triangulation().geom_traits().construct_point_3_object();
529 
530   for ( C3t3::Cells_in_complex_iterator it = c3t3.cells_in_complex_begin(),
531        end = c3t3.cells_in_complex_end() ; it != end ; ++it )
532   {
533     const Bare_point& p1 = wp2p(it->vertex(0)->point());
534     const Bare_point& p2 = wp2p(it->vertex(1)->point());
535     const Bare_point& p3 = wp2p(it->vertex(2)->point());
536     const Bare_point& p4 = wp2p(it->vertex(3)->point());
537 
538     const QColor& edge_color = subdomain_map_[c3t3.subdomain_index(it)];
539 
540     add_edge(p1,p2,edge_color);
541     add_edge(p1,p3,edge_color);
542     add_edge(p1,p4,edge_color);
543     add_edge(p2,p3,edge_color);
544     add_edge(p2,p4,edge_color);
545     add_edge(p3,p4,edge_color);
546 
547     add_vertex(p1,edge_color);
548     add_vertex(p2,edge_color);
549     add_vertex(p3,edge_color);
550     add_vertex(p4,edge_color);
551   }
552 }
553 
554 
555 void
556 C3t3_rib_exporter_plugin::
add_edge(const Bare_point & p,const Bare_point & q,const QColor & color)557 add_edge(const Bare_point& p, const Bare_point& q, const QColor& color)
558 {
559   if ( p < q )
560   {
561     edges_.insert(std::make_pair(std::make_pair(p,q),color));
562   }
563   else
564   {
565     edges_.insert(std::make_pair(std::make_pair(q,p),color));
566   }
567 }
568 
569 
570 void
571 C3t3_rib_exporter_plugin::
add_vertex(const Bare_point & p,const QColor & color)572 add_vertex(const Bare_point& p, const QColor& color)
573 {
574   vertices_.insert(std::make_pair(p,color));
575 }
576 
577 
578 void
579 C3t3_rib_exporter_plugin::
write_header(const std::string & filename,std::ofstream & out)580 write_header(const std::string& filename, std::ofstream& out)
581 {
582   out << "Option \"limits\" \"numthreads\" [16]" << std::endl
583       << "Option \"searchpath\" \"shader\" \".:./shaders:%PIXIE_SHADERS%:%PIXIEHOME%/shaders\"" << std::endl;
584 
585   if ( ! parameters_.is_preview )
586   {
587     out << "Attribute \"visibility\" \"specular\" 1" << std::endl
588         << "Attribute \"visibility\" \"transmission\" 1" << std::endl << std::endl;
589   }
590 
591   out << "Display \""<< filename << ".tif\" \"file\" \"rgb\"" << std::endl;
592 
593   if ( ! parameters_.is_preview )
594   {
595     out << "Format " << parameters_.width << " " << parameters_.height << " 1" << std::endl;
596   }
597   else
598   {
599     double ratio = double(parameters_.height) / double(parameters_.width);
600 
601     int width = (ratio < 1.)  ? 300               : int(300. / ratio);
602     int height = (ratio < 1.) ? int(ratio * 300.) : 300;
603 
604     out << "Format " << width << " " << height << " 1" << std::endl;
605   }
606 
607 
608   if ( parameters_.width > parameters_.height )
609   {
610     double ratio = double(parameters_.height) / double(parameters_.width);
611     out << "ScreenWindow -1 1 " << -ratio << " " << ratio << std::endl;
612   }
613   else if ( parameters_.height > parameters_.width )
614   {
615     double ratio = double(parameters_.width) / double(parameters_.height);
616     out << "ScreenWindow " << -ratio << " " << ratio << " -1 1" << std::endl;
617   }
618 
619   out << "Projection \"perspective\" \"fov\" 45" << std::endl
620       << "PixelSamples 4 4" << std::endl
621       << "PixelFilter \"catmull-rom\" 3 3" << std::endl
622       << "ShadingInterpolation \"smooth\"" << std::endl
623       << "Rotate 180 0 0 1" << std::endl
624       << "WorldBegin" << std::endl;
625 }
626 
627 
628 void
629 C3t3_rib_exporter_plugin::
write_lights(std::ofstream & out)630 write_lights(std::ofstream& out)
631 {
632   if ( ! parameters_.is_preview )
633   {
634     // ShadowLight
635     out << "LightSource \"shadowdistant\" 1 \"from\" [0 0 0] \"to\" [0 0 1]"
636         << " \"shadowname\" \"raytrace\" \"intensity\" " << parameters_.shadowIntensity << std::endl;
637 
638     // Ambient light
639     out << "LightSource \"ambientlight\" 2 \"intensity\" " << parameters_.ambientIntensity << std::endl;
640   }
641   else
642   {
643     out << "LightSource \"distantLight\" 1 \"from\" [0 0 0] \"to\" [0 0 1]"
644     << " \"intensity\" 0.85" << std::endl;
645   }
646 
647   // Background light
648   out << "LightSource \"ambientlight\" 99 \"intensity\" 1" << std::endl;
649   write_turn_background_light(false,out);
650 }
651 
652 
653 void
654 C3t3_rib_exporter_plugin::
write_turn_background_light(bool turn_on,std::ofstream & out)655 write_turn_background_light(bool turn_on, std::ofstream& out)
656 {
657   if (!turn_on)
658   {
659     out << "Illuminate 1 1" << std::endl;
660     if ( ! parameters_.is_preview ) { out << "Illuminate 2 1" << std::endl; }
661     out << "Illuminate 99 0" << std::endl;
662   }
663   else
664   {
665     out << "Illuminate 1 0" << std::endl;
666     if ( ! parameters_.is_preview ) { out << "Illuminate 2 0" << std::endl; }
667     out << "Illuminate 99 1" << std::endl;
668   }
669 }
670 
671 
672 void
673 C3t3_rib_exporter_plugin::
write_facets(const C3t3 & c3t3,std::ofstream & out)674 write_facets(const C3t3& c3t3, std::ofstream& out)
675 {
676   Geom_traits::Construct_point_3 wp2p
677     = c3t3.triangulation().geom_traits().construct_point_3_object();
678 
679   for ( C3t3::Facets_in_complex_iterator it = c3t3.facets_in_complex_begin(),
680        end = c3t3.facets_in_complex_end() ; it != end ; ++it )
681   {
682     const C3t3::Cell_handle& c = it->first;
683     const int& k = it->second;
684 
685     const Bare_point& p1 = wp2p(c->vertex((k+1)&3)->point());
686     const Bare_point& p2 = wp2p(c->vertex((k+2)&3)->point());
687     const Bare_point& p3 = wp2p(c->vertex((k+3)&3)->point());
688 
689     QColor color = c3t3.is_in_complex(c) ? subdomain_map_[c3t3.subdomain_index(c)]
690     : subdomain_map_[c3t3.subdomain_index(c->neighbor(k))];
691 
692     write_triangle(p1, p2, p3, color, color.darker(125), out );
693   }
694 }
695 
696 
697 void
698 C3t3_rib_exporter_plugin::
write_facets(const C3t3 & c3t3,const Plane & plane,std::ofstream & out)699 write_facets(const C3t3& c3t3, const Plane& plane, std::ofstream& out)
700 {
701   typedef EPICK::Oriented_side Side;
702 
703   Geom_traits::Construct_point_3 wp2p
704     = c3t3.triangulation().geom_traits().construct_point_3_object();
705 
706   for ( C3t3::Facets_in_complex_iterator it = c3t3.facets_in_complex_begin(),
707        end = c3t3.facets_in_complex_end() ; it != end ; ++it )
708   {
709     const C3t3::Cell_handle& c = it->first;
710     const int& k = it->second;
711 
712     const Bare_point& p1 = wp2p(c->vertex((k+1)&3)->point());
713     const Bare_point& p2 = wp2p(c->vertex((k+2)&3)->point());
714     const Bare_point& p3 = wp2p(c->vertex((k+3)&3)->point());
715 
716     const Side s1 = plane.oriented_side(p1);
717     const Side s2 = plane.oriented_side(p2);
718     const Side s3 = plane.oriented_side(p3);
719 
720     if(   s1 == CGAL::ON_NEGATIVE_SIDE && s2 == CGAL::ON_NEGATIVE_SIDE
721        && s3 == CGAL::ON_NEGATIVE_SIDE )
722     {
723       QColor color = c3t3.is_in_complex(c) ? subdomain_map_[c3t3.subdomain_index(c)]
724                                            : subdomain_map_[c3t3.subdomain_index(c->neighbor(k))];
725 
726       write_triangle(p1, p2, p3, color, color.darker(125), out );
727     }
728   }
729 }
730 
731 void
732 C3t3_rib_exporter_plugin::
write_surface_cells(const C3t3 & c3t3,const Plane &,std::ofstream & out)733 write_surface_cells(const C3t3& c3t3, const Plane& /* plane */, std::ofstream& out)
734 {
735   const Geom_traits& gt = c3t3.triangulation().geom_traits();
736   Geom_traits::Construct_point_3 wp2p = gt.construct_point_3_object();
737 
738   for ( C3t3::Cells_in_complex_iterator it_cell = c3t3.cells_in_complex_begin(),
739        end = c3t3.cells_in_complex_end() ; it_cell != end ; ++it_cell )
740   {
741     C3t3::Cell_handle c = it_cell;
742 
743     // Compute the number of surface vertices in c
744     // Keep one of them in memory
745     int num_2D_vertices = 0;
746     int last_2D_vertex_index = -1;
747     for (int i = 0 ; i < 4 ; ++i)
748     {
749       if (c3t3.in_dimension(c->vertex(i)) == 2)
750       {
751         ++num_2D_vertices;
752         last_2D_vertex_index = i;
753       }
754     }
755 
756     //const int TRANSPARENCY_ALPHA_VALUE = 100;
757     CGAL::Bbox_3 bbox = c3t3.bbox();
758     float relPos = static_cast<float>((c->weighted_circumcenter(gt).x() - bbox.xmin())
759                                       / (bbox.xmax() - bbox.xmin()));
760     float TRANSPARENCY_ALPHA_VALUE =
761       1.f -
762       (relPos < 0.25f ?
763         0.0f :
764         (relPos > 0.75f ?
765           1.0f :
766           (relPos - 0.25f)*1.0f/0.5f
767         )
768       );
769 
770 
771     /*
772     // ONLY SURFACE FACETS ARE TRANSPARENT
773     if (num_2D_vertices >= 3)
774     {
775       QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)];
776       QColor facecolor = basecolor.darker(150);
777       QColor edgecolor = facecolor.darker(150);
778 
779       for (int i = 0 ; i < 4 ; ++i)
780       {
781         if (c3t3.in_dimension(c->vertex((i+1)%4)) == 2
782             && c3t3.in_dimension(c->vertex((i+2)%4)) == 2
783             && c3t3.in_dimension(c->vertex((i+3)%4)) == 2)
784         {
785           edgecolor.setAlpha(TRANSPARENCY_ALPHA_VALUE);
786         }
787         else
788         {
789           edgecolor.setAlpha(255);
790         }
791 
792         write_triangle(wp2p(c->vertex((i+1)%4)->point()),
793                        wp2p(c->vertex((i+2)%4)->point()),
794                        wp2p(c->vertex((i+3)%4)->point()),
795                        facecolor, edgecolor, out );
796       }
797     }*/
798 
799 
800     // SURFACE CELLS ARE TRANSPARENT
801     if (num_2D_vertices >= 2)
802     {
803       QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)];
804       QColor facecolor = basecolor.darker(150);
805       QColor edgecolor = facecolor.darker(150);
806 
807       /*
808       typedef Kernel::Oriented_side Side;
809 
810       // Transparency on the negative side of the plane
811       const Side s0 = plane.oriented_side(wp2p(c->vertex(0)->point()));
812       const Side s1 = plane.oriented_side(wp2p(c->vertex(1)->point()));
813       const Side s2 = plane.oriented_side(wp2p(c->vertex(2)->point()));
814       const Side s3 = plane.oriented_side(wp2p(c->vertex(3)->point()));
815       if(   s0 == CGAL::ON_NEGATIVE_SIDE && s1 == CGAL::ON_NEGATIVE_SIDE
816          && s2 == CGAL::ON_NEGATIVE_SIDE && s3 == CGAL::ON_NEGATIVE_SIDE )
817       {
818         edgecolor.setAlpha(TRANSPARENCY_ALPHA_VALUE);
819       }
820       else
821       {
822         edgecolor.setAlpha(255);
823       }*/
824 
825       edgecolor.setAlphaF(TRANSPARENCY_ALPHA_VALUE);
826 
827       for (int i = 0 ; i < 4 ; ++i)
828       {
829         write_triangle(wp2p(c->vertex((i+1)%4)->point()),
830                        wp2p(c->vertex((i+2)%4)->point()),
831                        wp2p(c->vertex((i+3)%4)->point()),
832                        facecolor, edgecolor, out );
833       }
834     }
835     else if (num_2D_vertices == 1)
836     {
837       QColor basecolor = subdomain_map_[c3t3.subdomain_index(c)];
838       QColor facecolor = basecolor.darker(150);
839       QColor edgecolor = facecolor.darker(150);
840 
841       for (int i = 0 ; i < 4 ; ++i)
842       {
843         if (i == last_2D_vertex_index)
844         {
845           edgecolor.setAlphaF(TRANSPARENCY_ALPHA_VALUE);
846         }
847         else
848         {
849           edgecolor.setAlphaF(TRANSPARENCY_ALPHA_VALUE);
850         }
851 
852         write_triangle(wp2p(c->vertex((i+1)%4)->point()),
853                        wp2p(c->vertex((i+2)%4)->point()),
854                        wp2p(c->vertex((i+3)%4)->point()),
855                        facecolor, edgecolor, out );
856       }
857     }
858   }
859 }
860 
861 
862 void
863 C3t3_rib_exporter_plugin::
write_cells_intersecting_a_plane(const C3t3 & c3t3,const Plane & plane,std::ofstream & out)864 write_cells_intersecting_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out)
865 {
866   typedef EPICK::Oriented_side Side;
867 
868   Geom_traits::Construct_point_3 wp2p
869     = c3t3.triangulation().geom_traits().construct_point_3_object();
870 
871   for ( C3t3::Cells_in_complex_iterator it = c3t3.cells_in_complex_begin(),
872        end = c3t3.cells_in_complex_end() ; it != end ; ++it )
873   {
874     const Bare_point& p1 = wp2p(it->vertex(0)->point());
875     const Bare_point& p2 = wp2p(it->vertex(1)->point());
876     const Bare_point& p3 = wp2p(it->vertex(2)->point());
877     const Bare_point& p4 = wp2p(it->vertex(3)->point());
878 
879     const Side s1 = plane.oriented_side(p1);
880     const Side s2 = plane.oriented_side(p2);
881     const Side s3 = plane.oriented_side(p3);
882     const Side s4 = plane.oriented_side(p4);
883 
884     if(   s1 == CGAL::ON_ORIENTED_BOUNDARY || s2 == CGAL::ON_ORIENTED_BOUNDARY
885        || s3 == CGAL::ON_ORIENTED_BOUNDARY || s4 == CGAL::ON_ORIENTED_BOUNDARY
886        || s2 != s1 || s3 != s1 || s4 != s1 )
887     {
888       QColor basecolor = subdomain_map_[c3t3.subdomain_index(it)];
889       QColor facecolor = basecolor.darker(150);
890       QColor edgecolor = facecolor.darker(150);
891 
892       edgecolor.setAlpha(20);
893 
894       // Don't write facet twice
895       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE )
896         write_triangle(p1, p2, p3, facecolor, edgecolor, out );
897 
898       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
899         write_triangle(p1, p2, p4, facecolor, edgecolor, out );
900 
901       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
902         write_triangle(p1, p3, p4, facecolor, edgecolor, out );
903 
904       if ( s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
905         write_triangle(p2, p3, p4, facecolor, edgecolor, out );
906     }
907   }
908 }
909 
910 void
911 C3t3_rib_exporter_plugin::
write_cells_on_the_positive_side_of_a_plane(const C3t3 & c3t3,const Plane & plane,std::ofstream & out)912 write_cells_on_the_positive_side_of_a_plane(const C3t3& c3t3, const Plane& plane, std::ofstream& out)
913 {
914   typedef EPICK::Oriented_side Side;
915 
916   Geom_traits::Construct_point_3 wp2p
917     = c3t3.triangulation().geom_traits().construct_point_3_object();
918 
919   for ( C3t3::Cells_in_complex_iterator it = c3t3.cells_in_complex_begin(),
920        end = c3t3.cells_in_complex_end() ; it != end ; ++it )
921   {
922     const Bare_point& p1 = wp2p(it->vertex(0)->point());
923     const Bare_point& p2 = wp2p(it->vertex(1)->point());
924     const Bare_point& p3 = wp2p(it->vertex(2)->point());
925     const Bare_point& p4 = wp2p(it->vertex(3)->point());
926 
927     const Side s1 = plane.oriented_side(p1);
928     const Side s2 = plane.oriented_side(p2);
929     const Side s3 = plane.oriented_side(p3);
930     const Side s4 = plane.oriented_side(p4);
931 
932     if( (   s1 == CGAL::ON_POSITIVE_SIDE || s2 == CGAL::ON_POSITIVE_SIDE
933          || s3 == CGAL::ON_POSITIVE_SIDE || s4 == CGAL::ON_POSITIVE_SIDE )
934         /*&&
935         (   c3t3.surface_patch_index(it, 0) != C3t3::Surface_patch_index()
936          || c3t3.surface_patch_index(it, 1) != C3t3::Surface_patch_index()
937          || c3t3.surface_patch_index(it, 2) != C3t3::Surface_patch_index()
938          || c3t3.surface_patch_index(it, 3) != C3t3::Surface_patch_index() )*/
939     )
940     {
941       QColor basecolor = subdomain_map_[c3t3.subdomain_index(it)];
942       QColor facecolor = basecolor.darker(150);
943       QColor edgecolor = facecolor.darker(150);
944 
945       edgecolor.setAlpha(10);
946 
947       // Don't write facet twice
948       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE )
949         write_triangle(p1, p2, p3, facecolor, edgecolor, out );
950 
951       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s2 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
952         write_triangle(p1, p2, p4, facecolor, edgecolor, out );
953 
954       if ( s1 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
955         write_triangle(p1, p3, p4, facecolor, edgecolor, out );
956 
957       if ( s2 != CGAL::ON_NEGATIVE_SIDE || s3 != CGAL::ON_NEGATIVE_SIDE || s4 != CGAL::ON_NEGATIVE_SIDE )
958         write_triangle(p2, p3, p4, facecolor, edgecolor, out );
959     }
960   }
961 }
962 
963 
964 void
965 C3t3_rib_exporter_plugin::
write_triangle(const Bare_point & p,const Bare_point & q,const Bare_point & r,const QColor & color,const QColor & edge_color,std::ofstream & out)966 write_triangle (const Bare_point& p, const Bare_point& q, const Bare_point& r,
967                 const QColor& color, const QColor& edge_color, std::ofstream& out)
968 {
969   // Color
970   write_color(color, true, out);
971 
972   // Triangle
973   out << "Polygon \"P\" [";
974   write_point(p,out);
975   write_point(q,out);
976   write_point(r,out);
977   out << "]" << std::endl;
978 
979   // Edges (will be drawn later on)
980   add_edge(p,q,edge_color);
981   add_edge(p,r,edge_color);
982   add_edge(q,r,edge_color);
983 
984   // Vertices (will be drawn later on)
985   add_vertex(p,edge_color);
986   add_vertex(q,edge_color);
987   add_vertex(r,edge_color);
988 }
989 
990 void
991 C3t3_rib_exporter_plugin::
write_tetrahedron(const Bare_point & p,const Bare_point & q,const Bare_point & r,const Bare_point & s,const QColor & color,const QColor & edge_color,std::ofstream & out)992 write_tetrahedron (const Bare_point& p, const Bare_point& q, const Bare_point& r, const Bare_point& s,
993                    const QColor& color, const QColor& edge_color, std::ofstream& out)
994 {
995   // Color
996   write_color(color, true, out);
997 
998   // Triangle
999   out << "Polygon \"P\" [";
1000   write_point(p,out);
1001   write_point(q,out);
1002   write_point(r,out);
1003   write_point(s,out);
1004   out << "]" << std::endl;
1005 
1006   // Edges (will be drawn later on)
1007   add_edge(p,q,edge_color);
1008   add_edge(p,r,edge_color);
1009   add_edge(q,r,edge_color);
1010   add_edge(s,p,edge_color);
1011   add_edge(s,q,edge_color);
1012   add_edge(s,r,edge_color);
1013 
1014   // Vertices (will be drawn later on)
1015   add_vertex(p,edge_color);
1016   add_vertex(q,edge_color);
1017   add_vertex(r,edge_color);
1018   add_vertex(s,edge_color);
1019 }
1020 
1021 void
1022 C3t3_rib_exporter_plugin::
write_point(const Bare_point & p,std::ofstream & out)1023 write_point (const Bare_point& p, std::ofstream& out)
1024 {
1025   // Transform point in camera coordinates
1026   const Bare_point& p_cam = camera_coordinates(p);
1027 
1028   // Write it
1029   out << " " << -p_cam.x() << " " << -p_cam.y() << " " << -p_cam.z() << " ";
1030 }
1031 
1032 
1033 void
1034 C3t3_rib_exporter_plugin::
write_point_sphere(const Bare_point & p,std::ofstream & out)1035 write_point_sphere(const Bare_point& p, std::ofstream& out)
1036 {
1037   // Transform point in camera coordinates
1038   const Bare_point& p_cam = camera_coordinates(p);
1039 
1040   // radius
1041   const double& r = parameters_.sphere_radius;
1042 
1043   out << "Translate " << -p_cam.x() << " " << -p_cam.y() << " " << -p_cam.z() << std::endl;
1044 
1045   // Sphere radius zmin zmax thetamax
1046   out << "Sphere " << r << " " << -r << " " << r << " 360" << std::endl;
1047   out << "Identity" << std::endl;
1048 }
1049 
1050 
1051 void
1052 C3t3_rib_exporter_plugin::
write_edge_cylinder(const Bare_point & p,const Bare_point & q,std::ofstream & out)1053 write_edge_cylinder(const Bare_point& p, const Bare_point& q, std::ofstream& out)
1054 {
1055   // Transform point in camera coordinates
1056   const Bare_point& p_cam = camera_coordinates(p);
1057   const Bare_point& q_cam = camera_coordinates(q);
1058 
1059   double pq = CGAL::to_double(CGAL::sqrt(CGAL::squared_distance(p_cam,q_cam)));
1060 
1061   Aff_transformation_3 t (CGAL::Translation(), Vector_3(p_cam,CGAL::ORIGIN));
1062   const Bare_point& q_cam_t = q_cam.transform(t);
1063 
1064   Vector_3 Oq (CGAL::ORIGIN,q_cam_t);
1065   Vector_3 Oz (FT(0),FT(0),FT(1));
1066 
1067   Vector_3 r_axis = CGAL::cross_product(Oq,Oz);
1068   double cos_angle = CGAL::to_double((Oq*Oz)/CGAL::sqrt(Oq.squared_length()));
1069   double angle = std::acos(cos_angle) * 180. / CGAL_PI;
1070 
1071   // radius
1072   const double& r = parameters_.cylinder_radius;
1073 
1074   out << "Translate " << -p_cam.x() << " " << -p_cam.y() << " " << -p_cam.z() << std::endl;
1075   out << "Rotate " << (angle+180.) << " " << -r_axis.x() << " " << -r_axis.y() << " " << -r_axis.z() << std::endl;
1076 
1077   // Cylinder radius zmin zmax thetamax
1078   out << "Cylinder " << r << " 0 " << pq << " 360" << std::endl;
1079   out << "Identity" << std::endl;
1080 }
1081 
1082 
1083 void
1084 C3t3_rib_exporter_plugin::
write_edges_flat(std::ofstream & out)1085 write_edges_flat(std::ofstream& out)
1086 {
1087   // Lights
1088   write_turn_background_light(true,out);
1089 
1090   out << "Surface \"constant\"" << std::endl;
1091   write_opacity(CGAL_RIB_NON_TRANSPARENT_MATERIAL_ALPHA, out);
1092 
1093   // Translation
1094   out << "Translate 0 0 -0.1" << std::endl;
1095 
1096   for ( Edge_map::iterator it = edges_.begin(), end = edges_.end() ;
1097        it != end ; ++it )
1098   {
1099     // Color
1100     write_color(it->second, true, out);
1101 
1102     // Edge
1103     out << "Curves \"linear\" [2] \"nonperiodic\" \"P\" [";
1104     write_point(it->first.first,out);
1105     write_point(it->first.second,out);
1106     out << "] \"constantwidth\" [0.15]" << std::endl;
1107   }
1108 }
1109 
1110 
1111 void
1112 C3t3_rib_exporter_plugin::
write_edges_volumic(std::ofstream & out)1113 write_edges_volumic(std::ofstream& out)
1114 {
1115   // Material
1116   write_opacity(CGAL_RIB_NON_TRANSPARENT_MATERIAL_ALPHA, out);
1117 
1118   for ( Edge_map::iterator it = edges_.begin(), end = edges_.end() ;
1119        it != end ; ++it )
1120   {
1121     // Color
1122     write_color(it->second, true, out);
1123     // Edge
1124     write_edge_cylinder(it->first.first, it->first.second, out);
1125   }
1126 }
1127 
1128 void
1129 C3t3_rib_exporter_plugin::
write_vertices_volumic(std::ofstream & out)1130 write_vertices_volumic(std::ofstream& out)
1131 {
1132   // Material
1133   write_opacity(CGAL_RIB_NON_TRANSPARENT_MATERIAL_ALPHA, out);
1134 
1135   for ( Vertex_map::iterator it = vertices_.begin(), end = vertices_.end() ;
1136        it != end ; ++it )
1137   {
1138     // Color
1139     write_color(it->second, false, out);
1140     // Vertex
1141     write_point_sphere(it->first, out);
1142   }
1143 }
1144 
1145 
1146 void
1147 C3t3_rib_exporter_plugin::
write_color(const QColor & color,bool use_transparency,std::ofstream & out)1148 write_color(const QColor& color, bool use_transparency, std::ofstream& out)
1149 {
1150   if ( prev_color_ == color )
1151   {
1152     return;
1153   }
1154 
1155   // Cache data
1156   prev_color_ = color;
1157 
1158   // Write opacity data
1159   if (use_transparency)
1160   {
1161     write_opacity(color.alphaF(),out);
1162   }
1163 
1164   // Write color data
1165   out << "Color [ " << color.redF() << " " << color.greenF() << " "
1166       << color.blueF() <<  " ]" << std::endl;
1167 }
1168 
1169 
1170 void
1171 C3t3_rib_exporter_plugin::
write_opacity(const double alpha,std::ofstream & out)1172 write_opacity(const double alpha, std::ofstream& out)
1173 {
1174   if ( alpha == prev_alpha_ )
1175   {
1176     return;
1177   }
1178 
1179   // Cache data
1180   prev_alpha_ = alpha;
1181 
1182   // Write opacity data
1183   out << "Opacity " << alpha << " " << alpha << " " << alpha << std::endl;
1184 }
1185 
1186 
1187 void
1188 C3t3_rib_exporter_plugin::
write_background(const QColor & color,std::ofstream & out)1189 write_background(const QColor& color, std::ofstream& out)
1190 {
1191   write_turn_background_light(false,out);
1192 
1193   out << "Surface \"constant\"" << std::endl;
1194   write_color(color,false,out);
1195 
1196   double corner = zmax_ * 2.;
1197   double depth_pos = zmax_ * 1.6;
1198 
1199   out << "Polygon \"P\" [";
1200   out << " " << -corner << " " << -corner << " " << depth_pos << " ";
1201   out << " " <<  corner << " " << -corner << " " << depth_pos << " ";
1202   out << " " <<  corner << " " <<  corner << " " << depth_pos << " ";
1203   out << " " << -corner << " " <<  corner << " " << depth_pos << " ";
1204   out << "]" << std::endl;
1205 }
1206 
1207 #include "C3t3_rib_exporter_plugin.moc"
1208