1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef VAC_CELL_H
18 #define VAC_CELL_H
19 
20 // Remove C4250 warning in MSVC ('class1' : inherits 'class2::member' via dominance)
21 #if _MSC_VER && !__INTEL_COMPILER
22 #pragma warning(disable:4250)
23 #endif
24 
25 /*
26  * Here is defined the base class for any Cell  of the VAC.
27  *
28  * Any cell:
29  *   - has a pointer back to the VAC it belongs to
30  *   - has an ID, which is unique w.r.t. its VAC
31  *   - can be saved/load
32  *   - can be drawn and selected: Spatial behaviour
33  *   - has a lifetime: Temporal behaviour
34  *
35  * Any cell is either spatially (what the animator see):
36  *   1) Vertex
37  *   2) Edge
38  *   3) Face
39  *
40  * And orthogonally any cell is either temporally:
41  *   A) Key
42  *   B) Inbetween
43  *
44  * Which lead to the six possible cells in our VAC:
45  *   A1) KeyVertex
46  *   A2) KeyEdge
47  *   A3) KeyFace
48  *   B1) InbetweenVertex
49  *   B2) InbetweenEdge
50  *   B3) InbetweenFace
51  *
52  * Because, for instance, all  instant cells share some common
53  * behaviour, it  is very useful to  have a base  class for them
54  * inheriting from Cell and  overiding some of the method, for
55  * instant "bool  exists(time)" would  have been the  exact same
56  * implementation for all the 3  cells KeyVertex, KeyEdge
57  * and  KeyFace.  But because  this  is  also  true for  the
58  * spatial  behaviours, its  leads to  the  unfamous inheritance
59  * diamond pattern, e.g.:
60  *
61  *                        _________
62  *                       |   Cell  |
63  *                        ---------
64  *                       /          \
65  *         ________________        _____________
66  *        |     KeyCell    |      |  VertexCell |
67  *         ----------------        -------------
68  *                       \         /
69  *                     _______________
70  *                    |   KeyVertex   |
71  *                     ---------------
72  *
73  * This is the reason why the abstract classes:
74  *   - KeyCell
75  *   - InbetweenCell
76  *   - VertexCell
77  *   - EdgeCell
78  *   - FaceCell
79  * inherit  only "virtually" the  abstract base  class "Cell",
80  * so that the compiler takes  care not to duplicate the members
81  * of Cell this way, leading to ambiguity:
82  *
83  *            _________               _________
84  *           |   Cell  |             |   Cell  |
85  *            ---------               ---------
86  *                |                       |
87  *         ________________        _____________
88  *        |     KeyCell    |      |  VertexCell |
89  *         ----------------        -------------
90  *                       \         /
91  *                     _______________
92  *                    |   KeyVertex   |
93  *                     ---------------
94  *
95  * Tip: the  word "Cell"  in the name  of a class  reminds you
96  *      that this class is  virtual, and hence that the pointers
97  *      you manipulate can points to different kinds of cells.
98  *
99  */
100 
101 #include "../TimeDef.h"
102 #include "../ViewSettings.h"
103 #include "../View3DSettings.h"
104 #include "CellList.h"
105 #include "Triangles.h"
106 #include "BoundingBox.h"
107 #include <QString>
108 #include <QRect>
109 #include <QColor>
110 class QTextStream;
111 class XmlStreamWriter;
112 class XmlStreamReader;
113 
114 namespace VectorAnimationComplex
115 {
116 
117 class CellObserver;
118 class KeyHalfedge;
119 
120 // The abstract base class Cell
121 class Cell
122 {
123 
124 //###################################################################
125 //                            CORE
126 //###################################################################
127 
128 public:
129     // Get the VAC this cell belongs to, and the cell's id
vac()130     VAC * vac() const { return vac_; }
id()131     int id() const { return id_; }
132 
133     // Destroy the cell safely (syntactic sugar for vac()->deleteCell(this))
134     void destroy();
135 
136     // Observers
137     void addObserver(CellObserver * observer);
138     void removeObserver(CellObserver * observer);
139 
140 protected:
141     // Protected constructor, so only VAC and derived classes can call it.
142     // It creates a cell with VAC `vac`. `vac` must be non null.
143     // It is not inserted in the VAC's containers. No valid ID is given.
144     // All the above must be done by the VAC right after its creation.
145     Cell(VAC * vac);
146 
147     // Virtual protected destructor and helper methods for destruction.
148     // Note: These helper methods *must* be called before and outside
149     //       the actual Cell destructor since they rely on the virtual
150     //       method boundary().
151     virtual ~Cell()=0;
152     void destroyStar();
153     void informBoundaryImGettingDestroyed();
154 
155     // Cloning (caution: it is the caller's responsibility to
156     //                   insert it in the appropriate vac)
157     Cell(Cell * other);
158     virtual Cell * clone()=0;
159     virtual void remapPointers(VAC * newVAC);
160 
161     // Get cell from id (syntactic sugar for vac()->getCell(id))
162     Cell * getCell(int id);
163 
164 private:
165     // Embedding in VAC
166     friend class VAC;
167     VAC * vac_;
168     int id_;
169 
170     // Observers
171     QSet<CellObserver*> observers_;
172 
173 
174 //###################################################################
175 //                          TYPE CASTING
176 //###################################################################
177 
178 public:
to()179     template <class CellClass> CellClass * to() { return dynamic_cast<CellClass*>(this); }
180     Cell * toCell();
181     KeyCell * toKeyCell();
182     InbetweenCell * toInbetweenCell();
183     VertexCell * toVertexCell();
184     EdgeCell * toEdgeCell();
185     FaceCell * toFaceCell();
186     KeyVertex * toKeyVertex();
187     KeyEdge * toKeyEdge();
188     KeyFace * toKeyFace();
189     InbetweenVertex * toInbetweenVertex();
190     InbetweenEdge * toInbetweenEdge();
191     InbetweenFace * toInbetweenFace();
192 
193 
194 //###################################################################
195 //                           TIME
196 //###################################################################
197 
198 public:
199     // Check if the cell exists at this time
exists(Time)200     virtual bool exists(Time /*time*/) const { return false; }
isBefore(Time)201     virtual bool isBefore(Time /*time*/) const { return false; } // true iff cell lifespan \in (-inf,t)
isAfter(Time)202     virtual bool isAfter(Time /*time*/) const { return false; } // true iff cell lifespan \in (t,+inf)
isAt(Time)203     virtual bool isAt(Time /*time*/) const { return false; } // true iff cell lifespan \in { t }. Cannot return true for inbetween cells
204 
205 
206 //###################################################################
207 //                          TOPOLOGY
208 //###################################################################
209 
210 public:
211     // Get cell dimension
212     int dimension();
213 
214     // Topological Navigation Information
215     // ------------ Boundary ------------
216     CellSet boundary() const;
217     virtual CellSet spatialBoundary() const;
218     CellSet spatialBoundary(Time t) const;
219     KeyCellSet temporalBoundary() const;
220     virtual KeyCellSet beforeCells() const;
221     virtual KeyCellSet afterCells() const;
222     // -------------- Star --------------
223     CellSet star() const;
224     CellSet spatialStar() const;
225     CellSet spatialStar(Time t) const;
226     CellSet temporalStar() const;
227     CellSet temporalStarBefore() const;
228     CellSet temporalStarAfter() const;
229     // ---------- Neighbourhood ---------
230     CellSet neighbourhood() const;
231     CellSet spatialNeighbourhood() const;
232     CellSet spatialNeighbourhood(Time t) const;
233     CellSet temporalNeighbourhood() const;
234     CellSet temporalNeighbourhoodBefore() const;
235     CellSet temporalNeighbourhoodAfter() const;
236 
237     // Update cell boundary as a result of a split
238     void updateBoundary(KeyVertex * oldVertex, KeyVertex * newVertex);
239     void updateBoundary(const KeyHalfedge & oldHalfedge, const KeyHalfedge & newHalfedge);
240     void updateBoundary(KeyEdge * oldEdge, const KeyEdgeList & newEdges);
241 
242     // Safety check
243     bool check() const;
244 
245 protected:
246     // --- Modifying star of boundary ---
247     void addMeToStarOfBoundary_();
248     void removeMeFromStarOfBoundary_();
249     void removeMeFromStarOf_(Cell * c);
250     // --- Modifying spatial star of boundary ---
251     void addMeToSpatialStarOf_(Cell * c);
252     void removeMeFromSpatialStarOf_(Cell * c);
253     // --- Modifying temporal star of boundary ---
254     void addMeToTemporalStarBeforeOf_(Cell *c);
255     void addMeToTemporalStarAfterOf_(Cell *c);
256     void removeMeFromTemporalStarBeforeOf_(Cell *c);
257     void removeMeFromTemporalStarAfterOf_(Cell *c);
258 
259 private:
260     // Trusting operators
261     friend class Operator;
262     virtual bool check_() const=0;
263 
264     // Update boundary
265     void updateBoundary_preprocess();
266     void updateBoundary_postprocess();
267     virtual void updateBoundary_impl(KeyVertex * oldVertex, KeyVertex * newVertex);
268     virtual void updateBoundary_impl(const KeyHalfedge & oldHalfedge, const KeyHalfedge & newHalfedge);
269     virtual void updateBoundary_impl(KeyEdge * oldEdge, const KeyEdgeList & newEdges);
270 
271     // Star: Those are the boundary's back-pointers needed for efficiency
272     //       (Otherwise, if implemented as a method, it would be necessary
273     //        to visit all the cells in the VAC to check those whose boundary
274     //        contains this cell)
275     CellSet spatialStar_;
276     CellSet temporalStarBefore_; // We know they are animated cells, but not enforced to be consistent
277     CellSet temporalStarAfter_;  // with spatial star (in which case we know they are either edges of faces)
278                                  // This emphasizes the idea that we do not store any semantics for the star,
279                                  // only for the boundary, and that the star is only stored to inform all of them
280                                  // consistently when a change happened to the boundary
281 
282 
283 //###################################################################
284 //                 HIGHLIGHTING / SELECTING / DRAWING
285 //###################################################################
286 
287 public:
288     // Drawing and Picking, default implementation is:
289     //   - drawing: call glColor(color), then drawRaw()
290 
291     //   - picking: call Picking::setID(), then drawRaw()
292     //
293     // If this behaviour is  enough (e.g., use only one color,
294     // do  not use  some complex  picking), you  just  need to
295     // reimplement drawRaw(), and  modify the protected member
296     // "color".
297     //
298     // Note that it does take into account the selected and/or
299     // highlighted state to choose the color to draw. Hence it
300     // is better not to override other methods than drawRaw if
301     // not necessary, to ensure homogeneous behaviour.
302     // Todo: use the Visitor Pattern instead
303     //       this would reduce the number of virtual functions
304     //       and then the size of cell objects
305     virtual void draw(Time time, ViewSettings & viewSettings);
306     virtual void drawRaw(Time time, ViewSettings & viewSettings);
307     void drawPick(Time time, ViewSettings & viewSettings);
308 
309     virtual void drawTopology(Time time, ViewSettings & viewSettings);
310     virtual void drawRawTopology(Time time, ViewSettings & viewSettings);
311     void drawPickTopology(Time time, ViewSettings & viewSettings);
312 
313     virtual void draw3D(View3DSettings & viewSettings);
314     virtual void drawRaw3D(View3DSettings & viewSettings);
315     virtual void drawPick3D(View3DSettings & viewSettings);
316 
317     // Highlighting and Selecting
isHovered()318     bool isHovered() const  { return isHovered_; }
isSelected()319     bool isSelected()    const  { return isSelected_;    }
320     bool isHighlighted() const;
321 
322     // Change the color of the cell
323     QColor color() const;
324     void setColor(const QColor & c);
325 
326 protected:
327     // Make a call to  glColor, taking into account the member
328     // color,  the selected state  and the  highlighted state.
329     // Made virtual  for flexibility (automatically  called by
330     // draw() if not overriden), but you should avoid override
331     // it to ensure homogeneous behaviour.
332     virtual QColor getColor(Time time, ViewSettings & viewSettings) const;
333     virtual void glColor_(Time time, ViewSettings & viewSettings);
334     virtual void glColorTopology_();
335     virtual void glColor3D_();
336     double colorHighlighted_[4];
337     double colorSelected_[4];
338     double color_[4];
339 
340 private:
341     // highlighting and selecting
342     bool isHovered_;
343     bool isSelected_;
setHovered(bool b)344     void setHovered(bool b) { isHovered_ = b;    }
setSelected(bool b)345     void setSelected(bool b) { isSelected_    = b;    }
346 
347     // Non-Virtual Interface idiom
348     bool isPickable(Time time) const;
349     virtual bool isPickableCustom(Time time) const;
350     virtual void drawPickCustom(Time time, ViewSettings & viewSettings);
351     virtual void drawPickTopologyCustom(Time time, ViewSettings & viewSettings);
352 
353 
354 //###################################################################
355 //                            I/O
356 //###################################################################
357 
358 protected:
359     // Serializating
360     void write(XmlStreamWriter & xml) const;
361     virtual QString xmlType_() const;
362     virtual void write_(XmlStreamWriter & xml) const;
363 
364     // Unserializing
365     Cell(VAC * vac, XmlStreamReader & xml);
366     virtual void read2ndPass();
367 
368     // Serializing / Unserializing (DEPRECATED)
369     void save(QTextStream & out);
370     virtual void save_(QTextStream & out); // called at the end of save(), for derived object
stringType()371     virtual QString stringType() const {return "Cell";}
372     Cell(VAC * vac, QTextStream & in);
373     static Cell * read1stPass(VAC * vac, QTextStream & in);
374 
375     // Export
376     virtual void exportSVG(Time t, QTextStream & out);
377 
378 
379 //###################################################################
380 //                         GEOMETRY
381 //###################################################################
382 
383 public:
384     // Get all the triangles to be rendered at given time
385     const Triangles & triangles(Time t) const;
386 
387     // Get the bounding box of this cell at time t
388     const BoundingBox & boundingBox(Time t) const;
389     const BoundingBox & outlineBoundingBox(Time t) const;
390 
391     // Get the bounding box of this cell for all time t
392     virtual BoundingBox boundingBox() const=0;
393     virtual BoundingBox outlineBoundingBox() const=0;
394 
395     // Cell-BoundingBox intersection test. It uses the actual geometry of the
396     // cell, i.e. it is more expensive but more accurate than:
397     //     boundingBox(t).intersects(bb);
398     bool intersects(Time t, const BoundingBox & bb) const;
399 
400 protected:
401     // Method to be called by derived classes when their geometry changes
402     void processGeometryChanged_();
403 
404     // Clear cached geometry (derived classes caching more data may specialize it)
405     virtual void clearCachedGeometry_();
406 
407 private:
408     // Cached triangulations and bounding boxes (the integer represent a 1/60th of frame)
409     mutable QMap<int,Triangles> triangles_;
410     mutable QMap<int,BoundingBox> boundingBoxes_;
411     mutable QMap<int,BoundingBox> outlineBoundingBoxes_;
412 
413     // Compute triangulation for time t (must be implemented by derived classes)
414     virtual void triangulate_(Time t, Triangles & out) const=0;
415 
416     // Compute outline bounding box for time t (must be implemented by derived classes)
417     virtual void computeOutlineBoundingBox_(Time t, BoundingBox & out) const=0;
418 
419     // Return the list of cells whose geometry depends on this cell's geometry
420     CellSet geometryDependentCells_();
421 };
422 
423 }
424 
425 #endif
426