1 #include <boost/config.hpp>
2 #include <boost/version.hpp>
3 #include <fstream>
4
5 // CGAL headers
6 #include <CGAL/Cartesian.h>
7 #include <CGAL/MP_Float.h>
8 #include <CGAL/Algebraic_kernel_for_circles_2_2.h>
9 #include <CGAL/Circular_kernel_2.h>
10 #include <CGAL/intersections.h>
11 #include <CGAL/Circular_kernel_2.h>
12 #include <CGAL/Object.h>
13 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
14 #include <CGAL/IO/WKT.h>
15 #endif
16
17 // Qt headers
18 #include <QtGui>
19 #include <QString>
20 #include <QActionGroup>
21 #include <QFileDialog>
22 #include <QInputDialog>
23
24 // GraphicsView items and event filters (input classes)
25 #include <CGAL/Qt/GraphicsViewCircularArcInput.h>
26 #include "ArcsGraphicsItem.h"
27
28 // the two base classes
29 #include "ui_Circular_kernel_2.h"
30 #include <CGAL/Qt/DemosMainWindow.h>
31
32 typedef CGAL::Quotient<CGAL::MP_Float> NT;
33 typedef CGAL::Cartesian<NT> Linear_k;
34
35 typedef CGAL::Algebraic_kernel_for_circles_2_2<NT> Algebraic_k;
36 typedef CGAL::Circular_kernel_2<Linear_k,Algebraic_k> CircularKernel;
37
38 typedef CircularKernel::Point_2 Point_2;
39 typedef CircularKernel::Segment_2 Segment_2;
40 typedef CircularKernel::Line_arc_2 Line_arc_2;
41 typedef CircularKernel::Circular_arc_2 Circular_arc_2;
42 typedef CircularKernel::Circular_arc_point_2 Circular_arc_point_2;
43
44
45 typedef CGAL::Qt::ArcsGraphicsItem<CircularKernel> ArcsGraphicsItem;
46
47
48 typedef std::vector<CGAL::Object> ArcContainer;
49
50 class MainWindow :
51 public CGAL::Qt::DemosMainWindow,
52 public Ui::Circular_kernel_2
53 {
54 Q_OBJECT
55
56 private:
57 ArcContainer arcs;
58 ArcContainer intersections;
59 QGraphicsScene scene;
60
61 ArcsGraphicsItem * agi;
62
63
64 CGAL::Qt::GraphicsViewCircularArcInput<CircularKernel> * cai;
65
66 public:
67 MainWindow();
68
69 public Q_SLOTS:
70
71 virtual void open(QString);
72
73 void processInput(CGAL::Object o);
74
75
76 void on_actionInsertCircularArc_toggled(bool checked);
77
78 void on_actionClear_triggered();
79
80 void on_actionLoadLineAndCircularArcs_triggered();
81
82 void on_actionRecenter_triggered();
83
84
85 Q_SIGNALS:
86 void changed();
87 };
88
89
MainWindow()90 MainWindow::MainWindow()
91 : DemosMainWindow()
92 {
93 setupUi(this);
94
95 // Add a GraphicItem for the Circular triangulation
96 agi = new CGAL::Qt::ArcsGraphicsItem<CircularKernel>(arcs, intersections);
97
98 agi->setIntersectionsPen(QPen(Qt::red, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
99
100 QObject::connect(this, SIGNAL(changed()),
101 agi, SLOT(modelChanged()));
102
103 agi->setInputPen(QPen(Qt::black, 0, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
104 scene.addItem(agi);
105 agi->hide();
106
107 // Setup input handlers. They get events before the scene gets them
108 // and the input they generate is passed to the triangulation with
109 // the signal/slot mechanism
110 cai = new CGAL::Qt::GraphicsViewCircularArcInput<CircularKernel>(this, &scene);
111
112 QObject::connect(cai, SIGNAL(generate(CGAL::Object)),
113 this, SLOT(processInput(CGAL::Object)));
114
115 // Manual handling of actions
116 //
117 QObject::connect(this->actionQuit, SIGNAL(triggered()),
118 qApp, SLOT(quit()));
119
120 // Check two actions
121 this->actionInsertCircularArc->setChecked(true);
122
123 //
124 // Setup the scene and the view
125 //
126 scene.setItemIndexMethod(QGraphicsScene::NoIndex);
127 scene.setSceneRect(-100, -100, 100, 100);
128 this->graphicsView->setScene(&scene);
129
130 // Uncomment the following line to get antialiasing by default.
131 // actionUse_Antialiasing->setChecked(true);
132
133 // Turn the vertical axis upside down
134 this->graphicsView->scale(1, -1);
135
136 // The navigation adds zooming and translation functionality to the
137 // QGraphicsView
138 this->addNavigation(this->graphicsView);
139
140 this->setupStatusBar();
141 this->setupOptionsMenu();
142 this->addAboutDemo(":/cgal/help/about_Circular_kernel_2.html");
143 this->addAboutCGAL();
144 this->addRecentFiles(this->menuFile, this->actionQuit);
145 connect(this, SIGNAL(openRecentFile(QString)),
146 this, SLOT(open(QString)));
147 }
148
149
150 void
processInput(CGAL::Object o)151 MainWindow::processInput(CGAL::Object o)
152 {
153 Circular_arc_2 ca;
154 Line_arc_2 la;
155 bool is_circular = false;
156
157 if(assign(ca, o)){
158 is_circular = true;
159 } else if(! assign(la, o)){
160 std::cerr << "unknown object" << std::endl;
161 return;
162 }
163
164 for(std::vector<CGAL::Object>::iterator it = arcs.begin(); it != arcs.end(); ++it){
165 Circular_arc_2 vca;
166 Line_arc_2 vla;
167 if(assign(vca, *it)){
168 if(is_circular){
169 CGAL::intersection(ca, vca, std::back_inserter(intersections));
170 } else {
171 CGAL::intersection(la, vca, std::back_inserter(intersections));
172 }
173 } else if(assign(vla, *it)){
174 if(is_circular){
175 CGAL::intersection(ca, vla, std::back_inserter(intersections));
176 } else {
177 CGAL::intersection(la, vla, std::back_inserter(intersections));
178 }
179 }
180 }
181 arcs.push_back(o);
182 Q_EMIT( changed());
183 }
184
185
186 /*
187 * Qt Automatic Connections
188 * https://doc.qt.io/qt-5/designer-using-a-ui-file.html#automatic-connections
189 *
190 * setupUi(this) generates connections to the slots named
191 * "on_<action_name>_<signal_name>"
192 */
193
194 void
on_actionInsertCircularArc_toggled(bool checked)195 MainWindow::on_actionInsertCircularArc_toggled(bool checked)
196 {
197 if(checked){
198 scene.installEventFilter(cai);
199 } else {
200 scene.removeEventFilter(cai);
201 }
202 }
203
204 void
on_actionClear_triggered()205 MainWindow::on_actionClear_triggered()
206 {
207 arcs.clear();
208 intersections.clear();
209 Q_EMIT( changed());
210 }
211
212 void
on_actionLoadLineAndCircularArcs_triggered()213 MainWindow::on_actionLoadLineAndCircularArcs_triggered()
214 {
215 QString fileName = QFileDialog::getOpenFileName(this,
216 tr("Open Line and Circular Arc File"),
217 ".",
218 tr("Edge files (*.arc)\n"
219 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
220 "WKT files (*.wkt *.WKT)\n"
221 #endif
222 ));
223 if(! fileName.isEmpty()){
224 open(fileName);
225 this->addToRecentFiles(fileName);
226 }
227 }
228
229
230 void
open(QString fileName)231 MainWindow::open(QString fileName)
232 {
233 std::ifstream ifs(qPrintable(fileName));
234
235 char c;
236 double x,y;
237 if(fileName.endsWith(".wkt", Qt::CaseInsensitive))
238 {
239 #if BOOST_VERSION >= 105600 && (! defined(BOOST_GCC) || BOOST_GCC >= 40500)
240 //read pairs as Line_arc_2 and triplets as circular_arc_2
241 do
242 {
243 std::vector<Point_2> multi_points;
244 CGAL::IO::read_multi_point_WKT(ifs, multi_points);
245 if(multi_points.size() == 2)
246 {
247 Line_arc_2 la(Segment_2(multi_points[0],
248 multi_points[1]));
249 for(std::vector<CGAL::Object>::iterator it = arcs.begin(); it != arcs.end(); ++it){
250 Circular_arc_2 vca;
251 Line_arc_2 vla;
252 if(assign(vca, *it)){
253 CGAL::intersection(la, vca, std::back_inserter(intersections));
254 } else if(assign(vla, *it)){
255 CGAL::intersection(la, vla, std::back_inserter(intersections));
256 }
257 }
258 arcs.push_back(make_object(la));
259 }
260 else if(multi_points.size() == 3)
261 {
262 Circular_arc_2 ca(multi_points[0],
263 multi_points[1],
264 multi_points[2]);
265 for(std::vector<CGAL::Object>::iterator it = arcs.begin(); it != arcs.end(); ++it){
266 Circular_arc_2 vca;
267 Line_arc_2 vla;
268 if(assign(vca, *it)){
269 CGAL::intersection(ca, vca, std::back_inserter(intersections));
270 } else if(assign(vla, *it)){
271 CGAL::intersection(ca, vla, std::back_inserter(intersections));
272 }
273 }
274 arcs.push_back(make_object(ca));
275 }
276 else if(multi_points.size()>0)
277 {
278 std::cerr<<"unreadable object."<<std::endl;
279 }
280 }while(ifs.good() && !ifs.eof());
281 ifs.close();
282 #endif
283 }
284 else
285 {
286 while(ifs >> c){
287 if(c == 's'){
288 ifs >> x >> y;
289 Point_2 p(x,y);
290 ifs >> x >> y;
291 Point_2 q(x,y);
292
293 Line_arc_2 la(Segment_2(p,q));
294 for(std::vector<CGAL::Object>::iterator it = arcs.begin(); it != arcs.end(); ++it){
295 Circular_arc_2 vca;
296 Line_arc_2 vla;
297 if(assign(vca, *it)){
298 CGAL::intersection(la, vca, std::back_inserter(intersections));
299 } else if(assign(vla, *it)){
300 CGAL::intersection(la, vla, std::back_inserter(intersections));
301 }
302 }
303 arcs.push_back(make_object(la));
304 } else if(c == 'c'){
305 ifs >> x >> y;
306 Point_2 p(x,y);
307 ifs >> x >> y;
308 Point_2 q(x,y);
309 ifs >> x >> y;
310 Point_2 r(x,y);
311 Circular_arc_2 ca(p,q,r);
312 for(std::vector<CGAL::Object>::iterator it = arcs.begin(); it != arcs.end(); ++it){
313 Circular_arc_2 vca;
314 Line_arc_2 vla;
315 if(assign(vca, *it)){
316 CGAL::intersection(ca, vca, std::back_inserter(intersections));
317 } else if(assign(vla, *it)){
318 CGAL::intersection(ca, vla, std::back_inserter(intersections));
319 }
320 }
321 arcs.push_back(make_object(ca));
322 }
323 }
324 }
325 Q_EMIT( changed());
326 }
327
328 void
on_actionRecenter_triggered()329 MainWindow::on_actionRecenter_triggered()
330 {
331 this->graphicsView->setSceneRect(agi->boundingRect());
332 this->graphicsView->fitInView(agi->boundingRect(), Qt::KeepAspectRatio);
333 }
334
335
336 #include "Circular_kernel_2.moc"
337 #include <CGAL/Qt/resources.h>
338
main(int argc,char ** argv)339 int main(int argc, char **argv)
340 {
341 QApplication app(argc, argv);
342
343 app.setOrganizationDomain("geometryfactory.com");
344 app.setOrganizationName("GeometryFactory");
345 app.setApplicationName("Circular_kernel_2 demo");
346
347 // Import resources from libCGAL (Qt5).
348 CGAL_QT_INIT_RESOURCES;
349
350 MainWindow mainWindow;
351 mainWindow.show();
352 return app.exec();
353 }
354