1 // Copyright (c) 2008  GeometryFactory Sarl (France).
2 // All rights reserved.
3 //
4 // This file is part of CGAL (www.cgal.org); you may redistribute it under
5 // the terms of the Q Public License version 1.0.
6 // See the file LICENSE.QPL distributed with CGAL.
7 //
8 // Licensees holding a valid commercial license may use this file in
9 // accordance with the commercial license agreement provided with the software.
10 //
11 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13 //
14 // $URL: https://github.com/CGAL/cgal/blob/v5.3/GraphicsView/demo/Periodic_2_triangulation_2/include/CGAL/Qt/PeriodicTriangulationGraphicsItem.h $
15 // $Id: PeriodicTriangulationGraphicsItem.h cc99fd9 2021-02-19T16:02:12+01:00 Maxime Gimeno
16 //
17 //
18 // Author(s)     : Andreas Fabri <Andreas.Fabri@geometryfactory.com>
19 //                 Laurent Rineau <Laurent.Rineau@geometryfactory.com>
20 //                 Nico Kruithof <Nico@nghk.nl>
21 
22 #ifndef CGAL_QT_PERIODIC_TRIANGULATION_GRAPHICS_ITEM_H
23 #define CGAL_QT_PERIODIC_TRIANGULATION_GRAPHICS_ITEM_H
24 
25 #include <CGAL/Bbox_2.h>
26 #include <CGAL/Qt/PainterOstream.h>
27 #include <CGAL/Qt/GraphicsItem.h>
28 #include <CGAL/Qt/Converter.h>
29 
30 #include <QGraphicsScene>
31 #include <QPainter>
32 #include <QStyleOption>
33 
34 namespace CGAL {
35   namespace Qt {
36 
37     template <typename T>
38     class PeriodicTriangulationGraphicsItem : public GraphicsItem
39     {
40       typedef typename T::Geom_traits Geom_traits;
41     public:
42       PeriodicTriangulationGraphicsItem(T* t_);
43 
44       void modelChanged();
45 
46       enum Iterator_type {
47         STORED = 0,
48         UNIQUE, // 1
49         STORED_COVER_DOMAIN, // 2
50         UNIQUE_COVER_DOMAIN, // 3
51         NONE
52       };
setEmphasizedSimplices(Iterator_type type)53       void setEmphasizedSimplices(Iterator_type type) { this->type = type; }
getEmphasizedSimplices()54       Iterator_type getEmphasizedSimplices() { return this->type; }
55     public:
56 
57       QRectF boundingRect() const;
58 
59       void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
60 
61       virtual void operator()(typename T::Face_handle fh);
62 
verticesPen()63       const QPen& verticesPen() const
64       {
65         return vertices_pen;
66       }
67 
edgesPen()68       const QPen& edgesPen() const
69       {
70         return edges_pen;
71       }
72 
facesPen()73       const QPen& facesPen() const
74       {
75         return faces_pen;
76       }
77 
domainPen()78       const QPen& domainPen() const
79       {
80         return domain_pen;
81       }
82 
setVerticesPen(const QPen & pen)83       void setVerticesPen(const QPen& pen)
84       {
85         vertices_pen = pen;
86       }
87 
setEdgesPen(const QPen & pen)88       void setEdgesPen(const QPen& pen)
89       {
90         edges_pen = pen;
91       }
92 
setFacesPen(const QPen & pen)93       void setFacesPen(const QPen& pen)
94       {
95         edges_pen = pen;
96       }
97 
setDomainPen(const QPen & pen)98       void setDomainPen(const QPen& pen)
99       {
100         domain_pen = pen;
101       }
102 
visibleVertices()103       bool visibleVertices() const
104       {
105         return visible_vertices;
106       }
107 
setVisibleVertices(const bool b)108       void setVisibleVertices(const bool b)
109       {
110         visible_vertices = b;
111         update();
112       }
113 
visibleEdges()114       bool visibleEdges() const
115       {
116         return visible_edges;
117       }
118 
setVisibleEdges(const bool b)119       void setVisibleEdges(const bool b)
120       {
121         visible_edges = b;
122         update();
123       }
124 
125     protected:
126       virtual void drawAll(QPainter *painter);
127       void paintVertices(QPainter *painter);
128       void paintOneVertex(const typename T::Point& point);
129       virtual void paintVertex(typename T::Vertex_handle vh);
130       void updateBoundingBox();
131 
132       T * t;
133       QPainter* m_painter;
134       PainterOstream<Geom_traits> painterostream;
135 
136       typename T::Vertex_handle vh;
137       typename T::Point p;
138       QRectF bounding_rect;
139 
140       QPen vertices_pen;
141       QPen edges_pen;
142       QPen faces_pen;
143       QPen domain_pen;
144       bool visible_edges;
145       bool visible_vertices;
146 
147       Iterator_type type;
148     };
149 
150 
151     template <typename T>
PeriodicTriangulationGraphicsItem(T * t_)152     PeriodicTriangulationGraphicsItem<T>::PeriodicTriangulationGraphicsItem(T * t_)
153     :  t(t_), painterostream(nullptr),
154        visible_edges(true), visible_vertices(true),
155        type(NONE)
156     {
157       setVerticesPen(QPen(::Qt::red, 1.));
158       setFacesPen(QPen(QColor(100,100,100)));
159       setDomainPen(QPen(::Qt::blue, .01));
160       setEdgesPen(QPen(::Qt::black, .01));
161       if(t->number_of_vertices() == 0){
162         this->hide();
163       }
164       updateBoundingBox();
165       setZValue(3);
166     }
167 
168     template <typename T>
169     QRectF
boundingRect()170     PeriodicTriangulationGraphicsItem<T>::boundingRect() const
171     {
172       return bounding_rect;
173     }
174 
175 
176     template <typename T>
177     void
operator()178     PeriodicTriangulationGraphicsItem<T>::operator()(typename T::Face_handle fh)
179     {
180       if(visible_edges) {
181         for (int i=0; i<3; i++) {
182           if (fh < fh->neighbor(i)){
183             m_painter->setPen(this->edgesPen());
184             painterostream << t->segment(fh,i);
185           }
186         }
187       }
188       if(visible_vertices) {
189         for (int i=0; i<3; i++) {
190           paintVertex(fh->vertex(i));
191         }
192       }
193     }
194 
195     template <typename T>
196     void
drawAll(QPainter * painter)197     PeriodicTriangulationGraphicsItem<T>::drawAll(QPainter *painter)
198     {
199       painterostream = PainterOstream<Geom_traits>(painter);
200 
201       if (type != NONE)
202       {
203         typename T::Iterator_type itype;
204         switch (type) {
205         case STORED:
206           itype = T::STORED;
207           break;
208         case UNIQUE:
209           itype = T::UNIQUE;
210           break;
211         case STORED_COVER_DOMAIN:
212           itype = T::STORED_COVER_DOMAIN;
213           break;
214         case UNIQUE_COVER_DOMAIN:
215           itype = T::UNIQUE_COVER_DOMAIN;
216           break;
217         case NONE:
218         default:
219           assert(false);
220           itype = T::STORED;
221           break;
222         }
223 
224         Converter<Geom_traits> convert;
225 
226         QTransform matrix = painter->worldTransform();
227         painter->resetTransform();
228 
229         { // Faces
230           painter->setPen(QPen());
231           painter->setBrush(QBrush(::Qt::green));
232           for (typename T::Periodic_triangle_iterator tit = t->periodic_triangles_begin(itype);
233                tit != t->periodic_triangles_end(itype); ++tit) {
234             painter->drawConvexPolygon(matrix.map(convert(t->triangle(*tit))));
235           }
236           painter->setBrush(QBrush());
237         }
238         { // Edges
239           QPen pen = edgesPen();
240           pen.setWidth(pen.width() + 2);
241           painter->setPen(pen);
242           for (typename T::Periodic_segment_iterator sit = t->periodic_segments_begin(itype);
243                sit != t->periodic_segments_end(itype); ++sit) {
244             painter->drawLine(matrix.map(convert(t->segment(*sit))));
245           }
246         }
247         { // Vertices
248           QPen pen = verticesPen();
249           pen.setWidth(pen.width() + 2);
250           painter->setPen(pen);
251           for (typename T::Periodic_point_iterator pit = t->periodic_points_begin(itype);
252                pit != t->periodic_points_end(itype); ++pit) {
253             painter->drawPoint(matrix.map(convert(t->point(*pit))));
254           }
255         }
256 
257         painter->setWorldTransform(matrix);
258       }
259 
260       if(visibleEdges()) {
261         painter->setPen(this->edgesPen());
262         t->draw_triangulation(painterostream);
263       }
264 
265       paintVertices(painter);
266     }
267 
268     template <typename T>
269     void
paintVertices(QPainter * painter)270     PeriodicTriangulationGraphicsItem<T>::paintVertices(QPainter *painter)
271     {
272       if(visibleVertices()) {
273         Converter<Geom_traits> convert;
274 
275         QTransform matrix = painter->worldTransform();
276         painter->resetTransform();
277 
278         QPen pen = verticesPen();
279         if (t->number_of_vertices() < 8) {
280           int v_index=1;
281           for (typename T::Unique_vertex_iterator vit = t->unique_vertices_begin();
282                vit != t->unique_vertices_end(); ++vit) {
283             pen.setColor(QColor(255*(v_index&1), 255*((v_index>>1)&1), 255*((v_index>>2)&1)));
284             painter->setPen(pen);
285 
286             painter->drawPoint(matrix.map(convert(t->point(vit))));
287             std::vector<typename T::Vertex_handle> copies = t->periodic_copies(vit);
288             for (size_t i=0; i<copies.size(); ++i)
289               painter->drawPoint(matrix.map(convert(t->point(copies[i]))));
290 
291             ++v_index;
292           }
293 
294         } else {
295           painter->setPen(verticesPen());
296           for (typename T::Periodic_point_iterator ppit = t->periodic_points_begin();
297                ppit != t->periodic_points_end(); ++ppit)
298             {
299               QPointF point = matrix.map(convert(t->point(*ppit)));
300               painter->drawPoint(point);
301             }
302         }
303 
304         painter->setWorldTransform(matrix);
305       }
306     }
307 
308     template <typename T>
309     void
paintOneVertex(const typename T::Point & point)310     PeriodicTriangulationGraphicsItem<T>::paintOneVertex(const typename T::Point& point)
311     {
312       Converter<Geom_traits> convert;
313 
314       m_painter->setPen(this->verticesPen());
315       QTransform matrix = m_painter->worldTransform();
316       m_painter->resetTransform();
317       m_painter->drawPoint(matrix.map(convert(point)));
318       m_painter->setWorldTransform(matrix);
319     }
320 
321     template <typename T>
322     void
paintVertex(typename T::Vertex_handle vh)323     PeriodicTriangulationGraphicsItem<T>::paintVertex(typename T::Vertex_handle vh)
324     {
325       Converter<Geom_traits> convert;
326 
327       m_painter->setPen(this->verticesPen());
328       QTransform matrix = m_painter->worldTransform();
329       m_painter->resetTransform();
330       m_painter->drawPoint(matrix.map(convert(vh->point())));
331       m_painter->setWorldTransform(matrix);
332     }
333 
334     template <typename T>
335     void
paint(QPainter * painter,const QStyleOptionGraphicsItem *,QWidget *)336     PeriodicTriangulationGraphicsItem<T>::paint(QPainter *painter,
337                                                 const QStyleOptionGraphicsItem *,
338                                                 QWidget *)
339     {
340       drawAll(painter);
341 
342       painter->setPen(this->domainPen());
343       const typename Geom_traits::Iso_rectangle_2 &domain = t->domain();
344       double dx = domain.xmax()-domain.xmin();
345       double dy = domain.ymax()-domain.ymin();
346       typename T::Covering_sheets sheets = t->number_of_sheets();
347       for (int x=0; x<sheets[0]; ++x) {
348         for (int y=0; y<sheets[1]; ++y) {
349           painter->drawRect((int)(domain.xmin() + x*dx),
350                             (int)(domain.ymin() + y*dy),
351                             (int)dx, (int)dy);
352         }
353       }
354       m_painter = painter;
355     }
356 
357     // We let the bounding box only grow, so that when vertices get removed
358     // the maximal bbox gets refreshed in the GraphicsView
359     template <typename T>
360     void
updateBoundingBox()361     PeriodicTriangulationGraphicsItem<T>::updateBoundingBox()
362     {
363       prepareGeometryChange();
364 
365       CGAL::Bbox_2 bb = t->domain().bbox();
366       for (typename T::Periodic_triangle_iterator tit = t->periodic_triangles_begin(T::STORED_COVER_DOMAIN);
367            tit != t->periodic_triangles_end(T::STORED_COVER_DOMAIN); ++tit) {
368         bb = bb + t->triangle(*tit).bbox();
369       }
370 
371       double xmin = bb.xmin();
372       double ymin = bb.ymin();
373       double dx = bb.xmax() - xmin;
374       double dy = bb.ymax() - ymin;
375 
376       double delta = 0.05;
377       xmin -= delta * dx;
378       ymin -= delta * dy;
379       dx += 2 * delta * dx;
380       dy += 2 * delta * dy;
381 
382       bounding_rect = QRectF(xmin, ymin, dx, dy);
383     }
384 
385 
386     template <typename T>
387     void
modelChanged()388     PeriodicTriangulationGraphicsItem<T>::modelChanged()
389     {
390       if((t->number_of_vertices() == 0) ){
391         this->hide();
392       } else if((t->number_of_vertices() > 0) && (! this->isVisible())){
393         this->show();
394       }
395       updateBoundingBox();
396       update();
397     }
398 
399 
400   } // namespace Qt
401 } // namespace CGAL
402 
403 #endif // CGAL_QT_PERIODIC_TRIANGULATION_GRAPHICS_ITEM_H
404