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