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