1 //#define CGAL_USE_BOOST_BIMAP
2 
3 #include <fstream>
4 #include <vector>
5 
6 // CGAL headers
7 
8 #include "svd-typedefs.h"
9 #include <boost/config.hpp>
10 #include <boost/version.hpp>
11 #include <CGAL/Timer.h>
12 
13 // Qt headers
14 #include <QtGui>
15 #include <QString>
16 #include <QActionGroup>
17 #include <QFileDialog>
18 #include <QInputDialog>
19 #include <QDragEnterEvent>
20 #include <QDropEvent>
21 #include <QMessageBox>
22 #include <QGraphicsLineItem>
23 
24 // GraphicsView items and event filters (input classes)
25 #include <CGAL/Qt/GraphicsViewPolylineInput.h>
26 #include <CGAL/Qt/SegmentDelaunayGraphGraphicsItem.h>
27 #include <CGAL/Constraints_loader.h>
28 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
29 #include <CGAL/IO/WKT.h>
30 #endif
31 //#include <CGAL/Qt/Converter.h>
32 
33 // the two base classes
34 #include "ui_Segment_voronoi_2.h"
35 #include <CGAL/Qt/DemosMainWindow.h>
36 
37 // for viewportsBbox(QGraphicsScene*)
38 #include <CGAL/Qt/utility.h>
39 
40 typedef Rep K;
41 typedef SDG_2 SVD;
42 
43 typedef SVD::Vertex_handle Vertex_handle;
44 
45 
46 
47 class MainWindow :
48   public CGAL::Qt::DemosMainWindow,
49   public Ui::Segment_voronoi_2
50 {
51   Q_OBJECT
52 
53 private:
54   SVD svd;
55   QGraphicsScene scene;
56   std::list<Point_2> seeds;
57 
58   CGAL::Qt::SegmentDelaunayGraphGraphicsItem<SVD> * sdggi;
59 
60   CGAL::Qt::GraphicsViewPolylineInput<K> * pi;
61 
62 public:
63   MainWindow();
64 
65 private:
66   template <typename Iterator>
insert_polyline(Iterator b,Iterator e)67   void insert_polyline(Iterator b, Iterator e)
68   {
69     Point_2 p, q;
70     SVD::Vertex_handle vh, wh;
71     Iterator it = b;
72     vh = svd.insert(*it);
73     p = *it;
74     ++it;
75     for(; it != e; ++it){
76       q = *it;
77       if(p != q){
78         wh = svd.insert(*it);
79         svd.insert(vh,wh);
80         vh = wh;
81         p = q;
82       } else {
83         std::cout << "duplicate point: " << p << std::endl;
84       }
85     }
86     Q_EMIT( changed());
87   }
88 
89 protected Q_SLOTS:
90  virtual void open(QString);
91 
92 public Q_SLOTS:
93 
94   void processInput(CGAL::Object o);
95 
96   void on_actionInsertPolyline_toggled(bool checked);
97 
98   void on_actionClear_triggered();
99 
100   void on_actionRecenter_triggered();
101 
102   void on_actionLoadSegments_triggered();
103 
104   void loadPolygonConstraints(QString);
105 
106   void loadEdgConstraints(QString);
107   void loadWKTConstraints(QString fileName);
108 
109 Q_SIGNALS:
110   void changed();
111 };
112 
113 
MainWindow()114 MainWindow::MainWindow()
115   : DemosMainWindow()
116 {
117   setupUi(this);
118 
119   this->graphicsView->setAcceptDrops(false);
120 
121   // Add a GraphicItem for the SVD triangulation
122   sdggi = new CGAL::Qt::SegmentDelaunayGraphGraphicsItem<SVD>(&svd);
123   QColor segmentColor(::Qt::blue);
124   QColor voronoiColor(::Qt::black);
125   segmentColor.setAlpha(150);
126   sdggi->setSegmentPen(QPen(segmentColor,0));
127   sdggi->setVoronoiPen(QPen(voronoiColor,0));
128 
129   QObject::connect(this, SIGNAL(changed()),
130                    sdggi, SLOT(modelChanged()));
131 
132   sdggi->setVerticesPen(QPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
133 
134   sdggi->setZValue(-1);
135   scene.addItem(sdggi);
136 
137   // Setup input handlers. They get events before the scene gets them
138   // and the input they generate is passed to the triangulation with
139   // the signal/slot mechanism
140   pi = new CGAL::Qt::GraphicsViewPolylineInput<K>(this, &scene, 0, true); // inputs polylines which are not closed
141   QObject::connect(pi, SIGNAL(generate(CGAL::Object)),
142                    this, SLOT(processInput(CGAL::Object)));
143 
144 
145 
146   //
147   // Manual handling of actions
148   //
149   QObject::connect(this->actionQuit, SIGNAL(triggered()),
150                    this, SLOT(close()));
151 
152   // We put mutually exclusive actions in an QActionGroup
153   QActionGroup* ag = new QActionGroup(this);
154   ag->addAction(this->actionInsertPolyline);
155 
156   // Check two actions
157   this->actionInsertPolyline->setChecked(true);
158   this->actionShowVoronoi->setChecked(true);
159   this->actionShowConstraints->setChecked(true);
160 
161   //
162   // Setup the scene and the view
163   //
164   scene.setItemIndexMethod(QGraphicsScene::NoIndex);
165   scene.setSceneRect(-100, -100, 100, 100);
166   this->graphicsView->setScene(&scene);
167   this->graphicsView->setMouseTracking(true);
168 
169   // Turn the vertical axis upside down
170   this->graphicsView->scale(1, -1);
171 
172   // The navigation adds zooming and translation functionality to the
173   // QGraphicsView
174   this->addNavigation(this->graphicsView);
175 
176   this->setupStatusBar();
177   this->setupOptionsMenu();
178   this->addAboutDemo(":/cgal/help/about_Segment_voronoi_2.html");
179   this->addAboutCGAL();
180 
181   this->addRecentFiles(this->menuFile, this->actionQuit);
182   connect(this, SIGNAL(openRecentFile(QString)),
183           this, SLOT(open(QString)));
184 }
185 
186 
187 void
processInput(CGAL::Object o)188 MainWindow::processInput(CGAL::Object o)
189 {
190 
191   std::list<Point_2> points;
192   if(CGAL::assign(points, o)){
193     if(points.size() == 1) {
194       svd.insert(points.front());
195     }
196     else {
197       /*
198       std::cout.precision(12);
199       std::cout << points.size() << std::endl;
200       for( std::list<Point_2>::iterator it =  points.begin(); it != points.end(); ++it){
201         std::cout << *it << std::endl;
202       }
203       */
204       insert_polyline(points.begin(), points.end());
205     }
206   }
207 
208 
209   Q_EMIT( changed());
210 }
211 
212 
213 /*
214  *  Qt Automatic Connections
215  *  https://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connections
216  *
217  *  setupUi(this) generates connections to the slots named
218  *  "on_<action_name>_<signal_name>"
219  */
220 void
on_actionInsertPolyline_toggled(bool checked)221 MainWindow::on_actionInsertPolyline_toggled(bool checked)
222 {
223   if(checked){
224     scene.installEventFilter(pi);
225   } else {
226     scene.removeEventFilter(pi);
227   }
228 }
229 
230 
231 
232 void
on_actionClear_triggered()233 MainWindow::on_actionClear_triggered()
234 {
235   svd.clear();
236   Q_EMIT( changed());
237 }
238 
239 
240 void
open(QString fileName)241 MainWindow::open(QString fileName)
242 {
243   if(! fileName.isEmpty()){
244     if(fileName.endsWith(".polygons.cgal")){
245       loadPolygonConstraints(fileName);
246       this->addToRecentFiles(fileName);
247     } else if(fileName.endsWith(".edg")){
248       loadEdgConstraints(fileName);
249       this->addToRecentFiles(fileName);
250     } else if(fileName.endsWith(".wkt", Qt::CaseInsensitive)){
251 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
252       loadWKTConstraints(fileName);
253       this->addToRecentFiles(fileName);
254 #endif
255     }
256   }
257 }
258 
259 void
on_actionLoadSegments_triggered()260 MainWindow::on_actionLoadSegments_triggered()
261 {
262   QString fileName = QFileDialog::getOpenFileName(this,
263                                                   tr("Open Constraint File"),
264                                                   ".",
265                                                   tr("Edge files (*.edg);;"
266                                                      "Polyline files (*.polygons.cgal);;"
267                                                    #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
268                                                      "WKT files (*.wkt *.WKT)"
269                                                    #endif
270                                                      ));
271   open(fileName);
272 }
273 
274 void
loadPolygonConstraints(QString fileName)275 MainWindow::loadPolygonConstraints(QString fileName)
276 {
277   K::Point_2 p,q, first;
278   SVD::Vertex_handle vp, vq, vfirst;
279   std::ifstream ifs(qPrintable(fileName));
280   int n;
281   while(ifs >> n){
282     ifs >> first;
283     p = first;
284     vfirst = vp = svd.insert(p);
285     n--;
286     while(n--){
287       ifs >> q;
288       vq = svd.insert(q, vp);
289       svd.insert(vp,vq);
290       p = q;
291       vp = vq;
292     }
293     svd.insert(vp, vfirst);
294   }
295 
296 
297   Q_EMIT( changed());
298   actionRecenter->trigger();
299 }
300 
301 
302 void
loadEdgConstraints(QString fileName)303 MainWindow::loadEdgConstraints(QString fileName)
304 {
305   // wait cursor
306   QApplication::setOverrideCursor(Qt::WaitCursor);
307   CGAL::Timer tim;
308   tim.start();
309   std::ifstream ifs(qPrintable(fileName));
310   bool first=true;
311   int n;
312   ifs >> n;
313 
314   K::Point_2 p,q, qold(0,0); // Initialize qold, as otherwise some g++ issue a unjustified warning
315 
316   SVD::Vertex_handle vp, vq, vqold;
317   while(ifs >> p) {
318     ifs >> q;
319     if(p == q){
320       continue;
321     }
322     if((!first) && (p == qold)){
323       vp = vqold;
324     } else {
325       vp = svd.insert(p);
326     }
327     vq = svd.insert(q, vp);
328     svd.insert(vp,vq);
329     qold = q;
330     vqold = vq;
331     first = false;
332   }
333 
334 
335   tim.stop();
336   statusBar()->showMessage(QString("Insertion took %1 seconds").arg(tim.time()), 2000);
337   // default cursor
338   QApplication::restoreOverrideCursor();
339   Q_EMIT( changed());
340   actionRecenter->trigger();
341 }
342 
343 void
loadWKTConstraints(QString fileName)344 MainWindow::loadWKTConstraints(QString
345                                #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
346                                fileName
347                                #endif
348                                )
349 {
350 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
351   typedef CGAL::Polygon_with_holes_2<K> Polygon;
352   typedef std::vector<K::Point_2> LineString;
353 
354   //Multipolygon
355   K::Point_2 p,q, first;
356   SVD::Vertex_handle vp, vq, vfirst;
357   std::ifstream ifs(qPrintable(fileName));
358   do{
359     std::vector<Polygon> polygons;
360     CGAL::IO::read_multi_polygon_WKT(ifs, polygons);
361     for(const Polygon& poly : polygons)
362     {
363       if(poly.outer_boundary().is_empty())
364         continue;
365       Polygon::General_polygon_2::const_iterator it
366           =poly.outer_boundary().begin();
367       first = *(it++);
368       p = first;
369       vfirst = vp = svd.insert(p);
370       for(; it !=
371           poly.outer_boundary().end();
372           ++it){
373         q = *it;
374         vq = svd.insert(q, vp);
375         svd.insert(vp,vq);
376         p = q;
377         vp = vq;
378       }
379       if(vp != vfirst)
380         svd.insert(vp, vfirst);
381     }
382   }while(ifs.good() && !ifs.eof());
383   //MultiLineString
384   ifs.clear();
385   ifs.seekg(ifs.beg);
386   K::Point_2 qold(0,0); // Initialize qold, as otherwise some g++ issue a unjustified warning
387   SVD::Vertex_handle vqold;
388   do{
389     std::vector<LineString > linestrings;
390     CGAL::IO::read_multi_linestring_WKT(ifs, linestrings);
391     for(const LineString& ls : linestrings)
392     {
393       bool first_pass=true;
394       LineString::const_iterator it = ls.begin();
395       for(; it!=ls.end(); ++it){
396         p = *it++;
397         q = *it;
398         if(p == q){
399           continue;
400         }
401         if((!first_pass) && (p == qold)){
402           vp = vqold;
403         } else {
404           vp = svd.insert(p);
405         }
406         vq = svd.insert(q, vp);
407         if(vp != vq)
408           svd.insert(vp,vq);
409         qold = q;
410         vqold = vq;
411         first_pass = false;
412       }
413     }
414   }while(ifs.good() && !ifs.eof());
415   Q_EMIT( changed());
416   actionRecenter->trigger();
417 #endif
418 }
419 
420 void
on_actionRecenter_triggered()421 MainWindow::on_actionRecenter_triggered()
422 {
423   this->graphicsView->setSceneRect(sdggi->boundingRect());
424   this->graphicsView->fitInView(sdggi->boundingRect(), Qt::KeepAspectRatio);
425 }
426 
427 #include "Segment_voronoi_2.moc"
428 #include <CGAL/Qt/resources.h>
429 
main(int argc,char ** argv)430 int main(int argc, char **argv)
431 {
432   QApplication app(argc, argv);
433 
434   app.setOrganizationDomain("geometryfactory.com");
435   app.setOrganizationName("GeometryFactory");
436   app.setApplicationName("Segment Voronoi 2 demo");
437 
438   // Import resources from libCGAL (Qt5).
439   CGAL_QT_INIT_RESOURCES;
440 
441   MainWindow mainWindow;
442   mainWindow.show();
443   return app.exec();
444 }
445