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 #include "../OpenGL.h"
18 
19 #include "VAC.h"
20 
21 #include "KeyVertex.h"
22 #include "KeyEdge.h"
23 #include "KeyFace.h"
24 #include "InbetweenVertex.h"
25 #include "InbetweenEdge.h"
26 #include "InbetweenFace.h"
27 
28 #include "Halfedge.h"
29 #include "ProperCycle.h"
30 #include "Cycle.h"
31 #include "ProperPath.h"
32 #include "Path.h"
33 #include "SmartKeyEdgeSet.h"
34 
35 #include "Algorithms.h"
36 #include "CellObserver.h"
37 
38 #include "EdgeSample.h"
39 #include "EdgeGeometry.h"
40 #include "Intersection.h"
41 
42 #include "../GLUtils.h"
43 #include "../Timeline.h"
44 #include "../SaveAndLoad.h"
45 #include "../DevSettings.h"
46 #include "../Global.h"
47 #include "../MainWindow.h"
48 #include "../View.h"
49 #include "../Color.h"
50 #include "../Scene.h"
51 
52 #include "../XmlStreamWriter.h"
53 #include "../XmlStreamReader.h"
54 
55 #include <QPair>
56 #include <QtDebug>
57 #include <QApplication>
58 #include <QMessageBox>
59 #include <QStatusBar>
60 #include <QColorDialog>
61 #include <QInputDialog>
62 
63 #define MYDEBUG 0
64 
65 namespace VectorAnimationComplex
66 {
67 
68 
69 // unnamed namespace not to pollute global namespace with auxiliary functions
70 namespace
71 {
72 
73 const double PI = 3.14159;
74 
isCycleContainedInFace(const Cycle & cycle,const PreviewKeyFace & face)75 bool isCycleContainedInFace(const Cycle & cycle, const PreviewKeyFace & face)
76 {
77     // Get edges involved in cycle
78     KeyEdgeSet cycleEdges = cycle.cells();
79 
80     // Compute total length of edges
81     double totalLength = 0;
82     foreach (KeyEdge * edge, cycleEdges)
83         totalLength += edge->geometry()->length();
84 
85     // Compute percentage of edges inside face, based on approximately N samples
86     double N = 100;
87     double ds = totalLength / N;
88     double nInside = 0;
89     double nOutside = 0;
90     foreach (KeyEdge * edge, cycleEdges)
91     {
92         EdgeGeometry * geometry = edge->geometry();
93         double L = geometry->length();
94         for(double s=0; s<L; s+=ds)
95         {
96             Eigen::Vector2d p = geometry->pos2d(s);
97             if(face.intersects(p[0],p[1]))
98             {
99                 nInside++;
100             }
101             else
102             {
103                 nOutside++;
104             }
105         }
106     }
107     if(nInside > nOutside)
108         return true;
109     else
110         return false;
111 }
112 
113 // return invalid cycle if not found
findClosestPlanarCycle(QSet<KeyEdge * > & potentialEdges,QMap<KeyEdge *,EdgeGeometry::ClosestVertexInfo> & distancesToEdges,double x,double y)114 Cycle findClosestPlanarCycle(QSet<KeyEdge*> & potentialEdges,
115                                     QMap<KeyEdge*,EdgeGeometry::ClosestVertexInfo> & distancesToEdges, double x, double y)
116 {
117     while(!potentialEdges.isEmpty())
118     {
119         // Find closest potential edge
120         KeyEdge * closestPotentialEdge = 0;
121         EdgeGeometry::ClosestVertexInfo cvi;
122         cvi.s = 0;
123         cvi.d = std::numeric_limits<double>::max();
124         foreach(KeyEdge * e, potentialEdges)
125         {
126             EdgeGeometry::ClosestVertexInfo cvi_e = distancesToEdges[e];
127             if(cvi_e.d < cvi.d)
128             {
129                 closestPotentialEdge = e;
130                 cvi = cvi_e;
131             }
132         }
133 
134         // Compute direction of halfedge
135         Eigen::Vector2d der = closestPotentialEdge->geometry()->der(cvi.s);
136         double cross = der[0] * (y - cvi.p.y()) - der[1] * (x - cvi.p.x());
137         KeyHalfedge h(closestPotentialEdge, (cross>0 ? false : true) ); // Note: canvas is left-handed
138 
139         // Case where closestPotentialEdge is closed
140         if(closestPotentialEdge->isClosed())
141         {
142             KeyEdgeSet edgeSet;
143             edgeSet << closestPotentialEdge;
144             Cycle cycle(edgeSet);
145             if(cycle.isValid())
146             {
147                 return cycle;
148             }
149             else
150             {
151                 potentialEdges.remove(closestPotentialEdge);
152             }
153         }
154 
155         // Case where closestPotentialEdge is open
156         else
157         {
158             // First halfedge of non-simple-cycle
159             KeyHalfedge h0 = h;
160             QList<KeyHalfedge> potentialPlanarCycle;
161             potentialPlanarCycle << h;
162 
163             // Find the corresponding planar map cycle
164             int maxIter = 2 * potentialEdges.size() + 2;
165             bool foundPotentialPlanarCycle = false;
166             for(int i=0; i<maxIter; i++)
167             {
168                 // Find next halfedge in cycle
169                 h = h.next();
170 
171                 // Check it has not already been rejected
172                 if(!potentialEdges.contains(h.edge))
173                 {
174                     break;
175                 }
176 
177                 // Test if cycle completed or not
178                 if(h == h0)
179                 {
180                     // Cycle completed: leave loop
181                     foundPotentialPlanarCycle = true;
182                     break;
183                 }
184                 else
185                 {
186                     // Cycle not completed: insert and iterate
187                     potentialPlanarCycle << h;
188                 }
189             }
190 
191             // If not found (maxIter reached or edge already rejected)
192             if(!foundPotentialPlanarCycle)
193             {
194                 foreach(KeyHalfedge he, potentialPlanarCycle)
195                 {
196                     potentialEdges.remove(he.edge);
197                 }
198             }
199             else
200             {
201                 Cycle cycle(potentialPlanarCycle);
202                 if(cycle.isValid())
203                 {
204                     return cycle;
205                 }
206                 else
207                 {
208                     foreach(KeyHalfedge he, potentialPlanarCycle)
209                     {
210                         potentialEdges.remove(he.edge);
211                     }
212                 }
213             }
214         }
215     }
216 
217     return Cycle();
218 }
219 
addHoleToPaintedFace(QSet<KeyEdge * > & potentialHoleEdges,PreviewKeyFace & toBePaintedFace,QMap<KeyEdge *,EdgeGeometry::ClosestVertexInfo> & distancesToEdges,double x,double y)220 bool addHoleToPaintedFace(QSet<KeyEdge*> & potentialHoleEdges,
221                           PreviewKeyFace & toBePaintedFace,
222                           QMap<KeyEdge*,EdgeGeometry::ClosestVertexInfo> & distancesToEdges,
223                           double x, double y)
224 {
225     while(!potentialHoleEdges.isEmpty())
226     {
227         // Find closest planar cycle
228         Cycle cycle = findClosestPlanarCycle(potentialHoleEdges, distancesToEdges, x, y);
229 
230         // Returns directly if no planar cycle found, otherwise, proceed.
231         if(!cycle.isValid())
232         {
233             return false;
234         }
235 
236         // Remove potential edges
237         KeyEdgeSet cycleEdges = cycle.cells();
238         potentialHoleEdges.subtract(cycleEdges);
239 
240         // Create face from cycle for geometric query
241         PreviewKeyFace face;
242         face << cycle;
243 
244         // Check if the planar cycle should be added as a hole or not
245         if(!face.intersects(x,y) && isCycleContainedInFace(cycle,toBePaintedFace))
246         {
247             // Add it as a hole
248             toBePaintedFace << cycle;
249             return true;
250         }
251 
252     }// end while( !( found external boundary || isEmpty) )
253 
254     return false;
255 }
256 
257 } // end of namespace
258 
259 
260 
261     // ----------------- Constructors & Destructors ----------------
262 
263 
initNonCopyable()264 void VAC::initNonCopyable()
265 {
266     drawRectangleOfSelection_ = false;
267     sketchedEdge_ = 0;
268     hoveredFaceOnMousePress_ = 0;
269     hoveredFaceOnMouseRelease_ = 0;
270     sculptedEdge_ = 0;
271     toBePaintedFace_ = 0;
272     hoveredCell_ = 0;
273     transformTool_.setNoHoveredObject();
274     transformTool_.setCells(CellSet());
275     deselectAll();
276     signalCounter_ = 0;
277 }
278 
initCopyable()279 void VAC::initCopyable()
280 {
281     setMaxID_(-1);
282     ds_ = 5.0;
283     cells_.clear();
284     zOrdering_.clear();
285 }
286 
287 
VAC()288 VAC::VAC() :
289     SceneObject()
290 {
291     initNonCopyable();
292     initCopyable();
293 }
294 
~VAC()295 VAC::~VAC()
296 {
297     deleteAllCells();
298 }
299 
stringType()300 QString VAC::stringType()
301 {
302     return "VectorAnimationComplex";
303 }
304 
305 
clone()306 VAC * VAC::clone()
307 {
308     // Create new Graph
309     VAC * newVAC = new VAC();
310 
311     // Copy maxID
312     newVAC->setMaxID_(maxID_);
313 
314     // Copy sampling precision
315     newVAC->ds_ = ds_;
316 
317     // Copy cells
318     foreach(Cell * cell, cells_)
319     {
320         Cell * newCell = cell->clone();
321         newVAC->cells_[newCell->id()] = newCell;
322         newCell->setSelected(false);
323         newCell->setHovered(false);
324     }
325     foreach(Cell * newCell, newVAC->cells_)
326         newCell->remapPointers(newVAC);
327     for(auto c: zOrdering_)
328         newVAC->zOrdering_.insertLast(newVAC->getCell(c->id()));
329 
330     return newVAC;
331 }
332 
333 // returns a map such as mp[oldID] = newID
import(VAC * other,bool selectImportedCells)334 QMap<int,int> VAC::import(VAC * other, bool selectImportedCells)
335 {
336     QMap<int,int> res;
337 
338     // Create copy
339     VAC * copyOfOther = other->clone();
340 
341     // Create copy of zOrdering, since removing cells
342     // from copyOfOther invalidate iteration on zOrdering
343     QList<Cell*> ordering;
344     for(auto c: copyOfOther->zOrdering_)
345     {
346         ordering << c;
347     }
348 
349     // Take ownership of all cells
350     foreach(Cell * c, ordering)
351     {
352         int oldID = c->id();
353         copyOfOther->removeCell_(c);
354         insertCellLast_(c);
355         if(selectImportedCells)
356             addToSelection(c,false);
357         res[oldID] = c->id();
358     }
359 
360     // Delete copy of vac
361     delete copyOfOther;
362 
363     return res;
364 }
365 
subcomplex(const CellSet & subcomplexCells)366 VAC * VAC::subcomplex(const CellSet & subcomplexCells)
367 {
368     // Get closure of cells
369     CellSet cellsToKeep = Algorithms::closure(subcomplexCells);
370     CellSet cellsToDelete = cells();
371     cellsToDelete.subtract(cellsToKeep);
372     QList<int> idToDelete;
373     foreach(Cell * c, cellsToDelete)
374         idToDelete << c->id();
375 
376     // Create new Graph
377     VAC * newVAC = clone();
378 
379     // Delete all cells but the one to keep
380     foreach (double id, idToDelete)
381     {
382         if(newVAC->cells_.contains(id))
383             newVAC->deleteCell(newVAC->getCell(id));
384     }
385 
386     // Return subcomplex
387     return newVAC;
388 }
389 
390 // ------------------------- Drawing ---------------------------
391 
drawSketchedEdge(Time time,ViewSettings &) const392 void VAC::drawSketchedEdge(Time time, ViewSettings & /*viewSettings*/) const
393 {
394     if(!sketchedEdge_)
395         return;
396 
397     if(time.frame() != timeInteractivity_.frame())
398         return;
399 
400     if(sketchedEdge_->size() < 2)
401         return;
402 
403     QColor edgeColor = global()->edgeColor();
404     glColor4d(edgeColor.redF(),edgeColor.greenF(),edgeColor.blueF(),edgeColor.alphaF());
405 
406     // helper function
407     auto getNormal = [] (double x1, double y1, double x2, double y2)
408     {
409         Eigen::Vector2d p1(x1, y1);
410         Eigen::Vector2d p2(x2, y2);
411         Eigen::Vector2d v = p2-p1;
412         v.normalize();
413         return Eigen::Vector2d(-v[1],v[0]);
414     };
415 
416     // draw quad strip
417     glBegin(GL_QUAD_STRIP);
418     Eigen::Vector2d u = getNormal((*sketchedEdge_)[0].x(), (*sketchedEdge_)[0].y(),
419             (*sketchedEdge_)[1].x(), (*sketchedEdge_)[1].y());
420     Eigen::Vector2d p( (*sketchedEdge_)[0].x(), (*sketchedEdge_)[0].y() );
421     Eigen::Vector2d A = p + (*sketchedEdge_)[0].width() * 0.5 * u;
422     Eigen::Vector2d B = p - (*sketchedEdge_)[0].width() * 0.5 * u;
423     glVertex2d(A[0], A[1]);
424     glVertex2d(B[0], B[1]);
425     p = Eigen::Vector2d( (*sketchedEdge_)[1].x(), (*sketchedEdge_)[1].y() );
426     A = p + (*sketchedEdge_)[1].width() * 0.5 * u;
427     B = p - (*sketchedEdge_)[1].width() * 0.5 * u;
428     glVertex2d(A[0], A[1]);
429     glVertex2d(B[0], B[1]);
430     for(int i=2; i<(*sketchedEdge_).size(); i++)
431     {
432         Eigen::Vector2d u = getNormal((*sketchedEdge_)[i-1].x(), (*sketchedEdge_)[i-1].y(),
433                 (*sketchedEdge_)[i].x(), (*sketchedEdge_)[i].y());
434         p = Eigen::Vector2d( (*sketchedEdge_)[i].x(), (*sketchedEdge_)[i].y() );
435         A = p + (*sketchedEdge_)[i].width() * 0.5 * u;
436         B = p - (*sketchedEdge_)[i].width() * 0.5 * u;
437         glVertex2d(A[0], A[1]);
438         glVertex2d(B[0], B[1]);
439     }
440     glEnd();
441 
442     // Start cap
443     int n = 50;
444     p = Eigen::Vector2d( sketchedEdge_->leftPos().x(), sketchedEdge_->leftPos().y() );
445     double r = 0.5 * sketchedEdge_->leftPos().width();
446     glBegin(GL_POLYGON);
447     {
448         for(int i=0; i<n; ++i)
449         {
450             double theta = 2 * (double) i * 3.14159 / (double) n ;
451             glVertex2d(p.x() + r*std::cos(theta),p.y()+ r*std::sin(theta));
452         }
453     }
454     glEnd();
455 
456     // End cap
457     p = Eigen::Vector2d( sketchedEdge_->rightPos().x(), sketchedEdge_->rightPos().y() );
458     r = 0.5 * sketchedEdge_->rightPos().width();
459     glBegin(GL_POLYGON);
460     {
461         for(int i=0; i<n; ++i)
462         {
463             double theta = 2 * (double) i * 3.14159 / (double) n ;
464             glVertex2d(p.x() + r*std::cos(theta),p.y()+ r*std::sin(theta));
465         }
466     }
467     glEnd();
468 }
469 
drawTopologySketchedEdge(Time time,ViewSettings & viewSettings) const470 void VAC::drawTopologySketchedEdge(Time time, ViewSettings & viewSettings) const
471 {
472     if(!sketchedEdge_)
473         return;
474 
475     if(time.frame() != timeInteractivity_.frame())
476         return;
477 
478     if(sketchedEdge_->size() < 2)
479         return;
480 
481     glColor4d(0.18,0.60,0.90,1);
482     glLineWidth(viewSettings.edgeTopologyWidth());
483     glBegin(GL_LINE_STRIP);
484     for(int i=0; i<(*sketchedEdge_).size(); i++)
485         glVertex2d((*sketchedEdge_)[i].x(), (*sketchedEdge_)[i].y());
486     glEnd();
487 }
488 
drawOneFrame3D(Time time,View3DSettings & viewSettings,ViewSettings & view2DSettings,bool drawAsTopo)489 void VAC::drawOneFrame3D(Time time, View3DSettings & viewSettings, ViewSettings & view2DSettings, bool drawAsTopo)
490 {
491     // Translate to appropriate z value
492     double z = viewSettings.zFromT(time);
493     glPushMatrix();
494     glScaled(1, -1, 1);
495     glTranslated(0,0,z);
496 
497     glDisable(GL_LIGHTING);
498     //glDisable(GL_DEPTH_TEST); // Responsability of caller to do this because
499                                 // sometimes it should be disabled, sometimes not
500     double eps = 1.0e-2;
501     for(auto c: zOrdering_)
502     {
503         if(drawAsTopo)
504             c->drawTopology(time, view2DSettings);
505         else
506             c->draw(time, view2DSettings);
507         if(c->exists(time))
508             glTranslated(0,0,eps);
509     }
510 
511     //glEnable(GL_DEPTH_TEST);
512 
513     glPopMatrix();
514 }
515 
drawAllFrames3D(View3DSettings & viewSettings,ViewSettings & view2DSettings)516 void VAC::drawAllFrames3D(View3DSettings & viewSettings, ViewSettings & view2DSettings)
517 {
518     Timeline * timeline = global()->timeline();
519     int firstFrame = timeline->firstFrame();
520     int lastFrame = timeline->lastFrame();
521 
522     for(int i=lastFrame; i>=firstFrame; --i)
523         drawOneFrame3D(Time(i), viewSettings, view2DSettings, viewSettings.drawFramesAsTopology());
524 }
525 
drawKeyCells3D(View3DSettings & viewSettings,ViewSettings & view2DSettings)526 void VAC::drawKeyCells3D(View3DSettings & viewSettings, ViewSettings & view2DSettings)
527 {
528     QMap<int, QList<KeyCell *> > keyCellsOrderedAtFrame;
529     for(auto c: zOrdering_)
530     {
531         KeyCell * kc = c->toKeyCell();
532         if(kc)
533         {
534             int frame = kc->time().frame();
535             keyCellsOrderedAtFrame[frame].append(kc);
536         }
537     }
538 
539     QMapIterator<int, QList<KeyCell *> > i(keyCellsOrderedAtFrame);
540     while (i.hasNext())
541     {
542         i.next();
543 
544         // Get list of key frames at frame
545         int frame = i.key();
546         QList<KeyCell *> list = i.value();
547         Time t = Time(frame);
548 
549         // Special case: don't draw if overlayed with current frame
550         if(viewSettings.drawCurrentFrame() && ( t == global()->activeTime() ) )
551             continue;
552 
553         // Translate to appropriate z value
554         double z = viewSettings.zFromT(t);
555         glPushMatrix();
556         glScaled(1, -1, 1);
557         glTranslated(0,0,z);
558 
559         glDisable(GL_LIGHTING);
560 
561         glPushMatrix();
562         double eps = 1.0e-2;
563         foreach(KeyCell * c, list)
564         {
565             if(viewSettings.drawFramesAsTopology())
566                 c->drawTopology(t, view2DSettings);
567             else
568                 c->draw(t, view2DSettings);
569 
570             glTranslated(0,0,eps);
571         }
572         glPopMatrix(); // XXX Two pushes, one pop, isn't there a hidden bug here????
573     }
574 }
575 
drawInbetweenCells3D(View3DSettings & viewSettings)576 void VAC::drawInbetweenCells3D(View3DSettings & viewSettings)
577 {
578     // Draw inbetween vertices
579     InbetweenVertexSet inbetweenVertices = cells();
580     foreach(InbetweenVertex * v, inbetweenVertices)
581         v->draw3D(viewSettings);
582 
583     // Draw inbetween edges
584     //glColor4d(1.0,0.5,0.5,viewSettings.opacity());
585     glColor4d(0.6, 0.4, 0.4, 1.0);
586     if(viewSettings.drawAsMesh())
587         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
588     InbetweenEdgeSet inbetweenEdges = cells();
589     foreach(InbetweenEdge * e, inbetweenEdges)
590         e->draw3D(viewSettings);
591     if(viewSettings.drawAsMesh())
592         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
593 }
594 
drawPick3D(View3DSettings &)595 void VAC::drawPick3D(View3DSettings & /*viewSettings*/)
596 {
597 }
598 
draw(Time time,ViewSettings & viewSettings)599 void VAC::draw(Time time, ViewSettings & viewSettings)
600 {
601     ViewSettings::DisplayMode displayMode = viewSettings.displayMode();
602 
603     // Illustration mode
604     if( (displayMode == ViewSettings::ILLUSTRATION))
605     {
606         // Draw all cells
607         for(auto c: zOrdering_)
608             c->draw(time, viewSettings);
609 
610         // Draw sketched edge
611         if(sketchedEdge_)
612             drawSketchedEdge(time, viewSettings);
613     }
614 
615     // Outline only mode
616     else if( (displayMode == ViewSettings::OUTLINE) )
617     {
618         // Draw all cells
619         for(auto c: zOrdering_)
620             c->drawTopology(time, viewSettings);
621 
622         // Draw sketched edge
623         if(sketchedEdge_)
624             drawTopologySketchedEdge(time, viewSettings);
625     }
626 
627     // Illustration + Outline mode
628     else if( (displayMode == ViewSettings::ILLUSTRATION_OUTLINE) )
629     {
630         // First pass
631         for(auto c: zOrdering_)
632             c->draw(time, viewSettings);
633         if(sketchedEdge_)
634             drawSketchedEdge(time, viewSettings);
635 
636         // Second pass
637         for(auto c: zOrdering_)
638             c->drawTopology(time, viewSettings);
639         if(sketchedEdge_)
640             drawTopologySketchedEdge(time, viewSettings);
641     }
642 
643     // Draw to be painted face
644     if( (global()->toolMode() == Global::PAINT) &&
645             toBePaintedFace_)
646     {
647         toBePaintedFace_->draw(viewSettings);
648     }
649 
650     // Draw sculpt cursor
651     if(viewSettings.drawCursor()
652             && global()->toolMode() == Global::SCULPT
653             && sculptedEdge_
654             && !(hoveredCell_
655                  && (hoveredCell_->toKeyVertex()
656                      // || selectedCells_.contains(highlightedCell_)
657                      )
658                  )
659             && global()->hoveredView()
660             && global()->hoveredView()->activeTime() == time)
661     {
662         // set color of cursor
663         glColor3d(1,0,0);
664 
665         // draw point on instant edge
666         int n = 50;
667         EdgeSample p = sculptedEdge_->geometry()->sculptVertex();
668         glBegin(GL_POLYGON);
669         {
670             double r = 0.5 * p.width();
671             if(displayMode == ViewSettings::ILLUSTRATION_OUTLINE ||
672                     displayMode == ViewSettings::OUTLINE )
673             {
674                 r = 5.0  / viewSettings.zoom();
675             }
676             else if ( r == 0 )
677             {
678                 r = 3.0 / viewSettings.zoom();
679             }
680             else if (r * viewSettings.zoom() < 1)
681             {
682                 r = 1.0 / viewSettings.zoom();
683             }
684             for(int i=0; i<n; ++i)
685             {
686                 double theta = 2 * (double) i * 3.14159 / (double) n ;
687                 glVertex2d(p.x() + r*std::cos(theta),p.y()+ r*std::sin(theta));
688             }
689         }
690         glEnd();
691 
692         // draw circle of influence
693         glLineWidth(1);
694         glBegin(GL_LINE_LOOP);
695         {
696             double r = global()->sculptRadius();
697             for(int i=0; i<n; ++i)
698             {
699                 double theta = 2 * (double) i * 3.14159 / (double) n ;
700                 glVertex2d(p.x() + r*std::cos(theta),p.y()+ r*std::sin(theta));
701             }
702         }
703         glEnd();
704     }
705 
706     // Draw pen radius and snap threshold
707     if(viewSettings.drawCursor()
708             && global()->toolMode() == Global::SKETCH
709             && global()->hoveredView()
710             && global()->hoveredView()->activeTime() == time)
711     {
712 
713         // Set color of cursor. We enforce alpha>0.2 to make sure users see something
714         QColor color = global()->edgeColor();
715         glColor4d(color.redF(),color.greenF(),color.blueF(), std::max(0.2, color.alphaF()));
716 
717         // Get position of cursor in scene coordinates
718         Eigen::Vector2d p = global()->sceneCursorPos();
719 
720         // Draw pen cursor position + radius as disk
721         int n = 50;
722         glBegin(GL_POLYGON);
723         {
724             // Note: Unlike for the sculpt radius widget, we always draw the sketch widget with the actual
725             //       drawn width even in topology mode, since we want to give feedback to the user to what's
726             //       drawn under the hood
727             double r = 0.5 * global()->edgeWidth();
728 
729             //if(displayMode == ViewSettings::ILLUSTRATION_OUTLINE ||
730             //   displayMode == ViewSettings::OUTLINE )
731             //{
732             //    r = 5.0  / viewSettings.zoom();
733             //}
734             //else
735             if ( r == 0 )
736             {
737                 r = 3.0 / viewSettings.zoom();
738             }
739             else if (r * viewSettings.zoom() < 1)
740             {
741                 r = 1.0 / viewSettings.zoom();
742             }
743             for(int i=0; i<n; ++i)
744             {
745                 double theta = 2 * (double) i * 3.14159 / (double) n ;
746                 glVertex2d(p[0] + r*std::cos(theta),p[1]+ r*std::sin(theta));
747             }
748         }
749         glEnd();
750 
751         // draw snap radius
752         if(global()->snapMode())
753         {
754             glLineWidth(1);
755             glBegin(GL_LINE_LOOP);
756             {
757                 double r = global()->snapThreshold();
758                 for(int i=0; i<n; ++i)
759                 {
760                     double theta = 2 * (double) i * 3.14159 / (double) n ;
761                     glVertex2d(p[0] + r*std::cos(theta),p[1]+ r*std::sin(theta));
762                 }
763             }
764             glEnd();
765         }
766 
767 
768     }
769 
770     // Rectangle of selection
771     if(drawRectangleOfSelection_ && viewSettings.isMainDrawing())
772     {
773         glColor4d(0.5,0.5,0.8,0.2);
774         glLineWidth(1);
775         glBegin(GL_QUADS);
776         {
777             glVertex2d(rectangleOfSelectionStartX_,rectangleOfSelectionStartY_);
778             glVertex2d(rectangleOfSelectionStartX_,rectangleOfSelectionEndY_);
779             glVertex2d(rectangleOfSelectionEndX_,rectangleOfSelectionEndY_);
780             glVertex2d(rectangleOfSelectionEndX_,rectangleOfSelectionStartY_);
781         }
782         glEnd();
783         glColor4d(0,0,0,1);
784         glLineWidth(1);
785         glBegin(GL_LINE_LOOP);
786         {
787             glVertex2d(rectangleOfSelectionStartX_,rectangleOfSelectionStartY_);
788             glVertex2d(rectangleOfSelectionStartX_,rectangleOfSelectionEndY_);
789             glVertex2d(rectangleOfSelectionEndX_,rectangleOfSelectionEndY_);
790             glVertex2d(rectangleOfSelectionEndX_,rectangleOfSelectionStartY_);
791         }
792         glEnd();
793     }
794 
795     // Transform tool
796     if(global()->toolMode() == Global::SELECT && viewSettings.isMainDrawing())
797     {
798         transformTool_.draw(selectedCells_, time, viewSettings);
799     }
800 
801     // Draw edge orientation
802     if(DevSettings::getBool("draw edge orientation"))
803     {
804         KeyEdgeSet edges = cells();
805         foreach(KeyEdge * e, edges)
806         {
807             if(e->exists(time))
808             {
809                 double l = e->geometry()->length();
810                 Eigen::Vector2d p = e->geometry()->pos2d(0.5*l);
811                 Eigen::Vector2d u = e->geometry()->der(0.5*l);
812                 GLUtils::drawArrow(p,u);
813             }
814         }
815         InbetweenEdgeSet sedges = cells();
816         foreach(InbetweenEdge * se, sedges)
817         {
818             if(se->exists(time))
819             {
820                 QList<EdgeSample> samples = se->getSampling(time);
821                 LinearSpline ls(samples);
822                 double l = ls.length();
823                 Eigen::Vector2d p = ls.pos2d(0.5*l);
824                 Eigen::Vector2d u = ls.der(0.5*l);
825                 GLUtils::drawArrow(p,u);
826             }
827         }
828     }
829 }
830 
drawPick(Time time,ViewSettings & viewSettings)831 void VAC::drawPick(Time time, ViewSettings & viewSettings)
832 {
833     ViewSettings::DisplayMode displayMode = viewSettings.displayMode();
834 
835     if( (displayMode == ViewSettings::ILLUSTRATION) )
836     {
837         // Draw all cells
838         for(auto c: zOrdering_)
839         {
840             c->drawPick(time, viewSettings);
841         }
842     }
843 
844     else if( (displayMode == ViewSettings::OUTLINE) )
845     {
846         // Draw all cells
847         for(auto c: zOrdering_)
848         {
849             c->drawPickTopology(time, viewSettings);
850         }
851     }
852 
853     else if( (displayMode == ViewSettings::ILLUSTRATION_OUTLINE) )
854     {
855         // first pass: pick faces normally
856         for(auto c: zOrdering_)
857         {
858             if(c->toFaceCell())
859                 c->drawPick(time, viewSettings);
860         }
861 
862 
863         // second pass: pick vertices and edges as outline
864         for(auto c: zOrdering_)
865         {
866             if(!c->toFaceCell())
867                 c->drawPickTopology(time, viewSettings);
868         }
869     }
870 
871     // Transform tool
872     if(global()->toolMode() == Global::SELECT && viewSettings.isMainDrawing())
873     {
874         transformTool_.drawPick(selectedCells_, time, viewSettings);
875     }
876 }
877 
878 
emitSelectionChanged_()879 void VAC::emitSelectionChanged_()
880 {
881     if(signalCounter_ == 0)
882     {
883         transformTool_.setCells(selectedCells());
884         emit selectionChanged();
885         informTimelineOfSelection();
886     }
887     else
888     {
889         shouldEmitSelectionChanged_ = true;
890     }
891 }
892 
beginAggregateSignals_()893 void VAC::beginAggregateSignals_()
894 {
895     if(signalCounter_ == 0)
896     {
897         shouldEmitSelectionChanged_ = false;
898     }
899 
900     signalCounter_++;
901 }
902 
endAggregateSignals_()903 void VAC::endAggregateSignals_()
904 {
905     signalCounter_--;
906 
907     if(signalCounter_ == 0)
908     {
909         if(shouldEmitSelectionChanged_)
910         {
911             transformTool_.setCells(selectedCells());
912             emit selectionChanged();
913         }
914     }
915 }
916 
917 
918 
919 // ----------------- Selecting and Highlighting ----------------
920 
921 // Should NOT emit changed(). View does it if necessary
922 
setHoveredObject(Time,int id)923 void VAC::setHoveredObject(Time /*time*/, int id)
924 {
925     setHoveredCell(getCell(id));
926     transformTool_.setHoveredObject(id);
927 }
928 
setNoHoveredObject()929 void VAC::setNoHoveredObject()
930 {
931     setNoHoveredCell();
932     transformTool_.setNoHoveredObject();
933 }
934 
select(Time,int id)935 void VAC::select(Time /*time*/, int id)
936 {
937     addToSelection(getCell(id),false);
938 }
939 
deselect(Time,int id)940 void VAC::deselect(Time /*time*/, int id)
941 {
942     removeFromSelection(getCell(id),false);
943 }
944 
toggle(Time,int id)945 void VAC::toggle(Time /*time*/, int id)
946 {
947     toggleSelection(getCell(id),false);
948 }
949 
deselectAll(Time time)950 void VAC::deselectAll(Time time)
951 {
952     CellSet cellsToDeselect;
953     foreach(Cell * cell, selectedCells())
954         if(cell->exists(time))
955             cellsToDeselect << cell;
956     removeFromSelection(cellsToDeselect,false);
957 }
958 
deselectAll()959 void VAC::deselectAll()
960 {
961     if(numSelectedCells() != 0)
962         setSelectedCells(CellSet(),false);
963 }
964 
invertSelection()965 void VAC::invertSelection()
966 {
967     QSet<Cell *> newSelectedCells = cells();
968     newSelectedCells.subtract(selectedCells());
969     setSelectedCells(newSelectedCells);
970 }
971 
hoveredCell() const972 Cell * VAC::hoveredCell() const
973 {
974     return hoveredCell_;
975 }
976 
selectedCells() const977 const CellSet & VAC::selectedCells() const
978 {
979     return selectedCells_;
980 }
981 
numSelectedCells() const982 int VAC::numSelectedCells() const
983 {
984     return selectedCells_.size();
985 }
986 
hoveredTransformWidgetId() const987 int VAC::hoveredTransformWidgetId() const
988 {
989     return transformTool_.hovered();
990 }
991 
992 // ----------------------  Save & Load -------------------------
993 
write(XmlStreamWriter & xml)994 void VAC::write(XmlStreamWriter & xml)
995 {
996     for(Cell * cell: zOrdering_)
997         cell->write(xml);
998 }
999 
clear()1000 void VAC::clear()
1001 {
1002     deleteAllCells();
1003     initNonCopyable();
1004     initCopyable();
1005 }
1006 
read(XmlStreamReader & xml)1007 void VAC::read(XmlStreamReader & xml)
1008 {
1009     clear();
1010 
1011     while (xml.readNextStartElement())
1012     {
1013         Cell * cell = 0;
1014 
1015         if(xml.name() == "vertex")
1016             cell = new KeyVertex(this, xml);
1017         else if(xml.name() == "edge")
1018             cell = new KeyEdge(this, xml);
1019         else if(xml.name() == "face")
1020             cell = new KeyFace(this, xml);
1021         else if(xml.name() == "inbetweenvertex")
1022             cell = new InbetweenVertex(this, xml);
1023         else if(xml.name() == "inbetweenedge")
1024             cell = new InbetweenEdge(this, xml);
1025         else if(xml.name() == "inbetweenface")
1026             cell = new InbetweenFace(this, xml);
1027 
1028         xml.skipCurrentElement(); // XXX this should be in "Cell(this, xml)"
1029 
1030         if(cell)
1031         {
1032             int id = cell->id();
1033             if(id > maxID_)
1034                 setMaxID_(id);
1035             cells_.insert(id, cell);
1036             zOrdering_.insertLast(cell);
1037         }
1038     }
1039 
1040     read2ndPass_();
1041 }
1042 
read2ndPass_()1043 void VAC::read2ndPass_()
1044 {
1045     // Convert temp IDs (int) to pointers (Cell*)
1046     foreach(Cell * cell, cells_)
1047         cell->read2ndPass();
1048 
1049     // Create star from boundary
1050     foreach(Cell * cell, cells_)
1051     {
1052         CellSet spatialBoundary = cell->spatialBoundary();
1053         foreach(Cell * bcell, spatialBoundary)
1054             cell->addMeToSpatialStarOf_(bcell);
1055 
1056         CellSet temporalBoundaryBefore = cell->beforeCells();
1057         foreach(Cell * bcell, temporalBoundaryBefore)
1058             cell->addMeToTemporalStarAfterOf_(bcell);
1059 
1060         CellSet temporalBoundaryAfter = cell->afterCells();
1061         foreach(Cell * bcell, temporalBoundaryAfter)
1062             cell->addMeToTemporalStarBeforeOf_(bcell);
1063     }
1064 
1065     // Clean geometry
1066     foreach(Cell * cell, cells_)
1067     {
1068         KeyEdge * kedge = cell->toKeyEdge();
1069         if(kedge)
1070         {
1071             kedge->correctGeometry();
1072         }
1073     }
1074 }
1075 
save_(QTextStream & out)1076 void VAC::save_(QTextStream & out)
1077 {
1078     // list of objects
1079     out << Save::newField("Cells");
1080     out << "\n" << Save::indent() << "[";
1081     Save::incrIndent();
1082     for(Cell * obj: zOrdering_)
1083     {
1084         out << Save::openCurlyBrackets();
1085         obj->save(out);
1086         out << Save::closeCurlyBrackets();
1087     }
1088     Save::decrIndent();
1089     out << "\n" << Save::indent() << "]";
1090 }
1091 
exportSVG_(Time t,QTextStream & out)1092 void VAC::exportSVG_(Time t, QTextStream & out)
1093 {
1094     // list of objects
1095     for(Cell * c: zOrdering_)
1096     {
1097         if(c->exists(t))
1098             c->exportSVG(t, out);
1099     }
1100 }
1101 
VAC(QTextStream & in)1102 VAC::VAC(QTextStream & in) :
1103     SceneObject()
1104 {
1105     clear();
1106 
1107     Field field;
1108 
1109     // list of objects
1110     // -- 1st pass: construct temp objects storing IDs instead of pointers
1111     in >> field; // Cells
1112     Read::skipBracket(in); // [
1113     while(Read::string(in) == "{")
1114     {
1115         Cell * cell = Cell::read1stPass(this, in);
1116         int id = cell->id();
1117         if(id > maxID_)
1118             setMaxID_(id);
1119         cells_.insert(id, cell);
1120         zOrdering_.insertLast(cell);
1121         Read::skipBracket(in); // }
1122     }
1123     // last read string == ]
1124 
1125     read2ndPass_();
1126 }
1127 
1128 
1129 
1130 // ------------------- Accessing elements ----------------------
1131 
getCell(int id)1132 Cell * VAC::getCell(int id)
1133 {
1134     if(cells_.contains(id))
1135         return cells_[id];
1136     else
1137         return 0;
1138 }
1139 
getKeyVertex(int id)1140 KeyVertex * VAC::getKeyVertex(int id)
1141 {
1142     Cell * object = getCell(id);
1143     if(object)
1144         return object->toKeyVertex();
1145     else
1146         return 0;
1147 }
1148 
getKeyEdge(int id)1149 KeyEdge * VAC::getKeyEdge(int id)
1150 {
1151     Cell * object = getCell(id);
1152     if(object)
1153         return object->toKeyEdge();
1154     else
1155         return 0;
1156 }
1157 
getKeyFace(int)1158 KeyFace * VAC::getKeyFace(int /*id*/)
1159 {
1160     return 0;
1161 }
1162 
getInbetweenVertex(int)1163 InbetweenVertex * VAC::getInbetweenVertex(int /*id*/)
1164 {
1165     return 0;
1166 }
1167 
getInbetweenEdge(int)1168 InbetweenEdge * VAC::getInbetweenEdge(int /*id*/)
1169 {
1170     return 0;
1171 }
1172 
getInbetweenFace(int)1173 InbetweenFace * VAC::getInbetweenFace(int /*id*/)
1174 {
1175     return 0;
1176 }
1177 
zOrdering() const1178 const ZOrderedCells & VAC::zOrdering() const
1179 {
1180     return zOrdering_;
1181 }
1182 
cells()1183 CellSet VAC::cells()
1184 {
1185     CellSet res;
1186     foreach(Cell * obj, cells_)
1187         res << obj;
1188     return res;
1189 }
1190 
cells(Time time)1191 CellSet VAC::cells(Time time)
1192 {
1193     CellSet res;
1194     foreach(Cell * c, cells_)
1195     {
1196         if(c->exists(time))
1197             res << c;
1198     }
1199     return res;
1200 }
1201 
vertices()1202 VertexCellList VAC::vertices()
1203 {
1204     VertexCellList res;
1205     foreach(Cell * o, cells_)
1206     {
1207         VertexCell *node = o->toVertexCell();
1208         if(node)
1209             res << node;
1210     }
1211     return res;
1212 }
instantVertices()1213 KeyVertexList VAC::instantVertices()
1214 {
1215     KeyVertexList res;
1216     foreach(Cell * o, cells_)
1217     {
1218         KeyVertex *node = o->toKeyVertex();
1219         if(node)
1220             res << node;
1221     }
1222     return res;
1223 }
1224 
edges()1225 EdgeCellList VAC::edges()
1226 {
1227     EdgeCellList res;
1228     foreach(Cell * o, cells_)
1229     {
1230         EdgeCell *edge = o->toEdgeCell();
1231         if(edge)
1232             res << edge;
1233     }
1234     return res;
1235 }
1236 
edges(Time time)1237 EdgeCellList VAC::edges(Time time)
1238 {
1239     EdgeCellList res;
1240     foreach(Cell * o, cells_)
1241     {
1242         EdgeCell *edge = o->toEdgeCell();
1243         if(edge && edge->exists(time))
1244             res << edge;
1245     }
1246     return res;
1247 }
1248 
faces()1249 FaceCellList VAC::faces()
1250 {
1251     FaceCellList res;
1252     foreach(Cell * o, cells_)
1253     {
1254         FaceCell *face = o->toFaceCell();
1255         if(face)
1256             res << face;
1257     }
1258     return res;
1259 }
1260 
1261 
instantEdges()1262 KeyEdgeList VAC::instantEdges()
1263 {
1264     KeyEdgeList res;
1265     foreach(Cell * o, cells_)
1266     {
1267         KeyEdge * iedge = o->toKeyEdge();
1268         if(iedge)
1269             res << iedge;
1270     }
1271     return res;
1272 }
1273 
instantVertices(Time time)1274 KeyVertexList VAC::instantVertices(Time time)
1275 {
1276     KeyVertexList res;
1277     foreach(Cell * o, cells_)
1278     {
1279         KeyVertex *node = o->toKeyVertex();
1280         if(node && node->exists(time))
1281             res << node;
1282     }
1283     return res;
1284 }
1285 
instantEdges(Time time)1286 KeyEdgeList VAC::instantEdges(Time time)
1287 {
1288     KeyEdgeList res;
1289     foreach(Cell * o, cells_)
1290     {
1291         KeyEdge * iedge = o->toKeyEdge();
1292         if(iedge && iedge->exists(time))
1293             res << iedge;
1294     }
1295     return res;
1296 }
1297 
1298 // ----------------------- Managing IDs ------------------------
1299 
getAvailableID()1300 int VAC::getAvailableID()
1301 {
1302     setMaxID_(maxID_+1);
1303     return maxID_;
1304 }
1305 
insertCell_(Cell * cell)1306 void VAC::insertCell_(Cell * cell)
1307 {
1308     int id = getAvailableID();
1309     cell->id_ = id;
1310     cell->vac_ = this;
1311     cells_.insert(id, cell);
1312     zOrdering_.insertCell(cell);
1313 }
1314 
insertCellLast_(Cell * cell)1315 void VAC::insertCellLast_(Cell * cell)
1316 {
1317     int id = getAvailableID();
1318     cell->id_ = id;
1319     cell->vac_ = this;
1320     cells_.insert(id, cell);
1321     zOrdering_.insertLast(cell);
1322 }
1323 
removeCell_(Cell * cell)1324 void VAC::removeCell_(Cell * cell)
1325 {
1326     if(cell)
1327     {
1328         cells_.remove(cell->id());
1329         zOrdering_.removeCell(cell);
1330         removeFromSelection(cell,false);
1331         if(cell->isSelected())
1332         {
1333             removeFromSelection(cell,false);
1334         }
1335         if(cell->isHovered())
1336         {
1337             cell->setHovered(false);
1338             hoveredCell_ = 0;
1339         }
1340         if(cell == sculptedEdge_)
1341             sculptedEdge_ = 0;
1342 
1343         if(cell == hoveredFaceOnMousePress_)
1344             hoveredFaceOnMousePress_ = 0;
1345         if(cell == hoveredFaceOnMouseRelease_)
1346             hoveredFaceOnMouseRelease_= 0;
1347         hoveredFacesOnMouseMove_.remove(cell->toKeyFace());
1348         facesToConsiderForCutting_.remove(cell->toKeyFace());
1349     }
1350 }
1351 
1352 
smartDelete_(const CellSet & cellsToDelete)1353 void VAC::smartDelete_(const CellSet & cellsToDelete)
1354 {
1355     // Note: we know that deleting or simplifying a cell of dimension N
1356     // leave untouched any cell of dimension <= N.
1357 
1358     // For instance:
1359     //  - Deleting a face leaves untouched other faces, edges and vertices
1360     //  - Simplifying a face does nothing
1361     //  - Deleting an edge also deletes incident faces, but leaves untouched
1362     //    other edges and vertices
1363     //  - Simplifying an edge may merge incident faces (hence, delete them
1364     //    and create a new one) but leaves untouched other edges and vertices
1365     //  - Deleting a vertex may delete faces and edges, but leaves untouched
1366     //    other vertices
1367     //  - Simplifying a vertex may merge incident faces/edges, but leaves
1368     //    untouched other vertices
1369 
1370     // Hence, by first considering faces, then edges, then vertices, we don't
1371     // have to recompute sets
1372     KeyFaceSet facesToDelete = cellsToDelete;
1373     KeyEdgeSet edgesToDelete= cellsToDelete;
1374     KeyVertexSet verticesToDelete = cellsToDelete;
1375 
1376     foreach(KeyFace * iface, facesToDelete)
1377         smartDeleteCell(iface);
1378 
1379     foreach(KeyEdge * iedge, edgesToDelete)
1380         smartDeleteCell(iedge);
1381 
1382     foreach(KeyVertex * ivertex, verticesToDelete)
1383         smartDeleteCell(ivertex);
1384 }
1385 
smartDelete()1386 void VAC::smartDelete()
1387 {
1388     if(numSelectedCells() == 0)
1389         return;
1390 
1391     // Prepare automatic cleaning of vertices
1392     //CellSet cellsToDelete = selectedCells();
1393     //CellSet closureOfCellsToDelete = Algorithms::closure(cellsToDelete);
1394     //KeyVertexSet verticesToDelete = cellsToDelete;
1395     //KeyVertexSet verticesToConsiderForCleaning = closureOfCellsToDelete;
1396     //verticesToConsiderForCleaning.subtract(verticesToDelete);
1397     // => doesn't work, because "closure" is not enough
1398     //       v1 ---------- v2
1399     //  then deleting v1 should also delete v2 since e is deleted as a side effect
1400 
1401     smartDelete_(selectedCells());
1402 
1403     // Automatic cleaning of vertices
1404     // naive method for now, not efficient but works
1405     if(global()->deleteIsolatedVertices())
1406     {
1407         foreach(KeyVertex * keyVertex, instantVertices())
1408         {
1409             if(keyVertex->star().isEmpty())
1410                 deleteCell(keyVertex);
1411         }
1412     }
1413 
1414     emit needUpdatePicking();
1415     emit changed();
1416     emit checkpoint();
1417 }
1418 
deleteSelectedCells()1419 void VAC::deleteSelectedCells()
1420 {
1421     if(numSelectedCells() == 0)
1422         return;
1423 
1424     while(numSelectedCells() != 0)
1425     {
1426         Cell * obj = *selectedCells().begin();
1427         deleteCell(obj);
1428     }
1429 
1430     // Automatic cleaning of vertices
1431     // naive method for now, not efficient but works
1432     if(global()->deleteIsolatedVertices())
1433     {
1434         foreach(KeyVertex * keyVertex, instantVertices())
1435         {
1436             if(keyVertex->star().isEmpty())
1437                 deleteCell(keyVertex);
1438         }
1439     }
1440 
1441     emit needUpdatePicking();
1442     emit changed();
1443     emit checkpoint();
1444 }
1445 
deleteCells(const QSet<int> & cellIds)1446 void VAC::deleteCells(const QSet<int>  & cellIds)
1447 {
1448     foreach(int id, cellIds)
1449     {
1450         // Get cell corresponding to ID
1451         Cell * cell = getCell(id);
1452 
1453         // Note: cell might be NULL, as it might have been recursively deleted
1454         //       that's why this method has to be implemented with IDs, as pointers
1455         //       can become invalid if implemented directly with QSet<Cell*>
1456         if(cell)
1457             deleteCell(cell);
1458     }
1459 }
1460 
deleteCells(const CellSet & cells)1461 void VAC::deleteCells(const CellSet & cells)
1462 {
1463     QSet<int> cellIds;
1464     foreach(Cell * c, cells)
1465         cellIds << c->id();
1466     deleteCells(cellIds);
1467 }
1468 
deleteCell(Cell * cell)1469 void VAC::deleteCell(Cell * cell)
1470 {
1471     // Recusrively delete star cells first (complex remains valid upon return)
1472     cell->destroyStar();
1473 
1474     // Inform observers of the upcoming deletion
1475     foreach(CellObserver * observer, cell->observers_)
1476         observer->observedCellDeleted(cell);
1477 
1478     // Remove the cell from the star of its boundary
1479     cell->informBoundaryImGettingDestroyed();
1480 
1481     // Remove the cell from the various cell sets, e.g.:
1482     //  - id to pointer map
1483     //  - depth ordering
1484     //  - selection
1485     //  - ...
1486     removeCell_(cell);
1487 
1488     // Finally, now that no pointers point to the cell, release memory
1489     delete cell;
1490 }
1491 
1492 // Smart deletion and simplification
atomicSimplifyAtCell(Cell * cell)1493 bool VAC::atomicSimplifyAtCell(Cell * cell)
1494 {
1495     KeyVertex * ivertex = cell->toKeyVertex();
1496     KeyEdge * iedge = cell->toKeyEdge();
1497     if(ivertex)
1498     {
1499         return uncut_(ivertex);
1500     }
1501     else if(iedge)
1502     {
1503         return uncut_(iedge);
1504     }
1505     else
1506     {
1507         return false;
1508     }
1509 }
1510 
smartDeleteCell(Cell * cell)1511 void VAC::smartDeleteCell(Cell * cell)
1512 {
1513     bool success = atomicSimplifyAtCell(cell);
1514 
1515     if(success)
1516     {
1517         // Yay!
1518     }
1519     else
1520     {
1521         // Try to smart simplify direct star first
1522         // for now, since I do not have a directStar()
1523         // abstract method, I do things more manually.
1524         CellSet star = cell->star();
1525 
1526         KeyEdgeSet starEdges = star;
1527         if(!starEdges.isEmpty())
1528         {
1529             // Great, this means starEdges is the direct star of cell
1530             // Atomic simplify all of them
1531             foreach(KeyEdge * iedge, starEdges)
1532             {
1533                 atomicSimplifyAtCell(iedge);
1534             }
1535 
1536             // Ok, so maybe now it is possible to simplify at this cell
1537             bool newTrySuccess = atomicSimplifyAtCell(cell);
1538             if(newTrySuccess)
1539             {
1540                 // Yay!
1541             }
1542             else
1543             {
1544                 // There's definitely nothing we can't do about this cell
1545                 // the 1-skeleton of its extendedStar is non-manifold, and
1546                 // the 2-skeleton of its extendedStar is non-manifold either.
1547                 deleteCell(cell);
1548             }
1549         }
1550         else
1551         {
1552             // This means starFaces is the direct star of cell
1553             // Great: since we do not consider volumes, there is
1554             // no way faces can be simplified
1555             // Hence, we know for sure
1556             // Atomic simplify all of them atomicSimplifyAtCell(cell) == false.
1557             //
1558             // So there's nothing we can do about this cell
1559             deleteCell(cell);
1560         }
1561     }
1562 }
1563 
deleteAllCells()1564 void VAC::deleteAllCells()
1565 {
1566     while(!cells_.isEmpty())
1567     {
1568         Cell * obj = *cells_.begin();
1569         deleteCell(obj);
1570     }
1571     setMaxID_(-1);
1572 }
1573 
setMaxID_(int maxID)1574 void VAC::setMaxID_(int maxID)
1575 {
1576     maxID_ = maxID;
1577     transformTool_.setIdOffset(maxID_+1);
1578 }
1579 
newKeyVertex(Time time,const Eigen::Vector2d & pos)1580 KeyVertex* VAC::newKeyVertex(Time time, const Eigen::Vector2d & pos)
1581 {
1582     KeyVertex * node = new KeyVertex(this, time, pos);
1583     insertCell_(node);
1584     return node;
1585 }
1586 
newKeyVertex(Time time,const EdgeSample & sample)1587 KeyVertex* VAC::newKeyVertex(Time time, const EdgeSample& sample)
1588 {
1589     KeyVertex * node = new KeyVertex(this, time, sample);
1590     insertCell_(node);
1591     return node;
1592 }
1593 
newKeyEdge(Time time,KeyVertex * left,KeyVertex * right,EdgeGeometry * geometry,double width)1594 KeyEdge * VAC::newKeyEdge(Time time,
1595                           KeyVertex * left,
1596                           KeyVertex * right,
1597                           EdgeGeometry * geometry, double width)
1598 {
1599     if(geometry == 0)
1600     {
1601         // Create straight invisible edge
1602         EdgeSample startSample(left->pos()[0], left->pos()[1], width);
1603         EdgeSample endSample(right->pos()[0], right->pos()[1], width);
1604         SculptCurve::Curve<EdgeSample> curve(startSample, endSample);
1605         geometry = new LinearSpline(curve);
1606     }
1607 
1608     KeyEdge * edge = new KeyEdge(this, time, left, right, geometry);
1609     insertCell_(edge);
1610     return edge;
1611 }
1612 
newKeyEdge(Time time,EdgeGeometry * geometry)1613 KeyEdge * VAC::newKeyEdge(Time time,
1614                           EdgeGeometry * geometry)
1615 {
1616     if(geometry == 0)
1617         geometry = new EdgeGeometry();
1618 
1619     geometry->makeLoop();
1620     KeyEdge * edge = new KeyEdge(this, time, geometry);
1621     insertCell_(edge);
1622     return edge;
1623 }
1624 
newInbetweenVertex(KeyVertex * before,KeyVertex * after)1625 InbetweenVertex * VAC::newInbetweenVertex(
1626         KeyVertex * before,
1627         KeyVertex * after)
1628 {
1629     InbetweenVertex * svertex = new InbetweenVertex(this, before, after);
1630     insertCell_(svertex);
1631     return svertex;
1632 }
1633 
newInbetweenEdge(const Path & beforePath,const Path & afterPath,const AnimatedVertex & startAnimatedVertex,const AnimatedVertex & endAnimatedVertex)1634 InbetweenEdge * VAC::newInbetweenEdge(
1635         const Path & beforePath,
1636         const Path & afterPath,
1637         const AnimatedVertex & startAnimatedVertex,
1638         const AnimatedVertex & endAnimatedVertex)
1639 {
1640     InbetweenEdge * sedge = new InbetweenEdge(this, beforePath, afterPath, startAnimatedVertex, endAnimatedVertex);
1641     insertCell_(sedge);
1642     return sedge;
1643 }
newInbetweenEdge(const Cycle & beforeCycle,const Cycle & afterCycle)1644 InbetweenEdge * VAC::newInbetweenEdge(
1645         const Cycle & beforeCycle,
1646         const Cycle & afterCycle)
1647 {
1648     InbetweenEdge * sedge = new InbetweenEdge(this, beforeCycle, afterCycle);
1649     insertCell_(sedge);
1650     return sedge;
1651 }
1652 
newKeyFace(const Time & t)1653 KeyFace * VAC::newKeyFace(const Time & t)
1654 {
1655     KeyFace * face = new KeyFace(this, t);
1656     insertCell_(face);
1657     return face;
1658 }
1659 
newKeyFace(const Cycle & cycle)1660 KeyFace * VAC::newKeyFace(const Cycle & cycle)
1661 {
1662     KeyFace * face = new KeyFace(this, cycle);
1663     insertCell_(face);
1664     return face;
1665 }
1666 
newKeyFace(const QList<Cycle> & cycles)1667 KeyFace * VAC::newKeyFace(const QList<Cycle> & cycles)
1668 {
1669     KeyFace * face = new KeyFace(this, cycles);
1670     insertCell_(face);
1671     return face;
1672 }
newInbetweenFace(const QList<AnimatedCycle> & cycles,const QSet<KeyFace * > & beforeFaces,const QSet<KeyFace * > & afterFaces)1673 InbetweenFace * VAC::newInbetweenFace(const QList<AnimatedCycle> & cycles,
1674                                       const QSet<KeyFace*> & beforeFaces,
1675                                       const QSet<KeyFace*> & afterFaces)
1676 {
1677     InbetweenFace * sface = new InbetweenFace(this, cycles, beforeFaces, afterFaces);
1678     insertCell_(sface);
1679     return sface;
1680 }
1681 
1682 // ------------- User action: rectangle of selection -------------
1683 
beginRectangleOfSelection(double x,double y,Time time)1684 void VAC::beginRectangleOfSelection(double x, double y, Time time)
1685 {
1686     timeInteractivity_ = time;
1687     rectangleOfSelectionStartX_ = x;
1688     rectangleOfSelectionStartY_ = y;
1689     rectangleOfSelectionEndX_ = x;
1690     rectangleOfSelectionEndY_ = y;
1691     drawRectangleOfSelection_ = true;
1692     rectangleOfSelectionSelectedBefore_ = selectedCells();
1693 }
1694 
continueRectangleOfSelection(double x,double y)1695 void VAC::continueRectangleOfSelection(double x, double y)
1696 {
1697     // Set raw data
1698     rectangleOfSelectionEndX_ = x;
1699     rectangleOfSelectionEndY_ = y;
1700 
1701     // Express rectangle of selection as bounding box
1702     const BoundingBox bb(rectangleOfSelectionStartX_, rectangleOfSelectionEndX_,
1703                          rectangleOfSelectionStartY_, rectangleOfSelectionEndY_);
1704 
1705     // Compute which cells intersect with bounding box
1706     cellsInRectangleOfSelection_.clear();
1707     for(Cell * c: zOrdering_)
1708     {
1709         if (c->isPickable(timeInteractivity_) &&
1710             c->intersects(timeInteractivity_, bb))
1711         {
1712             cellsInRectangleOfSelection_ << c;
1713         }
1714     }
1715 
1716     // Set result
1717     setSelectedCellsFromRectangleOfSelection();
1718 }
1719 
setSelectedCellsFromRectangleOfSelection()1720 void VAC::setSelectedCellsFromRectangleOfSelection()
1721 {
1722     // Get keyboard modifiers to know what to do
1723     Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
1724     setSelectedCellsFromRectangleOfSelection(modifiers);
1725 }
1726 
setSelectedCellsFromRectangleOfSelection(Qt::KeyboardModifiers modifiers)1727 void VAC::setSelectedCellsFromRectangleOfSelection(Qt::KeyboardModifiers modifiers)
1728 {
1729     if(modifiers == Qt::NoModifier)
1730     {
1731         // Set selection
1732         setSelectedCells(cellsInRectangleOfSelection_, false);
1733     }
1734     else if(modifiers & Qt::ShiftModifier)
1735     {
1736         if(modifiers & Qt::AltModifier)
1737         {
1738             // Intersect selection
1739             CellSet newSelectedSet = rectangleOfSelectionSelectedBefore_;
1740             newSelectedSet.intersect(cellsInRectangleOfSelection_);
1741             setSelectedCells(newSelectedSet, false);
1742         }
1743         else
1744         {
1745             // Add to selection
1746             CellSet newSelectedSet = rectangleOfSelectionSelectedBefore_;
1747             newSelectedSet.unite(cellsInRectangleOfSelection_);
1748             setSelectedCells(newSelectedSet, false);
1749         }
1750     }
1751     else if(modifiers & Qt::AltModifier)
1752     {
1753         // Remove from selection
1754         CellSet newSelectedSet = rectangleOfSelectionSelectedBefore_;
1755         newSelectedSet.subtract(cellsInRectangleOfSelection_);
1756         setSelectedCells(newSelectedSet, false);
1757     }
1758 }
1759 
endRectangleOfSelection()1760 void VAC::endRectangleOfSelection()
1761 {
1762     drawRectangleOfSelection_ = false;
1763 }
1764 
1765 // ------------- User action: drawing a new stroke -------------
1766 
beginSketchEdge(double x,double y,double w,Time time)1767 void VAC::beginSketchEdge(double x, double y, double w, Time time)
1768 {
1769     timeInteractivity_ = time;
1770     sketchedEdge_ = new LinearSpline(ds_);
1771     sketchedEdge_->beginSketch(EdgeSample(x,y,w));
1772     hoveredFaceOnMousePress_ = 0;
1773     hoveredFaceOnMouseRelease_ = 0;
1774     hoveredFacesOnMouseMove_.clear();
1775     if(hoveredCell_)
1776     {
1777         InbetweenFace * sface = hoveredCell_->toInbetweenFace();
1778         if(sface && global()->planarMapMode())
1779             hoveredCell_ = keyframe_(sface, timeInteractivity_);
1780         hoveredFaceOnMousePress_ = hoveredCell_->toKeyFace();
1781     }
1782 }
1783 
continueSketchEdge(double x,double y,double w)1784 void VAC::continueSketchEdge(double x, double y, double w)
1785 {
1786     if(sketchedEdge_)
1787     {
1788         sketchedEdge_->continueSketch(EdgeSample(x,y,w));
1789         if(hoveredCell_)
1790         {
1791             InbetweenFace * sface = hoveredCell_->toInbetweenFace();
1792             if(sface && global()->planarMapMode())
1793                 hoveredCell_ = keyframe_(sface, timeInteractivity_);
1794 
1795             KeyFace * hoveredFace = hoveredCell_->toKeyFace();
1796             if(hoveredFace)
1797                 hoveredFacesOnMouseMove_.insert(hoveredFace);
1798         }
1799 
1800 
1801     }
1802 }
1803 
endSketchEdge()1804 void VAC::endSketchEdge()
1805 {
1806     if(sketchedEdge_)
1807     {
1808         InbetweenFace * sface = nullptr;
1809         if (hoveredCell_)
1810             sface = hoveredCell_ ->toInbetweenFace();
1811         if(sface && global()->planarMapMode())
1812             hoveredCell_ = keyframe_(sface, timeInteractivity_);
1813 
1814         if(hoveredCell_)
1815             hoveredFaceOnMouseRelease_ = hoveredCell_->toKeyFace();
1816 
1817 
1818         sketchedEdge_->endSketch();
1819 
1820         sketchedEdge_->resample(); // not sure if necessary
1821 
1822         facesToConsiderForCutting_ = hoveredFacesOnMouseMove_;
1823         if(hoveredFaceOnMousePress_)
1824             facesToConsiderForCutting_.insert(hoveredFaceOnMousePress_);
1825         if(hoveredFaceOnMouseRelease_)
1826             facesToConsiderForCutting_.insert(hoveredFaceOnMouseRelease_);
1827         insertSketchedEdgeInVAC();
1828 
1829         delete sketchedEdge_;
1830         sketchedEdge_ = 0;
1831 
1832 
1833         //emit changed();
1834         emit checkpoint();
1835     }
1836 }
1837 
beginCutFace(double x,double y,double w,KeyVertex * startVertex)1838 void VAC::beginCutFace(double x, double y, double w, KeyVertex * startVertex)
1839 {
1840     cut_startVertex_ = startVertex;
1841 
1842     if(cut_startVertex_)
1843     {
1844         timeInteractivity_ = cut_startVertex_->time();
1845         const bool invisibleCut = true;
1846         if(invisibleCut)
1847             w = 3.0;
1848 
1849         sketchedEdge_ = new LinearSpline(ds_);
1850         sketchedEdge_->beginSketch(EdgeSample(x,y,w));
1851 
1852         //emit changed();
1853     }
1854 
1855 }
1856 
continueCutFace(double x,double y,double w)1857 void VAC::continueCutFace(double x, double y, double w)
1858 {
1859     if(sketchedEdge_)
1860     {
1861         const bool invisibleCut = true;
1862         if(invisibleCut)
1863             w = 3.0;
1864 
1865         sketchedEdge_->continueSketch(EdgeSample(x,y,w));
1866         //emit changed();
1867     }
1868 }
1869 
endCutFace(KeyVertex * endVertex)1870 void VAC::endCutFace(KeyVertex * endVertex)
1871 {
1872     if(sketchedEdge_)
1873     {
1874         bool hasBeenCut = false;
1875 
1876         sketchedEdge_->endSketch();
1877         sketchedEdge_->resample(); // not sure if necessary
1878 
1879         if(endVertex)
1880         {
1881             // convenient alias
1882             KeyVertex * startVertex = cut_startVertex_;
1883 
1884             // find a face to cut
1885             KeyFaceSet startFaces = startVertex->spatialStar();
1886             KeyFaceSet endFaces = endVertex->spatialStar();
1887             KeyFaceSet faces = startFaces;
1888             faces.intersect(endFaces);
1889 
1890             if(!faces.isEmpty())
1891             {
1892                 // For now, just use the first face
1893                 KeyFace * face = *faces.begin();
1894 
1895                 // Create the new edge
1896                 EdgeGeometry * geometry = new LinearSpline(sketchedEdge_->curve());
1897                 KeyEdge * iedge = newKeyEdge(timeInteractivity_, startVertex, endVertex, geometry);
1898                 const bool invisibleCut = true;
1899                 if(invisibleCut)
1900                     iedge->setWidth(0);
1901 
1902                 // Cut the face by the new edge
1903                 hasBeenCut = cutFace_(face,iedge);
1904 
1905                 if(!hasBeenCut)
1906                     deleteCell(iedge);
1907             }
1908 
1909         }
1910 
1911         delete sketchedEdge_;
1912         sketchedEdge_ = 0;
1913 
1914         if(hasBeenCut)
1915         {
1916             //emit changed();
1917             emit checkpoint();
1918         }
1919     }
1920 }
1921 
cutFace_(KeyFace * face,KeyEdge * edge,CutFaceFeedback * feedback)1922 bool VAC::cutFace_(KeyFace * face, KeyEdge * edge, CutFaceFeedback * feedback)
1923 {
1924     // assumes edge is not a loop
1925     // assumes edge->start() and edge->end() belong to face boundary
1926 
1927     // Get involved vertices
1928     KeyVertex * startVertex = edge->startVertex();
1929     KeyVertex * endVertex = edge->endVertex();
1930 
1931     // Find a suitable use for vStart and vEnd.
1932     // If vStart has several suitable uses, it chooses the last one
1933     // If vEnd has several suitable uses, it chooses the last one
1934     // Better heuristics must use geometry to capture user's intent
1935     int iStart = -1;
1936     int iEnd = -1;
1937     int jStart = -1;
1938     int jEnd = -1;
1939     for(int i=0; i<face->cycles_.size(); ++i)
1940     {
1941         // convenient alias
1942         Cycle & cycle = face->cycles_[i];
1943 
1944         switch(cycle.type())
1945         {
1946         case Cycle::SingleVertex:
1947             if(cycle.singleVertex() == startVertex)
1948             {
1949                 iStart = i;
1950                 jStart = 0;
1951             }
1952             if(cycle.singleVertex() == endVertex)
1953             {
1954                 iEnd = i;
1955                 jEnd = 0;
1956             }
1957             break;
1958 
1959         case Cycle::ClosedHalfedge:
1960             // nothing to do, just ignore it
1961             break;
1962 
1963         case Cycle::OpenHalfedgeList:
1964             for(int j=0; j<cycle.size(); ++j)
1965             {
1966                 KeyHalfedge he = cycle.halfedges_[j];
1967                 KeyVertex * v = he.startVertex();
1968                 if(v == startVertex)
1969                 {
1970                     iStart = i;
1971                     jStart = j;
1972                 }
1973                 if(v == endVertex)
1974                 {
1975                     iEnd = i;
1976                     jEnd = j;
1977                 }
1978             }
1979             break;
1980 
1981         case Cycle::Invalid:
1982             break;
1983         }
1984     }
1985 
1986     // Makes sure they have been found
1987     if(iStart == -1 || iEnd == -1)
1988     {
1989         qDebug() << "CutFace: abort, endVertices of edge not used in face";
1990         return false;
1991     }
1992 
1993     // Case where they belong to the same cycle (can be a Steiner cycle)
1994     if(iStart == iEnd)
1995     {
1996         // Convenient alias to the cycle to cut
1997         int i = iStart; // (= iEnd too)
1998         Cycle & oldCycle = face->cycles_[i];
1999         int n = oldCycle.size();
2000 
2001         // Cut the cycle in two:
2002         //   * Cycle 1 goes from end to start
2003         //   * Cycle 2 goes from start to end
2004         Cycle newCycle1;
2005         Cycle newCycle2;
2006 
2007         // Special case where the uses chosen for vStart and vEnd are equal
2008         if(jEnd == jStart)
2009         {
2010             // Special case in special case where it is a Steiner vertex
2011             if(oldCycle.type() == Cycle::SingleVertex)
2012             {
2013                 // The two cycles to use are:
2014                 //   Cycle 1 = [ ]
2015                 //   Cycle 2 = [ ]
2016                 //
2017                 // Yet invalid, but will become valid by adding (e,true) or/and (e,false)
2018             }
2019             else
2020             {
2021                 // The two cycles to use are:
2022                 //   Cycle 1 = [ oldCycle ]
2023                 //   Cycle 2 = [ ]
2024                 //
2025                 // Cycle 2 Yet invalid, but will become valid by adding (e,true) or/and (e,false)
2026                 newCycle1.halfedges_ << oldCycle[jEnd];  // These two lines (first iteration of the loop) are necessary
2027                 jEnd = (jEnd+1) % n;                     // otherwise since jEnd == jStart, the loop would stop instantly
2028                 for(int j = jEnd; j != jStart; j = (j+1) % n)
2029                     newCycle1.halfedges_ << oldCycle[j];
2030             }
2031         }
2032         // Normal case, where the two uses for vStart and vEnd are different
2033         else
2034         {
2035             // Old Cycle = [ h0 ... h(jStart-1) | h(jStart) ... h(jEnd-1) | h(jEnd) ... h(n-1) ]
2036             // Cycle 1   = [ h(jEnd) ... h(n-1) | h0 ... h(jStart-1) ]
2037             // Cycle 2   = [ h(jStart) ... h(jEnd-1) ]
2038 
2039             for(int j = jEnd; j != jStart; j = (j+1) % n )
2040                 newCycle1.halfedges_ << oldCycle[j];
2041 
2042             for(int j = jStart; j != jEnd; j = (j+1) % n )
2043                 newCycle2.halfedges_ << oldCycle[j];
2044         }
2045 
2046         // Heuristic to decide between doing a Mobius cut or a normal cut
2047         bool moebiusCut = DevSettings::getBool("mobius cut");
2048         if(moebiusCut)
2049         {
2050             // New Cycle = [ Cycle1 | (e,true) | Cycle2.opposite() | (e,true) ]
2051             Cycle newCycle;
2052 
2053             // Append Cycle1
2054             for(int j = 0; j < newCycle1.size(); ++j)
2055                 newCycle.halfedges_ << newCycle1[j];
2056 
2057             // Append (e,true)
2058             newCycle.halfedges_ << KeyHalfedge(edge, true);
2059 
2060             // Append Cycle2.opposite()
2061             for(int j = newCycle2.size()-1; j >= 0 ; --j)
2062                 newCycle.halfedges_ << newCycle2[j].opposite();
2063 
2064             // Append (e,true)
2065             newCycle.halfedges_ << KeyHalfedge(edge, true);
2066 
2067             // Compute new cycles of f
2068             face->cycles_[i] = newCycle;
2069             face->addMeToSpatialStarOf_(edge);
2070             face->processGeometryChanged_();
2071         }
2072         else
2073         {
2074             // Cycle 1 <- [ Cycle1 | (e,true) ]
2075             newCycle1.halfedges_ << KeyHalfedge(edge, true);
2076 
2077             // Cycle 2 <- [ Cycle2 | (e,false) ]
2078             newCycle2.halfedges_ << KeyHalfedge(edge, false);
2079 
2080             // Create the new faces
2081             KeyFace * f1 = newKeyFace(newCycle1);
2082             KeyFace * f2 = newKeyFace(newCycle2);
2083             if(feedback)
2084             {
2085                 feedback->newFaces.insert(f1);
2086                 feedback->newFaces.insert(f2);
2087             }
2088             // Transfer other cycles to either f1 or f2 using a heuristic
2089             PreviewKeyFace f1Preview(newCycle1);
2090             for(int k=0; k<face->cycles_.size(); ++k)
2091             {
2092                 if(k != i)
2093                 {
2094                     if(isCycleContainedInFace(face->cycles_[k],f1Preview))
2095                         f1->addCycle(face->cycles_[k]);
2096                     else
2097                         f2->addCycle(face->cycles_[k]);
2098                 }
2099             }
2100 
2101             // Set their color to be the same of the cut face
2102             QColor color = face->color();
2103             f1->setColor(color);
2104             f2->setColor(color);
2105 
2106             //Set depth-ordering of new faces to be just below the old face
2107             zOrdering_.moveBelow(f1,face);
2108             zOrdering_.moveBelow(f2,face);
2109 
2110             // Update star
2111             InbetweenFaceSet sfacesbefore = face->temporalStarBefore();
2112             foreach(InbetweenFace * sface, sfacesbefore)
2113             {
2114                 sface->removeAfterFace(face);
2115                 sface->addAfterFace(f1);
2116                 sface->addAfterFace(f2);
2117             }
2118             InbetweenFaceSet sfacesafter = face->temporalStarAfter();
2119             foreach(InbetweenFace * sface, sfacesafter)
2120             {
2121                 sface->removeBeforeFace(face);
2122                 sface->addBeforeFace(f1);
2123                 sface->addBeforeFace(f2);
2124             }
2125 
2126             // Delete old face
2127             deleteCell(face);
2128             if(feedback)
2129             {
2130                 feedback->deletedFaces.insert(face);
2131             }
2132         }
2133     }
2134     // case where they belong to different cycles
2135     else
2136     {
2137         // Compute the new cycles
2138         int nStart = face->cycles_[iStart].size();
2139         int nEnd = face->cycles_[iEnd].size();
2140         QList<Cycle> newCycles;
2141 
2142         // Joined cycle =     [ | (e,true) |      oldCycleEnd      | (e,false) | oldCycleStart | ]
2143         //                    vStart      vEnd                    vEnd       vStart          vStart
2144         //                 or [ | (e,true) | oldCycleEnd.reverse() | (e,false) | oldCycleStart | ]
2145         Cycle joinedCycle;
2146 
2147         // Append (e,true)
2148         joinedCycle.halfedges_ << KeyHalfedge(edge, true);
2149 
2150         // Heuristic to reverse or not
2151         bool reverseOldCycleEnd = true;
2152         int turningNumberStart = face->cycles_[iStart].turningNumber();
2153         int turningNumberEnd = face->cycles_[iEnd].turningNumber();
2154         qDebug() << turningNumberStart << turningNumberEnd;
2155         if( turningNumberStart * turningNumberEnd < 0)
2156             reverseOldCycleEnd = false;
2157 
2158         // Append oldCycleEnd or oldCycleEnd.reverse()
2159         if(reverseOldCycleEnd)
2160         {
2161             for(int j = jEnd-1; j >= 0; --j)
2162                 joinedCycle.halfedges_ << face->cycles_[iEnd][j].opposite();
2163             for(int j = nEnd-1; j >= jEnd; --j)
2164                 joinedCycle.halfedges_ << face->cycles_[iEnd][j].opposite();
2165         }
2166         else
2167         {
2168             for(int j = jEnd; j != nEnd; ++j)
2169                 joinedCycle.halfedges_ << face->cycles_[iEnd][j];
2170             for(int j = 0; j != jEnd; ++j)
2171                 joinedCycle.halfedges_ << face->cycles_[iEnd][j];
2172         }
2173 
2174         // Append (e,false)
2175         joinedCycle.halfedges_ << KeyHalfedge(edge, false);
2176 
2177         // Append oldCycleStart
2178         for(int j = jStart; j != nStart; ++j)
2179             joinedCycle.halfedges_ << face->cycles_[iStart][j];
2180         for(int j = 0; j != jStart; ++j)
2181             joinedCycle.halfedges_ << face->cycles_[iStart][j];
2182 
2183         // Add joined cycle to face cycles
2184         newCycles << joinedCycle;
2185 
2186         // Add other cycles to face cycles
2187         for(int i=0; i<face->cycles_.size(); ++i)
2188         {
2189             if(i != iStart && i != iEnd)
2190                 newCycles << face->cycles_[i];
2191         }
2192 
2193         // Set these new cycles to be the face boundary
2194         face->setCycles(newCycles);
2195         face->addMeToSpatialStarOf_(edge);
2196     }
2197 
2198     return true;
2199 }
2200 
cutFaceAtVertex_(KeyFace * face,double x,double y)2201 KeyVertex * VAC::cutFaceAtVertex_(KeyFace * face, double x, double y)
2202 {
2203     KeyVertex * res = newKeyVertex(face->time());
2204     res->setPos(Eigen::Vector2d(x,y));
2205     Cycle newCycle(res);
2206     face->addCycle(newCycle);
2207     return res;
2208 }
2209 
cutEdgeAtVertex_(KeyEdge * edge,double s)2210 KeyVertex * VAC::cutEdgeAtVertex_(KeyEdge * edge, double s)
2211 {
2212     double l = edge->geometry()->length();
2213     double eps = 1e-2;
2214     if(edge->isClosed())
2215     {
2216         std::vector<double> splitValues;
2217         splitValues.push_back(s);
2218         splitValues.push_back(s+l);
2219         SplitInfo info = cutEdgeAtVertices_(edge, splitValues);
2220         return info.newVertices[0];
2221     }
2222     else
2223     {
2224         if(eps<s && s<l-eps)
2225         {
2226             std::vector<double> splitValues;
2227             splitValues.push_back(0);
2228             splitValues.push_back(s);
2229             splitValues.push_back(l);
2230             SplitInfo info = cutEdgeAtVertices_(edge, splitValues);
2231             return info.newVertices[0];
2232         }
2233         else
2234         {
2235             return 0;
2236         }
2237     }
2238 }
2239 
cutEdgeAtVertices_(KeyEdge * edgeToSplit,const std::vector<double> & splitValues)2240 VAC::SplitInfo VAC::cutEdgeAtVertices_(KeyEdge * edgeToSplit, const std::vector<double> & splitValues)
2241 {
2242     Time time = edgeToSplit->time();
2243 
2244     typedef SculptCurve::Curve<EdgeSample> SketchedEdge;
2245 
2246     // The return value
2247     SplitInfo res;
2248     res.oldEdge = edgeToSplit;
2249 
2250     // Split the curve
2251     std::vector<SketchedEdge,Eigen::aligned_allocator<SketchedEdge> > split = static_cast<LinearSpline *>(edgeToSplit->geometry())->curve().split(splitValues);
2252 
2253     // Get start node or create it in case of loop
2254     KeyVertex * startVertex;
2255     if(!edgeToSplit->isClosed())
2256     {
2257         startVertex = edgeToSplit->startVertex();
2258     }
2259     else
2260     {
2261         // Create new node
2262         EdgeSample v = split[0].start();
2263         startVertex = newKeyVertex(time);
2264         startVertex->setPos(Eigen::Vector2d(v.x(), v.y()));
2265         res.newVertices << startVertex;
2266     }
2267 
2268     // Keep this very first vertex for later
2269     KeyVertex * firstVertex = startVertex;
2270 
2271     // Create new nodes and edges
2272     QColor color = edgeToSplit->color();
2273     for(unsigned int j=0; j<split.size()-1; j++)
2274     {
2275         // Create new node
2276         EdgeSample v = split[j].end();
2277         KeyVertex * newVertex = newKeyVertex(time);
2278         newVertex->setPos(Eigen::Vector2d(v.x(), v.y()));
2279         res.newVertices << newVertex;
2280 
2281         // Create geometry out of it
2282         EdgeGeometry * geometry = new LinearSpline(split[j]);
2283         KeyEdge * iedge = newKeyEdge(time, startVertex, newVertex, geometry);
2284         iedge->setColor(color);
2285         res.newEdges << iedge;
2286 
2287         // Recurse
2288         startVertex = newVertex;
2289     }
2290 
2291     // Create geometry of last out of it
2292     EdgeGeometry * geometry = new LinearSpline(split.back());
2293     KeyVertex * endVertex;
2294     if(!edgeToSplit->isClosed())
2295         endVertex = edgeToSplit->endVertex();
2296     else
2297         endVertex = firstVertex;
2298     KeyEdge * iedge = newKeyEdge(time, startVertex, endVertex, geometry);
2299     iedge->setColor(color);
2300     res.newEdges << iedge;
2301 
2302     // Update star
2303     CellSet star = edgeToSplit->star();
2304     KeyFaceSet keyFaces =  star;
2305     InbetweenEdgeSet inbetweenEdges =  star;
2306     InbetweenFaceSet inbetweenFaces =  star;
2307     foreach(KeyFace * c, keyFaces)
2308     {
2309         c->updateBoundary(res.oldEdge, res.newEdges);
2310         c->processGeometryChanged_();
2311     }
2312     foreach(InbetweenEdge * c, inbetweenEdges)
2313     {
2314         c->updateBoundary(res.oldEdge, res.newEdges);
2315     }
2316     foreach(InbetweenFace * c, inbetweenFaces)
2317     {
2318         c->updateBoundary(res.oldEdge, res.newEdges);
2319     }
2320 
2321     // Now that all calls of c->boundary() are trustable, update cached star
2322     foreach(Cell * c, star)
2323     {
2324         c->removeMeFromStarOf_(res.oldEdge);
2325         c->addMeToStarOfBoundary_();
2326     }
2327     // Delete old edge
2328     edgeToSplit->destroy();
2329 
2330     // Return
2331     return res;
2332 }
2333 
2334 
2335 ///////////////////////////////////////////////////////////////////////////
2336 ////////////////////               GLUING               ///////////////////
2337 
2338 // convenient casting
2339 /*
2340     KeyVertex * castedKeyVertex_;
2341     KeyEdge * castedKeyEdge_;
2342     KeyFace * castedKeyFace_;
2343     InbetweenVertex * castedInbetweenVertex_;
2344     InbetweenEdge * castedInbetweenEdge_;
2345     InbetweenFace * castedInbetweenFace_;
2346     void multicast_(Cell * c)
2347     {
2348         castedKeyVertex_ = c->toKeyVertex();
2349         castedKeyEdge_ = c->toKeyEdge();
2350         castedKeyFace_ = c->toKeyFace();
2351         castedInbetweenVertex_ = c->toInbetweenVertex();
2352         castedInbetweenEdge_ = c->toInbetweenEdge();
2353         castedInbetweenFace_ = c->toInbetweenFace();
2354     }
2355 
2356 
2357     void updateCellBoundary_ReplaceKeyVertexByAnother_(Cell * cell, KeyVertex * oldVertex, KeyVertex * newVertex)
2358     {
2359         multicast_
2360         K
2361         if(cell)
2362         if()
2363     }
2364 
2365     {
2366 
2367     }
2368 
2369 
2370     }
2371     */
2372 
glue_(KeyVertex * v1,KeyVertex * v2)2373 void VAC::glue_(KeyVertex * v1, KeyVertex * v2)
2374 {
2375     // make sure they have same time
2376     if(v1->time() != v2->time())
2377     {
2378         QMessageBox::information(0, QObject::tr("operation aborted"),
2379                                  QObject::tr("you can't glue two vertices not sharing the same time."));
2380         return;
2381     }
2382 
2383     // create new vertex
2384     KeyVertex * v3 = newKeyVertex(v1->time());
2385     v3->setPos(0.5*(v1->pos() + v2->pos()));
2386 
2387     // Update star
2388     CellSet star = v1->star();
2389     star.unite(v2->star());
2390     KeyEdgeSet keyEdges =  star;
2391     KeyFaceSet keyFaces =  star;
2392     InbetweenVertexSet inbetweenVertices =  star;
2393     InbetweenEdgeSet inbetweenEdges =  star;
2394     InbetweenFaceSet inbetweenFaces =  star;
2395     foreach(KeyEdge * c, keyEdges)
2396     {
2397         c->updateBoundary(v1,v3);
2398         c->updateBoundary(v2,v3);
2399         c->correctGeometry();
2400     }
2401     foreach(InbetweenVertex * c, inbetweenVertices)
2402     {
2403         c->updateBoundary(v1,v3);
2404         c->updateBoundary(v2,v3);
2405     }
2406     foreach(KeyFace * c, keyFaces)
2407     {
2408         c->updateBoundary(v1,v3);
2409         c->updateBoundary(v2,v3);
2410         c->processGeometryChanged_();
2411     }
2412     foreach(InbetweenEdge * c, inbetweenEdges)
2413     {
2414         c->updateBoundary(v1,v3);
2415         c->updateBoundary(v2,v3);
2416     }
2417     foreach(InbetweenFace * c, inbetweenFaces)
2418     {
2419         c->updateBoundary(v1,v3);
2420         c->updateBoundary(v2,v3);
2421     }
2422 
2423     // Now that all calls of c->boundary() are trustable, update cached star
2424     foreach(Cell * c, star)
2425     {
2426         c->removeMeFromStarOf_(v1);
2427         c->removeMeFromStarOf_(v2);
2428         c->addMeToStarOfBoundary_();
2429     }
2430 
2431     // delete glued vertices
2432     deleteCell(v1);
2433     deleteCell(v2);
2434 }
2435 
2436 namespace
2437 {
haveSameOrientation(KeyEdge * e1,KeyEdge * e2)2438 bool haveSameOrientation(KeyEdge * e1, KeyEdge * e2)
2439 {
2440     double l1 = e1->geometry()->length();
2441     Eigen::Vector2d u1 = e1->geometry()->der(0.5*l1);
2442     double l2 = e2->geometry()->length();
2443     Eigen::Vector2d u2 = e2->geometry()->der(0.5*l2);
2444     double dot = u1.dot(u2);
2445     if(dot>0)
2446         return !DevSettings::getBool("inverse direction"); // true by default
2447     else
2448         return DevSettings::getBool("inverse direction"); // false by default
2449 }
2450 }
2451 
glue_(KeyEdge * e1,KeyEdge * e2)2452 void VAC::glue_(KeyEdge * e1, KeyEdge * e2)
2453 {
2454     // make sure they have same time
2455     if(e1->time() != e2->time())
2456     {
2457         QMessageBox::information(0, QObject::tr("operation aborted"),
2458                                  QObject::tr("you can't glue two edges not sharing the same time."));
2459         return;
2460     }
2461 
2462     // make sure they have same topology
2463     if(e1->isClosed() != e2->isClosed())
2464     {
2465         QMessageBox::information(0, QObject::tr("operation aborted"),
2466                                  QObject::tr("you can't glue a closed edge with an open edge."));
2467         return;
2468     }
2469 
2470     // decide in what orientation to glue with simple heuristics
2471     glue_( KeyHalfedge(e1,true), KeyHalfedge(e2,haveSameOrientation(e1,e2)));
2472 }
2473 
2474 // assume h1 and h2 have same topology
glue_(const KeyHalfedge & h1,const KeyHalfedge & h2)2475 void VAC::glue_(const KeyHalfedge &h1, const KeyHalfedge &h2)
2476 {
2477     // glue end vertices
2478     if(!h1.isClosed())
2479     {
2480         if(h1.startVertex() != h2.startVertex())
2481             glue_(h1.startVertex(), h2.startVertex());
2482         if(h1.endVertex() != h2.endVertex())
2483             glue_(h1.endVertex(), h2.endVertex());
2484     }
2485 
2486     // Convenient data
2487     KeyEdge * e1 = h1.edge;
2488     KeyEdge * e2 = h2.edge;
2489 
2490     // compute new geometry
2491     SculptCurve::Curve<EdgeSample> & g1 = static_cast<LinearSpline*>(h1.edge->geometry())->curve();
2492     SculptCurve::Curve<EdgeSample> & g2 = static_cast<LinearSpline*>(h2.edge->geometry())->curve();
2493     double l1 = h1.edge->geometry()->length();
2494     double l2 = h2.edge->geometry()->length();
2495     std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > g3Vertices;
2496     int n1 = g1.size();
2497     int n2 = g2.size();
2498     int n = (n1+n2)/2 + 1;
2499     for(int i=0; i<n+1; i++)
2500     {
2501         double s1 = (double) i / (double) n * l1;
2502         if(!h1.side)
2503             s1 = l1 - s1;
2504         double s2 = (double) i / (double) n * l2;
2505         if(!h2.side)
2506             s2 = l2 - s2;
2507 
2508         EdgeSample es1 =  g1(s1);
2509         EdgeSample es2 =  g2(s2);
2510         g3Vertices << es1.lerp(0.5, es2);
2511     }
2512     SculptCurve::Curve<EdgeSample> g3;
2513     g3.setVertices(g3Vertices);
2514     if(h1.isClosed())
2515         g3.makeLoop();
2516     LinearSpline * ls3;
2517     ls3 = new LinearSpline(g3, h1.isClosed());
2518 
2519     // create new edge
2520     KeyEdge * e3;
2521     if(h1.isClosed())
2522         e3 = newKeyEdge(h1.time(), ls3);
2523     else
2524         e3 = newKeyEdge(h1.time(), h1.startVertex(), h1.endVertex(), ls3);
2525     KeyHalfedge h3(e3,true);
2526 
2527 
2528     // Update star
2529     CellSet star = e1->star();
2530     star.unite(e2->star());
2531     KeyFaceSet keyFaces =  star;
2532     InbetweenEdgeSet inbetweenEdges =  star;
2533     InbetweenFaceSet inbetweenFaces =  star;
2534     foreach(KeyFace * c, keyFaces)
2535     {
2536         c->updateBoundary(h1,h3);
2537         c->updateBoundary(h2,h3);
2538         c->processGeometryChanged_();
2539     }
2540     foreach(InbetweenEdge * c, inbetweenEdges)
2541     {
2542         c->updateBoundary(h1,h3);
2543         c->updateBoundary(h2,h3);
2544     }
2545     foreach(InbetweenFace * c, inbetweenFaces)
2546     {
2547         c->updateBoundary(h1,h3);
2548         c->updateBoundary(h2,h3);
2549     }
2550 
2551     // Now that all calls of c->boundary() are trustable, update cached star
2552     foreach(Cell * c, star)
2553     {
2554         c->removeMeFromStarOf_(e1);
2555         c->removeMeFromStarOf_(e2);
2556         c->addMeToStarOfBoundary_();
2557     }
2558 
2559     // set color
2560     QColor color1 = e1->color();
2561     QColor color2 = e2->color();
2562     e3->setColor(lerp(color1,color2,0.5));
2563 
2564     // delete glued edges
2565     deleteCell(e1);
2566     deleteCell(e2);
2567 }
2568 
nUses_(KeyVertex * v)2569 int VAC::nUses_(KeyVertex * v)
2570 {
2571     int res = 0;
2572 
2573     KeyFaceSet incidentFaces = v->spatialStar();
2574     KeyEdgeSet incidentEdges = v->spatialStar();
2575 
2576     foreach(KeyFace * f, incidentFaces)
2577     {
2578         // count how many times f uses v
2579         for(int i=0; i<f->cycles_.size(); ++i)
2580         {
2581             if(f->cycles_[i].vertex_ == v) // Steiner vertex
2582                 res++;
2583 
2584             for(int j=0; j<f->cycles_[i].size(); ++j)
2585             {
2586                 if(f->cycles_[i][j].startVertex() == v)
2587                     res++;
2588             }
2589         }
2590     }
2591 
2592     foreach(KeyEdge * e, incidentEdges)
2593     {
2594         KeyFaceSet fs = e->spatialStar();
2595         if(fs.size() == 0) // otherwise, will be counted as a use by the face
2596         {
2597             if(e->startVertex() == v)
2598                 res++;
2599             if(e->endVertex() == v)
2600                 res++;
2601         }
2602     }
2603 
2604     return res;
2605 }
2606 
nUses_(KeyEdge * e)2607 int VAC::nUses_(KeyEdge * e)
2608 {
2609     int res = 0;
2610 
2611     KeyFaceSet incidentFaces = e->spatialStar();
2612     foreach(KeyFace * f, incidentFaces)
2613     {
2614         // count how many times f uses e
2615         for(int i=0; i<f->cycles_.size(); ++i)
2616         {
2617             for(int j=0; j<f->cycles_[i].size(); ++j)
2618             {
2619                 if(f->cycles_[i][j].edge == e)
2620                     res++;
2621             }
2622         }
2623     }
2624 
2625     return res;
2626 }
2627 
unglue_(KeyVertex * v)2628 void VAC::unglue_(KeyVertex * v)
2629 {
2630     // compute uses
2631     int nUses = nUses_(v);
2632     //qDebug() << "n uses:" << nUses;
2633 
2634     if(nUses>1)
2635     {
2636         // Note: Unglue does not yet support incident inbetween cells
2637         //       As a workaround, we just delete all incident inbetween cells
2638         //       Later, we'll do something smarter
2639         CellSet inbetweenCells = v->temporalStar();
2640         deleteCells(inbetweenCells);
2641 
2642         // Unglue all incident edges
2643         KeyEdgeSet iEdges = v->spatialStar();
2644         foreach(KeyEdge * edge, iEdges)
2645             unglue_(edge);
2646 
2647         // Creates one duplicate vertex for each use
2648         KeyFaceSet incidentFaces = v->spatialStar();
2649         KeyEdgeSet incidentEdges = v->spatialStar();
2650 
2651         foreach(KeyFace * f, incidentFaces)
2652         {
2653             for(int i=0; i<f->cycles_.size(); ++i)
2654             {
2655                 if(f->cycles_[i].vertex_ == v) // Steiner vertex
2656                 {
2657                     // Create new vertex
2658                     KeyVertex * vNew = newKeyVertex(v->time());
2659                     vNew->pos_ = v->pos();
2660 
2661                     // Use it instead of original one
2662                     f->cycles_[i].vertex_ = vNew;
2663                     f->addMeToSpatialStarOf_(vNew);
2664                     f->removeMeFromSpatialStarOf_(v);
2665                 }
2666 
2667                 for(int j=0; j<f->cycles_[i].size(); ++j)
2668                 {
2669                     if(f->cycles_[i][j].startVertex() == v)
2670                     {
2671                         // Create new vertex
2672                         KeyVertex * vNew = newKeyVertex(v->time());
2673                         vNew->pos_ = v->pos();
2674 
2675                         // Use it instead of original one
2676                         // The bracket here do "f->something_ = vNew" (done indirectly via the halfedges)
2677                         {
2678                             // for the two involved edges, use new vertex instead of the original one
2679                             // note: if v is used twice by e, you really want to change only the
2680                             //       appropriate one. The other will be created after
2681 
2682                             // Replace in f->cycles_[i][j]
2683                             KeyHalfedge & hAfter = f->cycles_[i].halfedges_[j];
2684                             if(hAfter.side)
2685                             {
2686                                 hAfter.edge->startVertex_ = vNew;
2687                                 hAfter.edge->addMeToSpatialStarOf_(vNew);
2688                                 hAfter.edge->removeMeFromSpatialStarOf_(v);
2689                             }
2690                             else
2691                             {
2692                                 hAfter.edge->endVertex_ = vNew;
2693                                 hAfter.edge->addMeToSpatialStarOf_(vNew);
2694                                 hAfter.edge->removeMeFromSpatialStarOf_(v);
2695                             }
2696 
2697                             // Replace in f->cycles_[i]["j-1"]
2698                             int jMinus1 = ( j==0 ? f->cycles_[i].size() - 1 : j-1 );
2699                             KeyHalfedge & hBefore = f->cycles_[i].halfedges_[jMinus1];
2700                             if(hBefore.side)
2701                             {
2702                                 hBefore.edge->endVertex_ = vNew;
2703                                 hBefore.edge->addMeToSpatialStarOf_(vNew);
2704                                 hBefore.edge->removeMeFromSpatialStarOf_(v);
2705                             }
2706                             else
2707                             {
2708                                 hBefore.edge->startVertex_ = vNew;
2709                                 hBefore.edge->addMeToSpatialStarOf_(vNew);
2710                                 hBefore.edge->removeMeFromSpatialStarOf_(v);
2711                             }
2712                         }
2713                         f->addMeToSpatialStarOf_(vNew);
2714                         f->removeMeFromSpatialStarOf_(v);
2715                     }
2716                 }
2717             }
2718 
2719             // Recompute geometry
2720             f->processGeometryChanged_();
2721         }
2722 
2723         foreach(KeyEdge * e, incidentEdges)
2724         {
2725             KeyFaceSet fs = e->spatialStar();
2726             if(fs.size() == 0) // otherwise, will be counted as a use by the face
2727             {
2728                 if(e->startVertex() == v)
2729                 {
2730                     // Create new vertex
2731                     KeyVertex * vNew = newKeyVertex(v->time());
2732                     vNew->pos_ = v->pos();
2733 
2734                     // Use it instead of original one
2735                     e->startVertex_ = vNew;
2736                     e->addMeToSpatialStarOf_(vNew);
2737                     e->removeMeFromSpatialStarOf_(v);
2738                 }
2739                 if(e->endVertex() == v)
2740                 {
2741                     // Create new vertex
2742                     KeyVertex * vNew = newKeyVertex(v->time());
2743                     vNew->pos_ = v->pos();
2744 
2745                     // Use it instead of original one
2746                     e->endVertex_ = vNew;
2747                     e->addMeToSpatialStarOf_(vNew);
2748                     e->removeMeFromSpatialStarOf_(v);
2749                 }
2750             }
2751         }
2752 
2753         // Delete original vertex
2754         deleteCell(v);
2755     }
2756 }
2757 
2758 
unglue_(KeyEdge * e)2759 void VAC::unglue_(KeyEdge * e)
2760 {
2761     // compute uses
2762     int nUses = nUses_(e);
2763     //qDebug() << "n uses:" << nUses;
2764 
2765     if(nUses>1)
2766     {
2767         // Note: Unglue does not yet support incident inbetween cells
2768         //       As a workaround, we just delete all incident inbetween cells
2769         //       Later, we'll do something smarter
2770         CellSet inbetweenCells = e->temporalStar();
2771         deleteCells(inbetweenCells);
2772 
2773         // Create one duplicate edge for each use
2774         KeyFaceSet incidentFaces = e->spatialStar();
2775         foreach(KeyFace * f, incidentFaces)
2776         {
2777             for(int i=0; i<f->cycles_.size(); ++i)
2778             {
2779                 for(int j=0; j<f->cycles_[i].size(); ++j)
2780                 {
2781                     if(f->cycles_[i][j].edge == e)
2782                     {
2783                         // duplicate edge
2784                         EdgeGeometry * geometryNew = e->geometry()->clone();
2785                         KeyEdge * eNew;
2786                         if(e->isClosed())
2787                             eNew = newKeyEdge(e->time(), geometryNew);
2788                         else
2789                             eNew = newKeyEdge(e->time(), e->startVertex(), e->endVertex(), geometryNew);
2790 
2791                         // set color
2792                         eNew->setColor(e->color());
2793 
2794                         // set duplicated edge as new boundary edge
2795                         f->cycles_[i].halfedges_[j].edge = eNew;
2796                         f->addMeToSpatialStarOf_(eNew);
2797                         f->removeMeFromSpatialStarOf_(e);
2798                     }
2799                 }
2800             }
2801 
2802             // Recompute geometry
2803             f->processGeometryChanged_();
2804         }
2805 
2806         // Delete original edge
2807         deleteCell(e);
2808     }
2809 }
2810 
uncut_(KeyVertex * v)2811 bool VAC::uncut_(KeyVertex * v)
2812 {
2813     // compute edge n usage, check it's not more than 2
2814     bool isSplittedLoop = false;
2815     KeyEdge * e1 = 0;
2816     KeyEdge * e2 = 0;
2817     KeyEdgeSet incidentEdges = v->spatialStar();
2818     if(incidentEdges.size() == 0)
2819     {
2820         // Then can be uncut if it is a steiner vertex of one face, and one face only
2821         KeyFaceSet incidentFaces = v->spatialStar();
2822         bool found = false;
2823         KeyFace * foundFace = 0;
2824         int foundI = -1;
2825         foreach(KeyFace * f, incidentFaces)
2826         {
2827             for(int i=0; i<f->cycles_.size(); ++i)
2828             {
2829                 if(f->cycles_[i].vertex_ == v) // Steiner vertex
2830                 {
2831                     if(found)
2832                     {
2833                         //qDebug() << "Abort: Steiner vertex more than once, can't uncut here";
2834                         return false;
2835                     }
2836                     else
2837                     {
2838                         found = true;
2839                         foundFace = f;
2840                         foundI = i;
2841                     }
2842                 }
2843             }
2844 
2845             // Recompute geometry
2846             f->processGeometryChanged_();
2847         }
2848 
2849         if(found == true)
2850         {
2851             // remove steiner vertex from cycles
2852             QList<Cycle> newCycles;
2853             for(int i=0; i<foundFace->cycles_.size(); ++i)
2854                 if(i != foundI)
2855                     newCycles << foundFace->cycles_[i];
2856 
2857             // update face
2858             foundFace->cycles_ = newCycles;
2859             foundFace->removeMeFromSpatialStarOf_(v);
2860 
2861             // delete vertex
2862             deleteCell(v);
2863 
2864             // return
2865             return true;
2866         }
2867         else
2868         {
2869             //qDebug() << "Abort: vertex has no star cells";
2870             return false;
2871         }
2872     }
2873     else if(incidentEdges.size() == 1)
2874     {
2875         e1 = *incidentEdges.begin();
2876         isSplittedLoop = true;
2877         if(e1->startVertex() != e1->endVertex())
2878         {
2879             //qDebug() << "Uncut abort: only one incident edge that do not loop";
2880             return false;
2881         }
2882     }
2883     else if(incidentEdges.size() == 2)
2884     {
2885         e1 = *incidentEdges.begin();
2886         e2 = *(++incidentEdges.begin());
2887         if( (e1->startVertex() == e1->endVertex()) || (e2->startVertex() == e2->endVertex()))
2888         {
2889             //qDebug() << "Uncut abort: more than two incident edges";
2890             return false;
2891         }
2892     }
2893     else
2894     {
2895         //qDebug() << "Uncut abort: more than two incident edges";
2896         return false;
2897     }
2898 
2899     // From here, we already left the method if incidentEdges.size() == 0.
2900     // hence, the following only concerns the case where the vertex has at least
2901     // one incident edge
2902 
2903     // check that removing this vertex is compatible with incident faces
2904     KeyFaceSet incidentFaces = v->spatialStar();
2905     foreach(KeyFace * f, incidentFaces)
2906     {
2907         // check that it can be removed
2908         for(int i=0; i<f->cycles_.size(); ++i)
2909         {
2910             if(f->cycles_[i].vertex_ == v) // Steiner vertex
2911             {
2912                 //qDebug() << "Vertex used as Steiner vertex: can't uncut here";
2913                 return false;
2914             }
2915 
2916             for(int j=0; j<f->cycles_[i].size(); ++j)
2917             {
2918                 if(f->cycles_[i][j].startVertex() == v)
2919                 {
2920                     // used here
2921                     if(isSplittedLoop)
2922                     {
2923                         // check that it is alone: in this case it will be replace
2924                         if(f->cycles_[i].size() != 1)
2925                         {
2926                             // TODO: actually, could cut if the other halfedges are also
2927                             // using the same edge (EDIT after EDIT: same direction (no switch backs))
2928                             // EDIT after TODO: actually... not. What would be done in this case?
2929                             // the edge is a splitted loop. Hence, the result of uncutting would give a loop.
2930                             // Either:
2931                             //   - we allow to repeat a pure loop inside a single cycle
2932                             //   - we can't uncut, since removing
2933                             // To keep rendering/winding rules unchanged
2934                             //qDebug() << "Split loop involved with other halfedges in cycle: can't uncut here";
2935                             return false;
2936                         }
2937                     }
2938                     else
2939                     {
2940                         // check that the same edge is not repeated
2941                         int jMinus1 = ( j==0 ? f->cycles_[i].size() - 1 : j-1 );
2942                         if(f->cycles_[i][jMinus1].edge == f->cycles_[i][j].edge)
2943                         {
2944                             //qDebug() << "Cycle switching back direction at vertex: can't uncut here";
2945                             return false;
2946                         }
2947                     }
2948                 }
2949             }
2950         }
2951 
2952         // Recompute geometry
2953         f->processGeometryChanged_();
2954     }
2955 
2956     // We're OK now, just do it :-)
2957 
2958     if(isSplittedLoop)
2959     {
2960         // transform splitted loop into pure loop
2961         e1->startVertex_ = 0;
2962         e1->endVertex_ = 0;
2963         e1->removeMeFromSpatialStarOf_(v);
2964         e1->geometry()->makeLoop();
2965 
2966         // update incident faces
2967         foreach(KeyFace * f, incidentFaces)
2968         {
2969             for(int i=0; i<f->cycles_.size(); ++i)
2970             {
2971                 for(int j=0; j<f->cycles_[i].size(); ++j)
2972                 {
2973                     if(f->cycles_[i][j].edge == e1)
2974                     {
2975                         f->removeMeFromSpatialStarOf_(v);
2976                     }
2977                 }
2978             }
2979 
2980             // Recompute geometry
2981             f->processGeometryChanged_();
2982         }
2983 
2984         // delete vertex
2985         deleteCell(v);
2986     }
2987     else
2988     {
2989         // get orientation: h1 -> v -> h2
2990         KeyHalfedge h1(e1, (e1->endVertex() == v ? true : false) );
2991         KeyHalfedge h2(e2, (e2->startVertex() == v ? true : false) );
2992 
2993         // create equivalent edge/halfedge
2994         // [... ; h = (e,true) ; ...]  <=>  [...;h1;h2;...]
2995 
2996         // compute new geometry
2997         SculptCurve::Curve<EdgeSample> & g1 = static_cast<LinearSpline*>(e1->geometry())->curve();
2998         SculptCurve::Curve<EdgeSample> & g2 = static_cast<LinearSpline*>(e2->geometry())->curve();
2999         std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > g3Vertices;
3000         int n1 = g1.size();
3001         int n2 = g2.size();
3002         if(h1.side)
3003         {
3004             for(int i=0; i<n1; ++i)
3005                 g3Vertices << g1[i];
3006         }
3007         else
3008         {
3009             for(int i=n1-1; i>=0; --i)
3010                 g3Vertices << g1[i];
3011         }
3012         if(h2.side)
3013         {
3014             for(int i=1; i<n2; ++i)
3015                 g3Vertices << g2[i];
3016         }
3017         else
3018         {
3019             for(int i=n2-2; i>=0; --i)
3020                 g3Vertices << g2[i];
3021         }
3022         SculptCurve::Curve<EdgeSample> g3;
3023         g3.setVertices(g3Vertices);
3024         LinearSpline * ls3 = new LinearSpline(g3, false);
3025 
3026         // create new edge
3027         KeyEdge * e = newKeyEdge(v->time(), h1.startVertex(), h2.endVertex(), ls3);
3028         QColor color1 = e1->color();
3029         QColor color2 = e2->color();
3030         e->setColor(lerp(color1,color2,0.5));
3031 
3032         // update incident faces
3033         foreach(KeyFace * f, incidentFaces)
3034         {
3035             for(int i=0; i<f->cycles_.size(); ++i)
3036             {
3037                 Cycle newCycle;
3038                 bool cycleHasChanged = false;
3039 
3040                 for(int j=0; j<f->cycles_[i].size(); ++j)
3041                 {
3042                     if(f->cycles_[i][j].edge == e1)
3043                     {
3044                         // do nothing
3045                     }
3046                     else if (f->cycles_[i][j].edge == e2)
3047                     {
3048                         if(f->cycles_[i][j].side == h2.side)
3049                         {
3050                             newCycle.halfedges_ << KeyHalfedge(e,true);
3051                         }
3052                         else
3053                         {
3054                             newCycle.halfedges_ << KeyHalfedge(e,false);
3055                         }
3056                         cycleHasChanged = true;
3057                     }
3058                     else
3059                     {
3060                         newCycle.halfedges_ << f->cycles_[i][j];
3061                     }
3062                 }
3063 
3064                 if(cycleHasChanged)
3065                 {
3066                     f->cycles_[i] = newCycle;
3067                     f->addMeToSpatialStarOf_(e);
3068                     f->removeMeFromSpatialStarOf_(e1);
3069                     f->removeMeFromSpatialStarOf_(e2);
3070                     f->removeMeFromSpatialStarOf_(v);
3071                 }
3072             }
3073 
3074             // Recompute geometry
3075             f->processGeometryChanged_();
3076         }
3077 
3078         // delete vertex
3079         deleteCell(v);
3080     }
3081 
3082     return true;
3083 }
3084 
uncut_(KeyEdge * e)3085 bool VAC::uncut_(KeyEdge * e)
3086 {
3087     // Compute number of uses
3088     int nUses = nUses_(e);
3089     if(nUses < 2)
3090     {
3091         //qDebug() << "less than 2 faces are incident to this edge: nothing to uncut";
3092         return false;
3093     }
3094     else if (nUses > 2)
3095     {
3096         //qDebug() << "more than 2 faces are incident to this edge: cannot uncut";
3097         return false;
3098     }
3099 
3100     // in case the edge is a loop
3101     if(e->isClosed())
3102     {
3103         // get incident faces
3104         KeyFaceSet incidentFaces = e->spatialStar();
3105 
3106         // two cases: either the two usages are from the same face, or from two different faces
3107         if(incidentFaces.size() == 1)
3108         {
3109             // in case they are from the same face, just remove the two cycles
3110             KeyFace * f = *incidentFaces.begin();
3111             QList<Cycle> newCycles;
3112             for(int i=0; i<f->cycles_.size(); ++i)
3113             {
3114                 if( (f->cycles_[i].type() == Cycle::SingleVertex) ||
3115                         (f->cycles_[i][0].edge != e) )
3116                     newCycles << f->cycles_[i];
3117             }
3118             f->cycles_ = newCycles;
3119             f->removeMeFromSpatialStarOf_(e);
3120 
3121             // Recompute geometry
3122             f->processGeometryChanged_();
3123 
3124             // and delete the edge
3125             deleteCell(e);
3126         }
3127         else if (incidentFaces.size() == 2)
3128         {
3129             // in case they are from two different faces, remove the cycle
3130             // from each, and combine topology in a single face
3131 
3132             // remove cycles
3133             KeyFace * f1 = *incidentFaces.begin();
3134             KeyFace * f2 = *(++incidentFaces.begin());
3135 
3136             // get all cycles of f1 except e
3137             QList<Cycle> newCycles;
3138             for(int i=0; i<f1->cycles_.size(); ++i)
3139             {
3140                 if( (f1->cycles_[i].type() == Cycle::SingleVertex) ||
3141                         (f1->cycles_[i][0].edge != e) )
3142                     newCycles << f1->cycles_[i];
3143             }
3144 
3145             // get all cycles of f2 except e
3146             for(int i=0; i<f2->cycles_.size(); ++i)
3147             {
3148                 if( (f2->cycles_[i].type() == Cycle::SingleVertex) ||
3149                         (f2->cycles_[i][0].edge != e) )
3150                     newCycles << f2->cycles_[i];
3151             }
3152 
3153             // delete f2
3154             deleteCell(f2);
3155 
3156             // update f1
3157             f1->cycles_ = newCycles;
3158             f1->removeMeFromSpatialStarOf_(e);
3159             foreach(Cell * c, f1->spatialBoundary())
3160                 f1->addMeToSpatialStarOf_(c);
3161 
3162             // Recompute geometry
3163             f1->processGeometryChanged_();
3164 
3165             // delete e
3166             deleteCell(e);
3167         }
3168         else
3169         {
3170             // can't happen, we know nUses == 2, hence incidentFaces.size == 1 or 2
3171         }
3172     }
3173     // In case the edge is an open edge
3174     else
3175     {
3176 
3177         //////////////////////////////////////////////////////////////////////////////////
3178         //          Compute newCycles, cycle1 and cycle2, delete f2 if any              //
3179         //////////////////////////////////////////////////////////////////////////////////
3180 
3181         // The new cycles
3182         QList<Cycle> newCycles;
3183 
3184         // The two cycles to merge
3185         Cycle cycle1;
3186         Cycle cycle2;
3187 
3188         // Get incident faces
3189         KeyFaceSet incidentFaces = e->spatialStar();
3190         if(incidentFaces.size() == 1)
3191         {
3192             // Either One face One cycle
3193             // Or     One face Two cycles
3194             KeyFace * f = *incidentFaces.begin();
3195             for(int i=0; i<f->cycles_.size(); ++i)
3196             {
3197                 // check if e belongs to this cycle
3198                 int eBelongsToCycle = 0;
3199                 int j1 = -1; // if it does, here are the indices
3200                 int j2 = -1;
3201                 int n = f->cycles_[i].size();
3202                 for(int j=0; j<n; ++j)
3203                     if(f->cycles_[i][j].edge == e)
3204                     {
3205                         eBelongsToCycle++;
3206                         if(j1 == -1)
3207                             j1 = j;
3208                         else
3209                             j2 = j;
3210                     }
3211 
3212                 // do something accordingly
3213                 if(eBelongsToCycle == 0)
3214                 {
3215                     // if e doesn't belong to cycle, just add cycle to newCycles
3216                     newCycles << f->cycles_[i];
3217                 }
3218                 else if(eBelongsToCycle == 1)
3219                 {
3220                     // If e belongs once to cycle
3221                     // ==> One face Two cycles
3222 
3223                     // Get the cycle to which we copy halfedges
3224                     Cycle & cycle = ( cycle1.size() ? cycle2 : cycle1 );
3225 
3226                     // Copy all halfedges of f->cycles_[i], except e, into cycle1 or cycle2.
3227                     int j1Plus1 = ( j1==n-1 ? 0 : j1+1);
3228                     for(int j=j1Plus1; j != j1; j = (j==n-1 ? 0 : j+1) )
3229                         cycle.halfedges_ << f->cycles_[i][j];
3230 
3231                     // Handle Steiner vertex case
3232                     if(cycle.size() == 0)
3233                     {
3234                         // This means that f->cycles_[i].size() = 1
3235                         // But we know e belong to the cycle and is open
3236                         // This means e is a splitted loop
3237                         // This means e->left() == e->right().
3238                         //
3239                         // Cycle must be of type Single Vertex
3240 
3241                         cycle.vertex_ = e->startVertex();
3242                     }
3243                 }
3244                 else if(eBelongsToCycle == 2)
3245                 {
3246                     // if e belongs twice to the same cycle
3247                     // ==> One face One cycle
3248 
3249                     // Copy all halfedges of f->cycles_[i], except e, into cycle1 and cycle2.
3250 
3251                     // Get indices where the cycles start
3252                     int j1Plus1 = ( j1==n-1 ? 0 : j1+1);
3253                     int j2Plus1 = ( j2==n-1 ? 0 : j2+1);
3254 
3255                     // Cycle 1
3256                     for(int j=j1Plus1; j != j2; j = (j==n-1 ? 0 : j+1) )
3257                         cycle1.halfedges_ << f->cycles_[i][j];
3258                     // Handle Steiner vertex case
3259                     if(cycle1.size() == 0)
3260                     {
3261                         // means j1+1 = j2
3262                         // must add vertex between j1 and j2
3263                         cycle1.vertex_ = f->cycles_[i][j1].endVertex();
3264                     }
3265 
3266                     // Cycle 2
3267                     for(int j=j2Plus1; j != j1; j = (j==n-1 ? 0 : j+1) )
3268                         cycle2.halfedges_ << f->cycles_[i][j];
3269                     // Handle Steiner vertex case
3270                     if(cycle2.size() == 0)
3271                     {
3272                         // means j2+1 = j1
3273                         // must add vertex between j2 and j1
3274                         cycle2.vertex_ = f->cycles_[i][j2].endVertex();
3275                     }
3276                 }
3277                 else
3278                 {
3279                     // can't happen
3280                 }
3281             }
3282 
3283             // Recompute geometry
3284             f->processGeometryChanged_();
3285         }
3286         else if (incidentFaces.size() == 2)
3287         {
3288             // ==> Two faces Two cycles
3289 
3290             // Face 1: append cycles to newCycles or Cycle 1
3291             KeyFace * f1 = *incidentFaces.begin();
3292             for(int i=0; i<f1->cycles_.size(); ++i)
3293             {
3294                 // check if (and where) e belongs to this cycle
3295                 int j1 = -1;
3296                 int n1 = f1->cycles_[i].size();
3297                 for(int j=0; j<n1; ++j)
3298                     if(f1->cycles_[i][j].edge == e)
3299                         j1 = j;
3300 
3301                 // do something accordingly
3302                 if(j1 == -1) // if doesn't belong to cycle
3303                 {
3304                     // add cycle to newCycles
3305                     newCycles << f1->cycles_[i];
3306                 }
3307                 else // if belongs to cycle
3308                 {
3309                     // Copy all halfedges of f1->cycles_[i], except e, into cycle1
3310                     int j1Plus1 = ( j1==n1-1 ? 0 : j1+1);
3311                     for(int j=j1Plus1; j != j1; j = (j==n1-1 ? 0 : j+1) )
3312                         cycle1.halfedges_ << f1->cycles_[i][j];
3313 
3314                     // Handle Steiner vertex case
3315                     if(cycle1.size() == 0)
3316                         cycle1.vertex_ = e->startVertex();
3317                 }
3318             }
3319 
3320             // Face 2: append cycles to newCycles or Cycle 2
3321             KeyFace * f2 = *(++incidentFaces.begin());
3322             for(int i=0; i<f2->cycles_.size(); ++i)
3323             {
3324                 // check if (and where) e belongs to this cycle
3325                 int j2 = -1;
3326                 int n2 = f2->cycles_[i].size();
3327                 for(int j=0; j<n2; ++j)
3328                     if(f2->cycles_[i][j].edge == e)
3329                         j2 = j;
3330 
3331                 // do something accordingly
3332                 if(j2 == -1) // if doesn't belong to cycle
3333                 {
3334                     // add cycle to newCycles
3335                     newCycles << f2->cycles_[i];
3336                 }
3337                 else // if belongs to cycle
3338                 {
3339                     // Copy all halfedges of f1->cycles_[i], except e, into cycle1
3340                     int j2Plus1 = ( j2==n2-1 ? 0 : j2+1);
3341                     for(int j=j2Plus1; j != j2; j = (j==n2-1 ? 0 : j+1) )
3342                         cycle2.halfedges_ << f2->cycles_[i][j];
3343 
3344                     // Handle Steiner vertex case
3345                     if(cycle2.size() == 0)
3346                         cycle2.vertex_ = e->startVertex();
3347                 }
3348             }
3349 
3350             // Set color
3351             QColor color1 = f1->color();
3352             QColor color2 = f2->color();
3353             f1->setColor(lerp(color1,color2,0.5));
3354 
3355             // Delete Face 2
3356             deleteCell(f2);
3357 
3358             // Recompute geometry
3359             f1->processGeometryChanged_();
3360         }
3361 
3362 
3363         //////////////////////////////////////////////////////////////////////////////////
3364         //    Decide on what to do with cycle1 and cycle2, add result to newCycles      //
3365         //////////////////////////////////////////////////////////////////////////////////
3366 
3367         // Ensure that the cycles are valid
3368         if(!cycle1.isValid() || !cycle2.isValid())
3369         {
3370             //qDebug() << "Uncut abort: cycle 1 or cycle 2 is invalid for an unknown reason";
3371             return false;
3372         }
3373 
3374         // Handle Steiner vertices
3375         if(cycle1.type() == Cycle::SingleVertex)
3376         {
3377             // If Cycle 1 is a Steiner vertex, then add Cycle 2 in any cases,
3378             // and add Cycle 1 only if not contained in Cycle 2
3379             if(cycle2.cells().contains(cycle1.singleVertex()))
3380                 newCycles << cycle2;
3381             else
3382                 newCycles << cycle1 << cycle2;
3383         }
3384         else if(cycle2.type() == Cycle::SingleVertex)
3385         {
3386             // If Cycle 1 is a Steiner vertex, then add Cycle 2 in any cases,
3387             // and add Cycle 1 only if not contained in Cycle 2
3388             if(cycle1.cells().contains(cycle2.singleVertex()))
3389                 newCycles << cycle1;
3390             else
3391                 newCycles << cycle2 << cycle1;
3392         }
3393 
3394         // Handle cases where none of cycle 1 or cycle 2 are Steiner vertices
3395         else
3396         {
3397             // Check if can or must be merge
3398             KeyVertex * startCycle1 = cycle1.halfedges_.front().startVertex();
3399             KeyVertex * endCycle1 = cycle1.halfedges_.back().endVertex();
3400             KeyVertex * startCycle2 = cycle2.halfedges_.front().startVertex();
3401             KeyVertex * endCycle2 = cycle2.halfedges_.back().endVertex();
3402 
3403             // if the two cycles are already valid, great! Don't touch them
3404             if( (endCycle1 == startCycle1) && (endCycle2 == startCycle2) )
3405             {
3406                 newCycles << cycle1 << cycle2;
3407             }
3408             // Otherwise need to combine them
3409             else if( (endCycle1 == startCycle2) && (endCycle2 == startCycle1) )
3410             {
3411                 // if already compatible, great! just append them
3412                 for(int j=0; j<cycle2.size(); ++j)
3413                     cycle1.halfedges_ << cycle2[j];
3414 
3415                 newCycles << cycle1;
3416             }
3417             else if( (endCycle1 == endCycle2) && (startCycle2 == startCycle1) )
3418             {
3419                 // in this case, we just have to reverse one of them, no big deal.
3420                 for(int j=cycle2.size()-1; j>=0; --j)
3421                     cycle1.halfedges_ << cycle2[j].opposite();
3422 
3423                 newCycles << cycle1;
3424             }
3425             else
3426             {
3427                 // woops, this shouldn't happen
3428                 //qDebug() << "Uncut abort: can't combine cycle 1 and 2 for some unknown reason";
3429                 return false;
3430             }
3431         }
3432 
3433 
3434         //////////////////////////////////////////////////////////////////////////////////
3435         //    Update merged face                                                    //
3436         //////////////////////////////////////////////////////////////////////////////////
3437 
3438         // update topology
3439         KeyFace * f = *incidentFaces.begin();
3440         f->cycles_ = newCycles;
3441         f->removeMeFromSpatialStarOf_(e);
3442         foreach(Cell * c, f->spatialBoundary())
3443             f->addMeToSpatialStarOf_(c);
3444 
3445         // update z-ordering
3446         zOrdering_.removeCell(f);
3447         zOrdering_.insertCell(f);
3448 
3449         // Recompute geometry
3450         f->processGeometryChanged_();
3451 
3452         // delete e
3453         deleteCell(e);
3454     }
3455 
3456     return true;
3457 }
3458 
insertSketchedEdgeInVAC()3459 void VAC::insertSketchedEdgeInVAC()
3460 {
3461     double tolerance = global()->snapThreshold();
3462     double toleranceEpsilon = 1e-2;
3463     if( (tolerance < toleranceEpsilon) || !(global()->snapMode()) )
3464         tolerance = 1e-2;
3465     insertSketchedEdgeInVAC(tolerance);
3466 }
3467 
insertSketchedEdgeInVAC(double tolerance,bool useFaceToConsiderForCutting)3468 void VAC::insertSketchedEdgeInVAC(double tolerance, bool useFaceToConsiderForCutting)
3469 {
3470     // --------------------------------------------------------------------
3471     // ---------------------- Input Variables -----------------------------
3472     // --------------------------------------------------------------------
3473 
3474     bool intersectWithSelf = global()->planarMapMode();
3475     bool intersectWithOthers = global()->planarMapMode();
3476 
3477     // --------------------------------------------------------------------
3478     // ----------------- Compute dirty intersections ----------------------
3479     // --------------------------------------------------------------------
3480 
3481     typedef SculptCurve::Curve<EdgeSample> SketchedEdge;
3482     std::vector<             SculptCurve::Intersection  > selfIntersections;
3483     std::vector< std::vector<SculptCurve::Intersection> > othersIntersections;
3484 
3485     // Lengths of the sketched edge and existing ("others") edges
3486     double lSelf = sketchedEdge_->length(); // compute it now
3487     std::vector<double> lOthers;            // will be computed inside the loop
3488 
3489     // Store geometry of existing edges as a "SketchedEdge"
3490     std::vector< SculptCurve::Curve<EdgeSample>,Eigen::aligned_allocator<SculptCurve::Curve<EdgeSample> >  > sketchedEdges; // sketchedEdges.size() == nEdges.
3491 
3492     // Compute intersections with self
3493     if(intersectWithSelf)
3494         selfIntersections = sketchedEdge_->curve().selfIntersections(tolerance);
3495 
3496     // Keyframe existing inbetween edge that intersect with sketched edge
3497     if(intersectWithOthers)
3498     {
3499         InbetweenEdgeSet inbetweenEdges;
3500         foreach(Cell * cell, cells())
3501         {
3502             InbetweenEdge * sedge = cell->toInbetweenEdge();
3503             if(sedge && sedge->exists(timeInteractivity_))
3504                 inbetweenEdges << sedge;
3505         }
3506         foreach(InbetweenEdge * sedge, inbetweenEdges)
3507         {
3508             // Get sampling as a QList of EdgeSamples
3509             QList<EdgeSample> sampling = sedge->getSampling(timeInteractivity_);
3510 
3511             // Convert sampling to a std::vector of EdgeSamples
3512             std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > stdSampling;
3513             for(int i=0; i<sampling.size(); ++i)
3514                 stdSampling << sampling[i];
3515 
3516             // Convert sampling to a SculptCurve::Curve<EdgeSample>
3517             SculptCurve::Curve<EdgeSample> sketchedEdge;
3518             sketchedEdge.setVertices(stdSampling);
3519 
3520             // Compute intersections
3521             std::vector<SculptCurve::Intersection> intersections = sketchedEdge_->curve().intersections(sketchedEdge, tolerance);
3522 
3523             // Keyframe edge if there are some intersections
3524             if(intersections.size() > 0)
3525                 keyframe_(sedge, timeInteractivity_);
3526         }
3527     }
3528 
3529     // Compute intersections with others
3530     KeyEdgeList iedgesBefore; // the list of edges before they are split by the newly sketched edge
3531     int nEdges = 0;               // the number of them
3532     if(intersectWithOthers)
3533     {
3534         // Get existing edges
3535         iedgesBefore = instantEdges(timeInteractivity_);
3536         nEdges = iedgesBefore.size();
3537 
3538         // For each of them, compute intersections with sketched edge
3539         foreach (KeyEdge * iedge, iedgesBefore)
3540         {
3541             // Convert geometry of instant edge to a SketchedEdge
3542             EdgeGeometry * geometry = iedge->geometry();
3543             LinearSpline * linearSpline = dynamic_cast<LinearSpline *>(geometry);
3544             if(linearSpline)
3545             {
3546                 sketchedEdges << linearSpline->curve() ;
3547             }
3548             else
3549             {
3550                 QList<Eigen::Vector2d> eigenSampling = geometry->sampling(ds_);
3551                 std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > vertices;
3552                 for(int i=0; i<eigenSampling.size(); ++i)
3553                     vertices << EdgeSample(eigenSampling[i][0], eigenSampling[i][1], 10); // todo: get actual width
3554                 sketchedEdges << SculptCurve::Curve<EdgeSample>();
3555                 sketchedEdges.back().setVertices(vertices);
3556             }
3557 
3558             // Compute intersections
3559             othersIntersections << sketchedEdge_->curve().intersections(sketchedEdges.back(), tolerance);
3560 
3561             // Store length
3562             lOthers << sketchedEdges.back().length();
3563         }
3564     }
3565 
3566 
3567     // --------------------------------------------------------------------
3568     // ----------------- Compute dirty split values -----------------------
3569     // --------------------------------------------------------------------
3570 
3571     // Convert dirty intersections to dirty (= with possible duplicates) split values
3572     std::vector<             double  > selfSplitValues_dirty;
3573     std::vector< std::vector<double> > othersSplitValues_dirty(nEdges, std::vector<double>() );
3574 
3575     // Self split values due to self-intersections + endpoints of sketched edge
3576     // Note: detecting if the sketched edge is a loop is done at a later stage
3577     for(auto intersection : selfIntersections)
3578         selfSplitValues_dirty << intersection.s << intersection.t;
3579     selfSplitValues_dirty << 0.0 << lSelf;
3580 
3581     // Split values (both self and others) due to intersections with existing edges
3582     for(int i=0; i<nEdges; ++i)
3583     {
3584         for(auto intersection : othersIntersections[i])
3585         {
3586             selfSplitValues_dirty << intersection.s;
3587             othersSplitValues_dirty[i] << intersection.t;
3588         }
3589     }
3590 
3591     // Sort dirty split values
3592     std::sort(selfSplitValues_dirty.begin(),
3593               selfSplitValues_dirty.end());
3594 
3595     for(auto & otherSplitValues : othersSplitValues_dirty)
3596     {
3597         std::sort(otherSplitValues.begin(),
3598                   otherSplitValues.end());
3599     }
3600 
3601 #if MYDEBUG
3602     {
3603         /////////  Print split values so far  /////////
3604         std::cout << "Raw split values:" << std::endl;
3605         std::cout << "  Self split values = [ ";
3606         for(double s : selfSplitValues_dirty)
3607             std::cout << s << " ";
3608         std::cout << "]" << std::endl;
3609         std::cout << "  Others split values =" << std::endl;
3610         for(auto splitValues : othersSplitValues_dirty)
3611         {
3612             std::cout << "    [ ";
3613             for(double s : splitValues)
3614                 std::cout << s << " ";
3615             std::cout << "]" << std::endl;
3616         }
3617         std::cout << std::endl;
3618     }
3619 #endif
3620 
3621 
3622     // --------------------------------------------------------------------
3623     // ---------------- Remove duplicated split values --------------------
3624     // --------------------------------------------------------------------
3625 
3626     // Remove duplicates
3627     std::vector<             double  > selfSplitValues;
3628     std::vector< std::vector<double> > othersSplitValues(nEdges, std::vector<double>() );
3629 
3630     // Convenient struct to avoid code duplication (almost same code for self/others intersections)
3631     struct SplitValuesToClean
3632     {
3633         SplitValuesToClean(std::vector<double> & dirty, std::vector<double> & clean, double l, bool isSelf, bool isClosed) :
3634             dirty(dirty), clean(clean), l(l), isSelf(isSelf), isClosed(isClosed) {}
3635 
3636         std::vector<double> & dirty;
3637         std::vector<double> & clean;
3638         double l;
3639         bool isSelf; // a flag to handle specific code only applying to self intersections
3640         bool isClosed;
3641     };
3642 
3643     // Build vector of split values to clean
3644     std::vector<SplitValuesToClean> toClean;
3645     toClean.emplace_back(selfSplitValues_dirty, selfSplitValues, lSelf, true, false); // self split values
3646 
3647     // For each of them, compute intersections with sketched edge
3648     {
3649         int i = 0;
3650         foreach (KeyEdge * iedge, iedgesBefore)
3651         {
3652             // Avoid cleaning non-intersected existing edges
3653             if(othersSplitValues_dirty[i].size() > 0)
3654                 toClean.emplace_back(othersSplitValues_dirty[i], othersSplitValues[i], lOthers[i], false, iedge->isClosed());
3655             ++i;
3656         }
3657     }
3658 
3659     // Clean all split values
3660     // This is done by "clustering" together nearby split values (within specified tolerance)
3661     // and replacing them by a single new split value, averaging the clustered old values
3662     for(auto splitValues : toClean)
3663     {
3664         // Safety check: nothing to clean if no split values
3665         if(splitValues.dirty.size() == 0)
3666             continue;
3667 
3668         // Variables to cluster split values together
3669         int nMean = 0;  // current number of split values in current cluster
3670         double sum = 0; // current sum    of split values in current cluster
3671 
3672         // Get and add first split value
3673         double firstSplitValue;
3674         if(splitValues.isClosed)
3675         {
3676             //qDebug() << "isClosed";
3677             firstSplitValue = splitValues.dirty.front();
3678         }
3679         else
3680             firstSplitValue = 0;
3681         splitValues.clean << firstSplitValue;
3682 
3683         // Get last split value
3684         double lastSplitValue;
3685         if(splitValues.isClosed)
3686             lastSplitValue = firstSplitValue + splitValues.l;
3687         else
3688             lastSplitValue = splitValues.l;
3689 
3690         // Main loop over all split values
3691         for(double s : splitValues.dirty)
3692         {
3693             // ignore all split values too close to start split value
3694             if(s < firstSplitValue + tolerance)
3695                 continue;
3696 
3697             // ignore all split values too close to end split value
3698             if(s > lastSplitValue - tolerance)
3699                 break;
3700 
3701             if(nMean == 0) // Add first split value to first cluster
3702             {
3703                 nMean = 1;
3704                 sum = s;
3705             }
3706             else           // Check if next split value must be appended to the current cluster
3707             {              // or inserted as the first split value of a new cluster
3708                 // the mean value that would be added if we stop contributing to this cluster
3709                 double mean = sum/nMean;
3710 
3711                 // test if adding the next value would infer a distance greater than tol or not
3712                 if(s > mean + tolerance)
3713                 {
3714                     // If yes, then insert the mean
3715                     splitValues.clean << mean;
3716 
3717                     // And recurse: create a new cluster
3718                     nMean = 1;
3719                     sum = s;
3720                 }
3721                 else
3722                 {
3723                     // Contribute to the mean
3724                     nMean++;
3725                     sum += s;
3726                 }
3727             }
3728         }
3729         // No more split values to process, add the one from last cluster
3730         if(nMean > 0)
3731             splitValues.clean << sum/nMean;
3732 
3733         // Add last split value
3734         splitValues.clean << lastSplitValue;
3735     }
3736 
3737 #if MYDEBUG
3738     /////////  Print cleaned split values  /////////
3739     std::cout << "Cleaning split values:" << std::endl;
3740     std::cout << "  Self split values = [ ";
3741     for(double s : selfSplitValues)
3742         std::cout << s << " ";
3743     std::cout << "] -- length = " << sketchedEdge_->length() << std::endl;
3744     std::cout << "  Others split values =" << std::endl;
3745     int i1 = 0;
3746     for(auto splitValues : othersSplitValues)
3747     {
3748         std::cout << "    [ ";
3749         for(double s : splitValues)
3750             std::cout << s << " ";
3751         std::cout << "] -- length = " << sketchedEdges[i1].length() << std::endl;
3752         i1++;
3753     }
3754     std::cout << std::endl;
3755 #endif
3756 
3757 
3758     // --------------------------------------------------------------------
3759     // ---- Compute node positions corresponding to split values ----------
3760     // --------------------------------------------------------------------
3761 
3762     struct SplitNodes {
3763 
3764         int size() const { return nSelf + nExisting; }
3765         EdgeSample operator[] (int i)
3766         {
3767             if(i<nSelf)
3768                 return self[i];
3769             else
3770             {
3771                 i -= nSelf;
3772                 return existing[i];
3773             }
3774         }
3775 
3776         int nSelf;
3777         std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > self;
3778 
3779         int nExisting;
3780         std::vector<EdgeSample,Eigen::aligned_allocator<EdgeSample> > existing;
3781         std::vector<KeyVertex *> existingNodes;
3782 
3783     } splitNodes;
3784 
3785     // Nodes created via selfIntersections
3786     splitNodes.nSelf = selfSplitValues.size();
3787     splitNodes.self.reserve(splitNodes.nSelf);
3788     for(int i=0; i<splitNodes.nSelf; ++i)
3789         splitNodes.self.push_back(sketchedEdge_->curve()(selfSplitValues[i]));
3790 
3791     // Existing nodes, at the end of intersected other curves
3792     { // create scope so that i stays local
3793         int i=0;
3794         foreach(KeyEdge * iedge, iedgesBefore) // TODO: generalize to Animated Nodes as well
3795         {
3796             if(othersSplitValues[i].size() > 0 && !iedge->isClosed())
3797             {
3798                 // todo: be careful!! Potentially add several times the same node here!!!
3799                 splitNodes.existing << sketchedEdges[i].start();
3800                 splitNodes.existingNodes << iedge->startVertex();
3801 
3802                 splitNodes.existing << sketchedEdges[i].end();
3803                 splitNodes.existingNodes << iedge->endVertex();
3804             }
3805             i++;
3806         }
3807     }
3808 
3809     // Existing nodes, close to end nodes.
3810     {
3811         EdgeSample startVertex = sketchedEdge_->curve().start();
3812         EdgeSample endVertex = sketchedEdge_->curve().end();
3813         foreach(KeyVertex * v, instantVertices(timeInteractivity_))
3814         {
3815             // todo: be careful!! Potentially add several times the same node here!!!
3816             EdgeSample sv = startVertex;
3817             sv.setX(v->pos()[0]);
3818             sv.setY(v->pos()[1]);
3819             if(sv.distanceTo(startVertex) < tolerance)
3820             {
3821                 splitNodes.existing << sv;
3822                 splitNodes.existingNodes << v;
3823             }
3824             else
3825             {
3826                 sv = endVertex;
3827                 sv.setX(v->pos()[0]);
3828                 sv.setY(v->pos()[1]);
3829                 if(sv.distanceTo(endVertex) < tolerance)
3830                 {
3831                     splitNodes.existing << sv;
3832                     splitNodes.existingNodes << v;
3833                 }
3834             }
3835         }
3836     }
3837 
3838     // Vertices created via intersection with other curves
3839     // Warning: this step destroy some edges in iedgesBefore, but without removing
3840     // them form
3841     {
3842         int i = 0;
3843         foreach(KeyEdge * oldEdge, iedgesBefore)
3844         {
3845             if(othersSplitValues[i].size() > 2 || (oldEdge->isClosed() && othersSplitValues[i].size() > 1))
3846                 // avoid splitting if the cleaned split values are [0,l]
3847                 // unless it's a loop and split values can be [s,s+l]
3848             {
3849                 // Split the edge
3850                 SplitInfo info = cutEdgeAtVertices_(oldEdge, othersSplitValues[i]);
3851                 foreach(KeyVertex * ivertex, info.newVertices)
3852                 {
3853                     splitNodes.existing << EdgeSample(ivertex->pos()[0], ivertex->pos()[1]);
3854                     splitNodes.existingNodes << ivertex;
3855                 }
3856             }
3857             i++;
3858         }
3859 
3860         // From this point, iedgesBefore must not be used, since some
3861         // of its edges are deleted
3862         iedgesBefore.clear();
3863     }
3864     splitNodes.nExisting = splitNodes.existing.size();
3865 
3866 
3867 #if MYDEBUG
3868     /////////  Print position of BasivVertex  /////////
3869     std::cout << "  Positions = [ ";
3870     for(int i=0; i<splitNodes.size(); ++i)
3871         std::cout << "(" << splitNodes[i].x() << "," << splitNodes[i].y() << ") ";
3872     std::cout << "]" << std::endl;
3873     std::cout << std::endl;
3874 #endif
3875 
3876 
3877     // --------------------------------------------------------------------
3878     // ------------------- Create 2D clustering graph ---------------------
3879     // --------------------------------------------------------------------
3880 
3881     // Create graph where nodes are linked by an edge iff their 2D euclidean distance is < tol
3882     // The graph is represented as an adjacency list
3883     // Initialize adj list
3884     int nSplit = splitNodes.size();
3885     std::vector< std::vector<int> > neighbours(nSplit, std::vector<int>());
3886 
3887     // feed adj list: here, room for optimization from n^2 to n log(n) by sorting and swipe line algos
3888     // in practice, n is rarely gonna exceeding 10, so... not a serious concern for now
3889     for(int i=0; i<nSplit; ++i)
3890         for(int j=i+1; j<nSplit; ++j)
3891         {
3892             double d = splitNodes[i].distanceTo(splitNodes[j]);
3893             if(d<tolerance)
3894             {
3895                 neighbours[i].push_back(j);
3896                 neighbours[j].push_back(i);
3897             }
3898         }
3899 
3900     // Aux structure associated with each cluster.
3901     // It creates a new Node() if no existing node exists in the cluster.
3902     // Then, for each i in the clusters, return the corresponding Node *.
3903     //
3904     // Note: the comment above is obsolete, now the cluster itself has no
3905     //       logic, just store the data, and what is written above is not
3906     //       done by the cluster but by the algorithm just after
3907     //
3908     struct Cluster
3909     {
3910         // members
3911         std::vector<int> indices;
3912 
3913         // member methods
3914         int size() const { return indices.size(); }
3915         Cluster & operator<<(int i) { indices << i; return *this; }
3916     };
3917 
3918     // Compute connected components: those are the clusters
3919     std::vector< Cluster > clusters;
3920     std::vector<bool> marked(nSplit, false);
3921     for(int startNode=0; startNode<nSplit; ++startNode)
3922     {
3923         if(!marked[startNode])
3924         {
3925             // create a new cluster
3926             clusters.emplace_back();
3927             Cluster & cluster = clusters.back();
3928 
3929             // insert the first node in the cluster
3930             cluster << startNode;
3931             marked[startNode] = true;
3932 
3933             // fill the connected components
3934             std::queue<int> q;
3935             q.push(startNode);
3936             while(!q.empty())
3937             {
3938                 int node = q.front();
3939                 q.pop();
3940                 int nNeighbours = neighbours[node].size();
3941                 for(int i=0; i<nNeighbours; ++i)
3942                 {
3943                     int neighbour = neighbours[node][i];
3944                     if(!marked[neighbour])
3945                     {
3946                         marked[neighbour] = true;
3947                         q.push(neighbour);
3948                         cluster << neighbour;
3949                     }
3950                 }
3951             }
3952         }
3953     }
3954     int nClusters= clusters.size();
3955 
3956 #if MYDEBUG
3957     /////////  Print clusters  /////////
3958     std::cout << "Clustering:" << std::endl;
3959     std::cout << "  Self nodes indices = [ 0 .. " << splitNodes.nSelf-1 << " ]" << std::endl;
3960     std::cout << "  Existing nodes indices = [ ";
3961     if(nSplit-1 < splitNodes.nSelf)
3962         std::cout << "]" << std::endl;
3963     else if(nSplit-1 == splitNodes.nSelf)
3964         std::cout << splitNodes.nSelf << " ]" << std::endl;
3965     else
3966         std::cout << splitNodes.nSelf << " .. " << nSplit-1 << " ]" << std::endl;
3967     std::cout << "  Clusters: ";
3968     for(int k=0; k<nClusters; ++k)
3969     {
3970         std::cout << "[ ";
3971         int nConnected = clusters[k].size();
3972         for(int i=0; i<nConnected; ++i)
3973             std::cout << clusters[k].indices[i] << " ";
3974         std::cout << "] ";
3975     }
3976     std::cout << std::endl;
3977 #endif
3978 
3979 
3980     // --------------------------------------------------------------------
3981     // ----------- Detect when the sketched edge must be a loop -----------
3982     // --------------------------------------------------------------------
3983 
3984     // TODO: Change the following code. Instead, we should detect when the first and last vertex of the sketched edge must be destroyed
3985 
3986     // I suppose no cluster has no self node in it. The reason is that if
3987     // an existing node is taken into account in this algo, then it has split
3988     // the sketched curve too, or will be use as start/end vertex.
3989     //
3990     // Edit: I think the above is wrong, since end points of intersected edges
3991     //       are automatically added as nodes
3992     //
3993     // Hence, all clusters have at least one self node. In the case of a loop,
3994     // this mean there is only one cluster, made of two self nodes.
3995     bool isClosed = false;
3996     int nSelf = splitNodes.nSelf;
3997     if(nSelf == 2     &&
3998             nClusters == 1 &&
3999             clusters[0].size() == 2 )
4000     {
4001         isClosed = true;
4002     }
4003 
4004 
4005     // --------------------------------------------------------------------
4006     // ---------------------- Process the clusters ------------------------
4007     // --------------------------------------------------------------------
4008 
4009     // From the indices in the cluster, compute:
4010     //   - how many of them are existing nodes
4011     //   - if zero: compute the mean, create new node
4012     //   - if one: basically do nothing
4013     //   - if more than one: for each index, compute closest existing node in cluster
4014 
4015     // Note: nSelfSplitValues = nSelfSplitNodes, by definition of nSelfSplitNodes
4016     // The actual nodes corresponding to the
4017     // self interections, already existing or newly created
4018     std::vector<KeyVertex*> selfNodes;
4019     selfNodes.resize(nSelf);
4020 
4021     if(isClosed)
4022     {
4023         // nothing to do
4024     }
4025     else
4026     {
4027         for(int i=0; i<nClusters; ++i)
4028         {
4029             Cluster & cluster = clusters[i];
4030 
4031             // How many existing nodes are in this cluster?
4032             // Who are they?
4033             //
4034             // todo? : what if no self nodes are in this cluster? Is this even possible? likely?
4035             //
4036             std::vector<KeyVertex *> existing;
4037             for(int i : cluster.indices)
4038                 if(i>=nSelf)
4039                     existing << splitNodes.existingNodes[i-nSelf];
4040 
4041             // If none of them, compute the mean vertex
4042             // and create a new node
4043             if(existing.size() == 0)
4044             {
4045                 // Create the new node
4046                 KeyVertex * newNode = newKeyVertex(timeInteractivity_);
4047 
4048                 // compute node position as mean of all self intersections
4049                 Eigen::Vector2d mean(0,0);
4050                 int n = cluster.size(); // we know size() > 0
4051                 for(int i=0; i<n; ++i)
4052                 {
4053                     int idx = cluster.indices[i];
4054 
4055                     // contributes to mean
4056                     mean += Eigen::Vector2d(splitNodes[idx].x(), splitNodes[idx].y());
4057 
4058                     // set the new node to be my node
4059                     selfNodes[idx] = newNode;
4060                 }
4061                 // Set node position
4062                 mean /= (double) n;
4063                 newNode->setPos(mean);
4064             }
4065             else if (existing.size() == 1)
4066             {
4067                 for(int i : cluster.indices)
4068                     if(i<nSelf)
4069                         selfNodes[i] = existing.front();
4070             }
4071             else
4072             {
4073                 // for now, just use first one instead of the closest one. Todo: improve this
4074                 for(int i : cluster.indices)
4075                     if(i<nSelf)
4076                         selfNodes[i] = existing.front();
4077 
4078             }
4079         }
4080     }
4081 
4082     // --------------------------------------------------------------------
4083     // -------------------- Split the drawn curve -------------------------
4084     // --------------------------------------------------------------------
4085 
4086     std::vector<SketchedEdge,Eigen::aligned_allocator<SketchedEdge> > curves;
4087     if(!isClosed)
4088         curves = sketchedEdge_->curve().split(selfSplitValues);
4089 
4090     // Create topology and retarget drawn curve
4091     if(isClosed)
4092     {
4093         // retarget curve
4094         EdgeSample vStart = sketchedEdge_->curve().start();
4095         EdgeSample vEnd = sketchedEdge_->curve().end();
4096         double meanX = 0.5 * (vStart.x() + vEnd.x());
4097         double meanY = 0.5 * (vStart.y() + vEnd.y());
4098         vStart.setX(meanX);
4099         vStart.setY(meanY);
4100         vEnd.setX(meanX);
4101         vEnd.setY(meanY);
4102         sketchedEdge_->curve().setEndPoints(vStart, vEnd);
4103 
4104         // Create geometry out of it
4105         EdgeGeometry * geometry = new LinearSpline(sketchedEdge_->curve(), true);
4106         KeyEdge * iedge = newKeyEdge(timeInteractivity_, geometry);
4107 
4108         // if planar map mode, the loop can "cut" a face
4109         if(global()->planarMapMode())
4110         {
4111             if(hoveredFaceOnMousePress_)
4112             {
4113                 // Cut face with loop
4114                 KeyEdgeSet loopCycle;
4115                 loopCycle << iedge;
4116                 Cycle newCycle(loopCycle);
4117                 hoveredFaceOnMousePress_->addCycle(newCycle);
4118                 KeyFace * iFace = newKeyFace(loopCycle);
4119                 iFace->setColor(hoveredFaceOnMousePress_->color());
4120                 InbetweenFaceSet sfacesbefore = hoveredFaceOnMousePress_->temporalStarBefore();
4121                 foreach(InbetweenFace * sface, sfacesbefore)
4122                     sface->addAfterFace(iFace);
4123                 InbetweenFaceSet sfacesafter = hoveredFaceOnMousePress_->temporalStarAfter();
4124                 foreach(InbetweenFace * sface, sfacesafter)
4125                     sface->addBeforeFace(iFace);
4126             }
4127         }
4128     }
4129     else
4130     {
4131         // if planar map mode, the first and last vertices can "cut" faces
4132         // by being added as Steiner cycles
4133         if(global()->planarMapMode() && nSelf>0)
4134         {
4135             KeyVertex * firstVertex = selfNodes[0];
4136             KeyVertex * lastVertex = selfNodes[nSelf-1];
4137 
4138             if(hoveredFaceOnMousePress_ &&
4139                     !(hoveredFaceOnMousePress_->spatialBoundary().contains(firstVertex)))
4140             {
4141                 // Cut face with Steiner verte
4142                 Cycle newCycle(firstVertex);
4143                 hoveredFaceOnMousePress_->addCycle(newCycle);
4144             }
4145             if(hoveredFaceOnMouseRelease_ && (firstVertex != lastVertex) &&
4146                     !(hoveredFaceOnMouseRelease_->spatialBoundary().contains(lastVertex)))
4147             {
4148                 // Cut face with Steiner vertex
4149                 Cycle newCycle(lastVertex);
4150                 hoveredFaceOnMouseRelease_->addCycle(newCycle);
4151             }
4152         }
4153 
4154 
4155         for(int i=0; i<nSelf-1; ++i)
4156         {
4157             // end nodes
4158             KeyVertex * startNode = selfNodes[i];
4159             KeyVertex * endNode = selfNodes[i+1];
4160 
4161             // retarget curve
4162             EdgeSample vStart = curves[i].start();
4163             vStart.setX(startNode->pos()[0]);
4164             vStart.setY(startNode->pos()[1]);
4165             EdgeSample vEnd = curves[i].end();
4166             vEnd.setX(endNode->pos()[0]);
4167             vEnd.setY(endNode->pos()[1]);
4168             curves[i].setEndPoints(vStart, vEnd);
4169 
4170             // Create geometry out of it
4171             EdgeGeometry * geometry = new LinearSpline(curves[i]);
4172             KeyEdge * iedge = 0;
4173             if(geometry->length() > tolerance)
4174                 iedge = newKeyEdge(timeInteractivity_, startNode, endNode, geometry);
4175 
4176             // if planar map mode, cut a potential face underneath
4177             if(iedge && global()->planarMapMode())
4178             {
4179                 // find a face to cut
4180                 KeyFaceSet startFaces = startNode->spatialStar();
4181                 KeyFaceSet endFaces = endNode->spatialStar();
4182                 KeyFaceSet faces = startFaces;
4183                 faces.intersect(endFaces);
4184                 if(useFaceToConsiderForCutting)
4185                     faces.intersect(facesToConsiderForCutting_);
4186 
4187                 if(!faces.isEmpty())
4188                 {
4189                     // For now, just use the first face
4190                     KeyFace * face = *faces.begin();
4191 
4192                     // Cut the face by the new edge
4193                     CutFaceFeedback feedback;
4194                     cutFace_(face,iedge, &feedback);
4195                     if(useFaceToConsiderForCutting)
4196                     {
4197                         foreach(KeyFace * face, feedback.deletedFaces)
4198                             facesToConsiderForCutting_.remove(face);
4199                         foreach(KeyFace * face, feedback.newFaces)
4200                             facesToConsiderForCutting_.insert(face);
4201                     }
4202                 }
4203             }
4204         }
4205     }
4206 }
4207 
4208 // --------------------- Sculpting ------------------------
4209 
updateSculpt(double x,double y,Time time)4210 void VAC::updateSculpt(double x, double y, Time time)
4211 {
4212     double radius = global()->sculptRadius();
4213     timeInteractivity_ = time;
4214     KeyEdgeList iedges = instantEdges(timeInteractivity_);
4215     double minD = std::numeric_limits<double>::max();
4216     sculptedEdge_ = 0;
4217     foreach(KeyEdge * iedge, iedges)
4218     {
4219         double d = iedge->updateSculpt(x, y, radius);
4220         if(d<radius && d<minD)
4221         {
4222             minD = d;
4223             sculptedEdge_ = iedge;
4224         }
4225     }
4226 }
4227 
beginSculptDeform(double x,double y)4228 void VAC::beginSculptDeform(double x, double y)
4229 {
4230     if(sculptedEdge_)
4231     {
4232         sculptedEdge_->beginSculptDeform(x, y);
4233     }
4234 }
4235 
continueSculptDeform(double x,double y)4236 void VAC::continueSculptDeform(double x, double y)
4237 {
4238     if(sculptedEdge_)
4239     {
4240         sculptedEdge_->continueSculptDeform(x, y);
4241         //emit changed();
4242     }
4243 }
4244 
endSculptDeform()4245 void VAC::endSculptDeform()
4246 {
4247     if(sculptedEdge_)
4248     {
4249         sculptedEdge_->endSculptDeform();
4250         //emit changed(); // done manually by View, after calling updatePicking(newX, newY)
4251         emit checkpoint();
4252     }
4253 }
4254 
beginSculptEdgeWidth(double x,double y)4255 void VAC::beginSculptEdgeWidth(double x, double y)
4256 {
4257     if(sculptedEdge_)
4258     {
4259         sculptedEdge_->beginSculptEdgeWidth(x, y);
4260     }
4261 }
4262 
continueSculptEdgeWidth(double x,double y)4263 void VAC::continueSculptEdgeWidth(double x, double y)
4264 {
4265     if(sculptedEdge_)
4266     {
4267         sculptedEdge_->continueSculptEdgeWidth(x, y);
4268         //emit changed();
4269     }
4270 }
4271 
endSculptEdgeWidth()4272 void VAC::endSculptEdgeWidth()
4273 {
4274     if(sculptedEdge_)
4275     {
4276         sculptedEdge_->endSculptEdgeWidth();
4277         //emit changed(); // done manually by View, after calling updatePicking(newX, newY)
4278         emit checkpoint();
4279     }
4280 }
4281 
beginSculptSmooth(double,double)4282 void VAC::beginSculptSmooth(double /*x*/, double /*y*/)
4283 {
4284     /* useless
4285         if(sculptedEdge_)
4286         {
4287             sculptedEdge_->beginSculptSmooth(x, y);
4288         }
4289         */
4290 }
4291 
continueSculptSmooth(double x,double y)4292 void VAC::continueSculptSmooth(double x, double y)
4293 {
4294     updateSculpt(x, y, timeInteractivity_);
4295     if(sculptedEdge_)
4296     {
4297         // WARNING: sculptedEdge_ may have changed, and then sculptedEdge_->continueSculptSmooth(x, y);
4298         //          called without sculptedEdge_->beginSculptSmooth(x, y); called beforehand
4299         sculptedEdge_->continueSculptSmooth(x, y);
4300         //emit changed();
4301     }
4302 }
4303 
endSculptSmooth()4304 void VAC::endSculptSmooth()
4305 {
4306     if(sculptedEdge_)
4307     {
4308         sculptedEdge_->endSculptSmooth();
4309         //emit changed(); // done manually by View, after calling updatePicking(newX, newY)
4310         emit checkpoint();
4311     }
4312 }
4313 
4314 
4315 // ------------- User action: connect objects -------------
4316 
4317 
4318 
inbetweenVertices_(KeyVertex * v1,KeyVertex * v2)4319 InbetweenVertex * VAC::inbetweenVertices_(KeyVertex * v1, KeyVertex * v2)
4320 {
4321     InbetweenVertex * stv = newInbetweenVertex(v1, v2);
4322     stv->setColor(v1->color());
4323     return stv;
4324 }
4325 
4326 namespace
4327 {
4328 
findAnimatedVertexRec(KeyVertex * visitedVertex,KeyVertex * targetVertex,QMap<KeyVertex *,InbetweenVertex * > & next)4329 void findAnimatedVertexRec(KeyVertex * visitedVertex, KeyVertex * targetVertex, QMap<KeyVertex*,InbetweenVertex*> & next)
4330 {
4331     // If already visited, do nothing
4332     if(!next.contains(visitedVertex))
4333     {
4334         if(visitedVertex->time() >= targetVertex->time())
4335         {
4336             // Terminal case 1: fail
4337             next[visitedVertex] = 0;
4338         }
4339         else
4340         {
4341             InbetweenVertexSet svs = visitedVertex->temporalStarAfter();
4342             foreach(InbetweenVertex * sv, svs)
4343             {
4344                 KeyVertex * afterVertex = sv->afterVertex();
4345                 if(afterVertex == targetVertex)
4346                 {
4347                     // Terminal case 2: success
4348                     next[visitedVertex] = sv;
4349                     break;
4350                 }
4351                 else
4352                 {
4353                     // Recursion
4354                     findAnimatedVertexRec(afterVertex, targetVertex,next);
4355                     if(next[afterVertex])
4356                     {
4357                         // Recursive case 1: success
4358                         next[visitedVertex] = sv;
4359                         break;
4360                     }
4361                 }
4362             }
4363 
4364             // Recursive case 2: fail
4365             if(!next.contains(visitedVertex))
4366             {
4367                 next[visitedVertex] = 0;
4368             }
4369         }
4370     }
4371 }
4372 
findOrCreateAnimatedVertex(VAC * vac,KeyVertex * v1,KeyVertex * v2)4373 AnimatedVertex findOrCreateAnimatedVertex(VAC * vac, KeyVertex * v1, KeyVertex * v2)
4374 {
4375     assert(v1->time() != v2->time());
4376 
4377     if(v1->time() > v2->time())
4378         std::swap(v1,v2);
4379 
4380     QMap<KeyVertex*,InbetweenVertex*> next;
4381     findAnimatedVertexRec(v1,v2,next);
4382 
4383     InbetweenVertexList res;
4384 
4385     // Success case: get the animated vertex made of existing inbetween edges
4386     KeyVertex * v = v1;
4387     while( (v != v2) && (next[v]))
4388     {
4389         InbetweenVertex * sv = next[v];
4390         res << sv;
4391         v = sv->afterVertex();
4392     }
4393 
4394     // Fail case: create new inbetween edge
4395     if(res.isEmpty())
4396     {
4397         res << vac->newInbetweenVertex(v1, v2);
4398     }
4399 
4400     return AnimatedVertex(res);
4401 }
4402 
4403 }
4404 
inbetweenEdges_(KeyEdge * e1,KeyEdge * e2)4405 InbetweenEdge * VAC::inbetweenEdges_(KeyEdge * e1, KeyEdge * e2)
4406 {
4407     // closed edges
4408     if(e1->isClosed() && e2->isClosed())
4409     {
4410         KeyHalfedge h1(e1,true);
4411         KeyHalfedge h2(e2,haveSameOrientation(e1,e2));
4412         Cycle cycle1(QList<KeyHalfedge>() << h1);
4413         Cycle cycle2(QList<KeyHalfedge>() << h2);
4414 
4415         InbetweenEdge * ste = newInbetweenEdge(cycle1,cycle2);
4416         ste->setColor(e1->color());
4417 
4418         return ste;
4419     }
4420     // open edges
4421     else if(!e1->isClosed() && !e2->isClosed())
4422     {
4423         KeyHalfedge h1(e1,true);
4424         KeyHalfedge h2(e2,haveSameOrientation(e1,e2));
4425         KeyVertex * vstart1 = h1.startVertex();
4426         KeyVertex * vstart2 = h2.startVertex();
4427         KeyVertex * vend1 = h1.endVertex();
4428         KeyVertex * vend2 = h2.endVertex();
4429         Path path1(QList<KeyHalfedge>() << h1);
4430         Path path2(QList<KeyHalfedge>() << h2);
4431         AnimatedVertex avstart = findOrCreateAnimatedVertex(this,vstart1,vstart2);
4432         AnimatedVertex avend = findOrCreateAnimatedVertex(this,vend1,vend2);
4433 
4434         InbetweenEdge * ste = newInbetweenEdge(path1,path2,avstart,avend);
4435         ste->setColor(e1->color());
4436 
4437         return ste;
4438     }
4439     else // one closed edge and one open edge
4440     {
4441         qDebug("Operation aborted: you tried to inbetween a closed curve to an open path. This is not possible. Please split the closed curve before");
4442         return 0;
4443     }
4444 }
4445 
inbetweenSelection()4446 void VAC::inbetweenSelection()
4447 {
4448     // ---- get selected key cells ----
4449 
4450     KeyCellList list = selectedCells();
4451 
4452     // separate them into two lists with different times
4453     if(list.size() == 0 )
4454         return;
4455     Time t1 = list[0]->time();
4456     Time t2;
4457     bool ok = false;
4458     foreach(KeyCell * object, list)
4459     {
4460         if(!ok) // didn't find t2 yet
4461         {
4462             if(object->time() != t1) // found t2
4463             {
4464                 t2 = object->time();
4465                 ok = true;
4466             }
4467         }
4468         else // already found t2
4469         {
4470             if(object->time() != t1 && object->time() != t2) // found some t3
4471             {
4472                 qDebug("Inbetweening: Selected objects span at least three different frames. Abort due to ambiguity.");
4473                 return;
4474             }
4475         }
4476     }
4477     if(!ok)
4478     {
4479         qDebug("Inbetweening: Selected objects are all contained in the same frame, nothing to inbetween.");
4480         return;
4481     }
4482     if(t1>t2)
4483     {
4484         Time aux = t1;
4485         t1=t2;
4486         t2=aux;
4487     }
4488     KeyCellList list1;
4489     KeyCellList list2;
4490     foreach(KeyCell * object, list)
4491     {
4492         if(object->time() == t1)
4493             list1 << object;
4494         if(object->time() == t2)
4495             list2 << object;
4496     }
4497     // partition lists into vertices/edges/faces
4498     KeyVertexList vertices1 = list1;
4499     KeyVertexList vertices2 = list2;
4500     KeyEdgeList edges1 = list1;
4501     KeyEdgeList edges2 = list2;
4502     KeyFaceList faces1 = list1;
4503     KeyFaceList faces2 = list2;
4504 
4505 
4506     // ---------------- connect two key vertices --------------------
4507 
4508     if(list1.size() == 1 && list1[0]->toKeyVertex() &&
4509             list2.size() == 1 && list2[0]->toKeyVertex())
4510     {
4511         KeyVertex * v1 = list1[0]->toKeyVertex();
4512         KeyVertex * v2 = list2[0]->toKeyVertex();
4513         inbetweenVertices_(v1, v2);
4514     }
4515 
4516 
4517     // ---------------- connect two key edges --------------------
4518 
4519     else if(list1.size() == 1 && list1[0]->toKeyEdge() &&
4520             list2.size() == 1 && list2[0]->toKeyEdge())
4521     {
4522         KeyEdge * e1 = list1[0]->toKeyEdge();
4523         KeyEdge * e2 = list2[0]->toKeyEdge();
4524         inbetweenEdges_(e1,e2);
4525     }
4526 
4527 
4528     // ---------------- connect one key vertex to one key edge (Grow) --------------------
4529 
4530     else if(list1.size() == 1 && list1[0]->toKeyVertex() &&
4531             list2.size() == 1 && list2[0]->toKeyEdge())
4532     {
4533         KeyVertex * v1 = list1[0]->toKeyVertex();
4534         KeyEdge * e2 = list2[0]->toKeyEdge();
4535         // closed edge
4536         if(e2->isClosed())
4537         {
4538             KeyHalfedge h2(e2,true);
4539             Cycle cycle1(v1);
4540             Cycle cycle2(QList<KeyHalfedge>() << h2);
4541             newInbetweenEdge(cycle1,cycle2);
4542         }
4543         // open edges
4544         else
4545         {
4546             Path path1(v1);
4547             KeyHalfedge h2(e2,true);
4548             KeyVertex * vstart2 = h2.startVertex();
4549             KeyVertex * vend2 = h2.endVertex();
4550             Path path2(QList<KeyHalfedge>() << h2);
4551             AnimatedVertex avstart = findOrCreateAnimatedVertex(this,v1,vstart2);
4552             AnimatedVertex avend = findOrCreateAnimatedVertex(this,v1,vend2);
4553             InbetweenEdge * ste = newInbetweenEdge(path1,path2,avstart,avend);
4554             ste->setColor(e2->color());
4555         }
4556     }
4557 
4558     // ---------------- connect one key edge to one key vertex (Shrink) --------------------
4559 
4560     else if(list1.size() == 1 && list1[0]->toKeyEdge() &&
4561             list2.size() == 1 && list2[0]->toKeyVertex())
4562     {
4563         KeyEdge * e1 = list1[0]->toKeyEdge();
4564         KeyVertex * v2 = list2[0]->toKeyVertex();
4565         // closed edge
4566         if(e1->isClosed())
4567         {
4568             KeyHalfedge h1(e1,true);
4569             Cycle cycle1(QList<KeyHalfedge>() << h1);
4570             Cycle cycle2(v2);
4571             newInbetweenEdge(cycle1,cycle2);
4572         }
4573         // open edges
4574         else
4575         {
4576             Path path2(v2);
4577             KeyHalfedge h1(e1,true);
4578             KeyVertex * vstart1 = h1.startVertex();
4579             KeyVertex * vend1 = h1.endVertex();
4580             Path path1(QList<KeyHalfedge>() << h1);
4581             AnimatedVertex avstart = findOrCreateAnimatedVertex(this,vstart1,v2);
4582             AnimatedVertex avend = findOrCreateAnimatedVertex(this,vend1,v2);
4583             InbetweenEdge * ste = newInbetweenEdge(path1,path2,avstart,avend);
4584             ste->setColor(e1->color());
4585         }
4586     }
4587 
4588     // ---------------- General case: connect several edges to several edges --------------------
4589 
4590     else if(faces1.isEmpty() && faces2.isEmpty())
4591     {
4592         bool abort = false;
4593 
4594         // Try to convert selection at time t1 into a cycle or/and a path
4595         Cycle cycle1;
4596         Path path1;
4597         if(edges1.isEmpty())
4598         {
4599             if(vertices1.size() == 1)
4600             {
4601                 cycle1 = Cycle(vertices1[0]);
4602                 path1 = Path(vertices1[0]);
4603             }
4604             else
4605             {
4606                 abort = true;
4607             }
4608         }
4609         else
4610         {
4611             KeyEdgeSet edges1Set = edges1;
4612 
4613             ProperCycle properCycle1(edges1Set);
4614             if(properCycle1.isValid())
4615             {
4616                 cycle1 = Cycle(properCycle1);
4617                 path1 = Path(properCycle1);
4618             }
4619             else
4620             {
4621                 ProperPath properPath1(edges1Set);
4622                 if(properPath1.isValid())
4623                     path1 = Path(properPath1);
4624             }
4625         }
4626 
4627         // Try to convert selection at time t2 into a cycle or/and a path
4628         Cycle cycle2;
4629         Path path2;
4630         if(edges2.isEmpty())
4631         {
4632             if(vertices2.size() == 1)
4633             {
4634                 cycle2 = Cycle(vertices2[0]);
4635                 path2 = Path(vertices2[0]);
4636             }
4637             else
4638             {
4639                 abort = true;
4640             }
4641         }
4642         else
4643         {
4644             KeyEdgeSet edges2Set = edges2;
4645 
4646             ProperCycle properCycle2(edges2Set);
4647             if(properCycle2.isValid())
4648             {
4649                 cycle2 = Cycle(properCycle2);
4650                 path2 = Path(properCycle2);
4651             }
4652             else
4653             {
4654                 ProperPath properPath2(edges2Set);
4655                 if(properPath2.isValid())
4656                     path2 = Path(properPath2);
4657             }
4658         }
4659 
4660         // Decide if we should create a closed inbetween edge or an open inbetween edge,
4661         // with priority for closed inbetween edge, if possible. If none possible, abort
4662         // for now. In the future, use a smart optimization to optimize inbetweening for
4663         // arbitrary selection
4664         if(!abort)
4665         {
4666             if(cycle1.isValid() && cycle2.isValid())
4667             {
4668                 // Choose cycle orientation (TODO: use a heuristic instead of settings checkbox)
4669                 // TODO: choose cycle orientation, pick best offset
4670                 if(DevSettings::getBool("inverse direction"))
4671                     cycle1 = cycle1.reversed();
4672 
4673                 // Create closed inbetween edge
4674                 newInbetweenEdge(cycle1,cycle2);
4675 
4676 
4677             }
4678             else if(path1.isValid() && path2.isValid())
4679             {
4680                 // Choose cycle orientation (TODO: use a heuristic instead of settings checkbox)
4681                 if(DevSettings::getBool("inverse direction"))
4682                     path1 = path1.reversed();
4683 
4684                 // Create open inbetween edge
4685                 KeyVertex * vstart1 = path1.startVertex();
4686                 KeyVertex * vstart2 = path2.startVertex();
4687                 KeyVertex * vend1 = path1.endVertex();
4688                 KeyVertex * vend2 = path2.endVertex();
4689                 InbetweenVertex * svstart = 0;
4690                 InbetweenVertexSet vstartAfter = vstart1->temporalStarAfter();
4691                 foreach(InbetweenVertex * sv, vstartAfter)
4692                     if(sv->afterVertex() == vstart2)
4693                         svstart = sv;
4694                 if(!svstart)
4695                     svstart = newInbetweenVertex(vstart1, vstart2);
4696                 InbetweenVertex * svend = 0;
4697                 if(vstart1 == vend1 && vstart2 == vend2)
4698                     svend = svstart;
4699                 if(!svend)
4700                 {
4701                     InbetweenVertexSet vendAfter = vend1->temporalStarAfter();
4702                     foreach(InbetweenVertex * sv, vendAfter)
4703                         if(sv->afterVertex() == vend2)
4704                             svend = sv;
4705                 }
4706                 if(!svend)
4707                     svend = newInbetweenVertex(vend1, vend2);
4708 
4709 
4710 
4711                 AnimatedVertex avstart(InbetweenVertexList() << svstart);
4712                 AnimatedVertex avend(InbetweenVertexList() << svend);
4713                 newInbetweenEdge(path1,path2,avstart,avend);
4714 
4715                 // TODO: choose cycle orientation, pick best offset of one of the paths
4716                 // is also a valid cycle.
4717             }
4718             else
4719             {
4720                 abort = true;
4721             }
4722         }
4723     }
4724 
4725     deselectAll();
4726     emit needUpdatePicking();
4727     emit changed();
4728     emit checkpoint();
4729 }
4730 
keyframeSelection()4731 void VAC::keyframeSelection()
4732 {
4733     keyframe_(selectedCells(), global()->activeTime());
4734     deselectAll();
4735 
4736     emit needUpdatePicking();
4737     emit changed();
4738     emit checkpoint();
4739 }
4740 
4741 class KeyframeHelper
4742 {
4743 public:
KeyframeHelper(InbetweenCell * sc,VAC * vac)4744     KeyframeHelper(InbetweenCell * sc, VAC * vac) :
4745         wasHovered(false),
4746         wasSelected(false),
4747         vac(vac)
4748     {
4749         wasHovered = sc->isHovered();
4750         wasSelected = sc->isSelected();
4751     }
4752 
setKeyframe(KeyCell * kc)4753     void setKeyframe(KeyCell * kc)
4754     {
4755         if(kc)
4756         {
4757             if(wasHovered)
4758                 vac->setHoveredCell(kc);
4759             if(wasSelected)
4760                 vac->addToSelection(kc,false);
4761         }
4762     }
4763 
4764 private:
4765     bool wasHovered;
4766     bool wasSelected;
4767     VAC * vac;
4768 };
4769 
keyframe_(const CellSet & cells,Time time)4770 KeyCellSet VAC::keyframe_(const CellSet & cells, Time time)
4771 {
4772     KeyCellSet keyframedCells;
4773 
4774     InbetweenCellSet inbetweenCells = cells;
4775     InbetweenCellSet relevantInbetweenCells;
4776     foreach(InbetweenCell * scell, inbetweenCells)
4777     {
4778         if(scell->exists(time))
4779             relevantInbetweenCells << scell;
4780     }
4781 
4782     InbetweenVertexSet inbetweenVertices = relevantInbetweenCells;
4783     InbetweenEdgeSet inbetweenEdges = relevantInbetweenCells;
4784     InbetweenFaceSet inbetweenFaces = relevantInbetweenCells;
4785     foreach(InbetweenVertex * svertex, inbetweenVertices)
4786     {
4787         KeyCell * keyframedCell = keyframe_(svertex,time);
4788         if(keyframedCell)
4789             keyframedCells << keyframedCell;
4790     }
4791     foreach(InbetweenEdge * sedge, inbetweenEdges)
4792     {
4793         KeyCell * keyframedCell = keyframe_(sedge,time);
4794         if(keyframedCell)
4795             keyframedCells << keyframedCell;
4796     }
4797     foreach(InbetweenFace * sface, inbetweenFaces)
4798     {
4799         KeyCell * keyframedCell = keyframe_(sface,time);
4800         if(keyframedCell)
4801             keyframedCells << keyframedCell;
4802     }
4803 
4804     return keyframedCells;
4805 }
4806 
keyframe_(InbetweenVertex * svertex,Time time)4807 KeyVertex * VAC::keyframe_(InbetweenVertex * svertex, Time time)
4808 {
4809     // Preprocess
4810     KeyframeHelper keyframHelper(svertex,this);
4811 
4812     // Create new cells
4813     KeyVertex * keyVertex = newKeyVertex(time, svertex->pos(time));
4814     InbetweenVertex * inbetweenVertexBefore = newInbetweenVertex(svertex->beforeVertex(),keyVertex);
4815     InbetweenVertex * inbetweenVertexAfter = newInbetweenVertex(keyVertex,svertex->afterVertex());
4816 
4817     // Transfer properties
4818     Color color = svertex->color();
4819     keyVertex->setColor(color);
4820     inbetweenVertexBefore->setColor(color);
4821     inbetweenVertexAfter->setColor(color);
4822 
4823     // Update incidence relationships
4824     InbetweenCellSet spatialStar = svertex->spatialStar();
4825     InbetweenEdgeSet inbetweenEdgesToUpdate = spatialStar;
4826     InbetweenFaceSet inbetweenFacesToUpdate = spatialStar;
4827     foreach(InbetweenEdge * sedge, inbetweenEdgesToUpdate)
4828     {
4829         assert(!sedge->isClosed());
4830 
4831         sedge->startAnimatedVertex_.replaceCells(svertex,inbetweenVertexBefore,inbetweenVertexAfter);
4832         sedge->endAnimatedVertex_.replaceCells(svertex,inbetweenVertexBefore,inbetweenVertexAfter);
4833 
4834         sedge->removeMeFromSpatialStarOf_(svertex);
4835         sedge->addMeToSpatialStarOf_(inbetweenVertexBefore);
4836         sedge->addMeToSpatialStarOf_(keyVertex);
4837         sedge->addMeToSpatialStarOf_(inbetweenVertexAfter);
4838 
4839         sedge->processGeometryChanged_();
4840     }
4841     foreach(InbetweenFace * sface, inbetweenFacesToUpdate)
4842     {
4843         for(int k=0; k < sface->cycles_.size(); ++k)
4844         {
4845             sface->cycles_[k].replaceInbetweenVertex(svertex,
4846                                                      inbetweenVertexBefore,keyVertex,inbetweenVertexAfter);
4847         }
4848 
4849         sface->removeMeFromSpatialStarOf_(svertex);
4850         sface->addMeToSpatialStarOf_(inbetweenVertexBefore);
4851         sface->addMeToSpatialStarOf_(keyVertex);
4852         sface->addMeToSpatialStarOf_(inbetweenVertexAfter);
4853 
4854         sface->processGeometryChanged_();
4855     }
4856 
4857     // Transfer Z-ordering of old cell to new cells
4858     zOrdering_.moveBelow(inbetweenVertexBefore, svertex);
4859     zOrdering_.moveBelow(keyVertex, svertex);
4860     zOrdering_.moveBelow(inbetweenVertexAfter, svertex);
4861 
4862     // Delete old cell
4863     deleteCell(svertex);
4864 
4865     // Postprocess
4866     keyframHelper.setKeyframe(keyVertex);
4867 
4868     // Return keyframe
4869     return keyVertex;
4870 }
4871 
4872 
keyframe_(InbetweenEdge * sedge,Time time)4873 KeyEdge * VAC::keyframe_(InbetweenEdge * sedge, Time time)
4874 {
4875     // Preprocess
4876     KeyframeHelper keyframHelper(sedge,this);
4877 
4878     // Keyframe boundary
4879     KeyVertex * startVertex = 0;
4880     KeyVertex * endVertex = 0;
4881     if(!sedge->isClosed())
4882     {
4883         VertexCellSet startVertices = sedge->startAnimatedVertex_.vertices();
4884         foreach(VertexCell * v, startVertices)
4885         {
4886             if(v->exists(time))
4887             {
4888                 startVertex = v->toKeyVertex();
4889                 if(!startVertex)
4890                 {
4891                     startVertex = keyframe_(v->toInbetweenVertex(),time);
4892                 }
4893                 break;
4894             }
4895         }
4896 
4897         VertexCellSet endVertices = sedge->endAnimatedVertex_.vertices();
4898         foreach(VertexCell * v, endVertices)
4899         {
4900             if(v->exists(time))
4901             {
4902                 endVertex = v->toKeyVertex();
4903                 if(!endVertex)
4904                 {
4905                     endVertex = keyframe_(v->toInbetweenVertex(),time);
4906                 }
4907                 break;
4908             }
4909         }
4910     }
4911 
4912     // Create new cells
4913     EdgeGeometry * geo = new LinearSpline(sedge->getSampling(time));
4914     KeyEdge * keyEdge = 0;
4915     InbetweenEdge * inbetweenEdgeBefore = 0;
4916     InbetweenEdge * inbetweenEdgeAfter = 0;
4917     if(sedge->isClosed())
4918     {
4919         // Create key cell
4920         keyEdge = newKeyEdge(time, geo);
4921 
4922         // Create boundary helpers
4923         KeyHalfedge halfedge(keyEdge,true);
4924         Cycle cycle(QList<KeyHalfedge>() << halfedge);
4925 
4926         // Create inbetween cells
4927         inbetweenEdgeBefore = newInbetweenEdge(sedge->beforeCycle(), cycle);
4928         inbetweenEdgeAfter = newInbetweenEdge(cycle, sedge->afterCycle());
4929     }
4930     else
4931     {
4932         // Create key cell
4933         keyEdge = newKeyEdge(time, startVertex, endVertex, geo);
4934 
4935         // Create boundary helpers
4936         AnimatedVertex startVertices = sedge->startAnimatedVertex_;
4937         InbetweenVertexList startVerticesBefore;
4938         InbetweenVertexList startVerticesAfter;
4939         for(int i=0; i<startVertices.size(); ++i)
4940         {
4941             InbetweenVertex * sv = startVertices[i];
4942             if(sv->beforeVertex()->time() < time)
4943                 startVerticesBefore << sv;
4944             else
4945                 startVerticesAfter << sv;
4946         }
4947         AnimatedVertex endVertices = sedge->endAnimatedVertex_;
4948         InbetweenVertexList endVerticesBefore;
4949         InbetweenVertexList endVerticesAfter;
4950         for(int i=0; i<endVertices.size(); ++i)
4951         {
4952             InbetweenVertex * sv = endVertices[i];
4953             if(sv->beforeVertex()->time() < time)
4954                 endVerticesBefore << sv;
4955             else
4956                 endVerticesAfter << sv;
4957         }
4958         KeyHalfedge halfedge(keyEdge,true);
4959         Path path(QList<KeyHalfedge>() << halfedge);
4960 
4961         // Create inbetween cells
4962         inbetweenEdgeBefore = newInbetweenEdge(sedge->beforePath(),path,
4963                                                AnimatedVertex(startVerticesBefore),
4964                                                AnimatedVertex(endVerticesBefore));
4965         inbetweenEdgeAfter = newInbetweenEdge(path,sedge->afterPath(),
4966                                               AnimatedVertex(startVerticesAfter),
4967                                               AnimatedVertex(endVerticesAfter));
4968     }
4969 
4970 
4971     // Update incidence relationships
4972     InbetweenCellSet spatialStar = sedge->spatialStar();
4973     InbetweenFaceSet inbetweenFacesToUpdate = spatialStar;
4974     foreach(InbetweenFace * sface, inbetweenFacesToUpdate)
4975     {
4976 
4977         for(int k=0; k < sface->cycles_.size(); ++k)
4978         {
4979             sface->cycles_[k].replaceInbetweenEdge(sedge,
4980                                                    inbetweenEdgeBefore,keyEdge,inbetweenEdgeAfter);
4981         }
4982 
4983         sface->removeMeFromSpatialStarOf_(sedge);
4984         sface->addMeToSpatialStarOf_(inbetweenEdgeBefore);
4985         sface->addMeToSpatialStarOf_(keyEdge);
4986         sface->addMeToSpatialStarOf_(inbetweenEdgeAfter);
4987 
4988         sface->processGeometryChanged_();
4989     }
4990 
4991     // Transfer properties
4992     Color color = sedge->color();
4993     keyEdge->setColor(color);
4994     inbetweenEdgeBefore->setColor(color);
4995     inbetweenEdgeAfter->setColor(color);
4996 
4997     // Transfer Z-ordering of old cell to new cells
4998     zOrdering_.moveBelow(inbetweenEdgeBefore, sedge);
4999     zOrdering_.moveBelow(keyEdge, sedge);
5000     zOrdering_.moveBelow(inbetweenEdgeAfter, sedge);
5001 
5002     // Delete old cell
5003     deleteCell(sedge);
5004 
5005     // Postprocess
5006     keyframHelper.setKeyframe(keyEdge);
5007 
5008     // Return keyframe
5009     return keyEdge;
5010 }
5011 
keyframe_(InbetweenFace * sface,Time time)5012 KeyFace * VAC::keyframe_(InbetweenFace * sface, Time time)
5013 {
5014     // Preprocess
5015     KeyframeHelper keyframHelper(sface,this);
5016 
5017     // Keyframe boundary
5018     for(int i=0; i<sface->numAnimatedCycles(); ++i)
5019     {
5020         // Keyframes inbetween vertices in cycle
5021         InbetweenVertexSet sverticesInCycle = sface->animatedCycle(i).cells();
5022         foreach(InbetweenVertex * svertex, sverticesInCycle)
5023             if(svertex->exists(time))
5024                 keyframe_(svertex, time);
5025 
5026         // Keyframes inbetween edges in cycle
5027         InbetweenEdgeSet sedgesInCycle = sface->animatedCycle(i).cells();
5028         foreach(InbetweenEdge * sedge, sedgesInCycle)
5029             if(sedge->exists(time))
5030                 keyframe_(sedge, time);
5031     }
5032 
5033     // Create key cell
5034     KeyFace * keyFace = newKeyFace(time);
5035     InbetweenFace * inbetweenFaceBefore = newInbetweenFace(QList<AnimatedCycle>(),
5036                                                            QSet<KeyFace*>(),
5037                                                            QSet<KeyFace*>());
5038     InbetweenFace * inbetweenFaceAfter = newInbetweenFace(QList<AnimatedCycle>(),
5039                                                           QSet<KeyFace*>(),
5040                                                           QSet<KeyFace*>());
5041 
5042     // "Split" each animated cycle into two animated cycle and one key cycle
5043     // Add these cycles to the boundary of new cells
5044     for(int i=0; i<sface->numAnimatedCycles(); ++i)
5045     {
5046         // --- Create before and after animated cycles ---
5047 
5048         // Create copy of cycles
5049         AnimatedCycle beforeCycle = sface->animatedCycle(i);
5050         AnimatedCycle afterCycle = sface->animatedCycle(i);
5051 
5052         // Compute "first" nodes
5053         AnimatedCycleNode * beforeCycleFirst = beforeCycle.first();
5054         AnimatedCycleNode * afterCycleFirst = afterCycle.getNode(time)->after();
5055 
5056         // Compute all nodes to delete
5057         QSet<AnimatedCycleNode*> beforeCycleNodesToDelete;
5058         foreach(AnimatedCycleNode * node, beforeCycle.nodes())
5059             if(!node->cell()->isBefore(time))
5060                 beforeCycleNodesToDelete << node;
5061         QSet<AnimatedCycleNode*> afterCycleNodesToDelete;
5062         foreach(AnimatedCycleNode * node, afterCycle.nodes())
5063             if(!node->cell()->isAfter(time))
5064                 afterCycleNodesToDelete << node;
5065 
5066         // Set pointers to deleted nodes to null instead
5067         foreach(AnimatedCycleNode * node, beforeCycle.nodes())
5068             if(beforeCycleNodesToDelete.contains(node->after()))
5069                 node->setAfter(0);
5070         foreach(AnimatedCycleNode * node, afterCycle.nodes())
5071             if(afterCycleNodesToDelete.contains(node->before()))
5072                 node->setBefore(0);
5073 
5074         // Set "first"
5075         beforeCycle.setFirst(beforeCycleFirst);
5076         afterCycle.setFirst(afterCycleFirst);
5077 
5078         // Delete nodes to delete
5079         foreach(AnimatedCycleNode * node, beforeCycleNodesToDelete)
5080             delete node;
5081         foreach(AnimatedCycleNode * node, afterCycleNodesToDelete)
5082             delete node;
5083 
5084         // Add cycles to new inbetween faces
5085         inbetweenFaceBefore->addAnimatedCycle(beforeCycle);
5086         inbetweenFaceAfter->addAnimatedCycle(afterCycle);
5087 
5088         // --- Create key cycle ---
5089 
5090         // Create copy of cycles
5091         AnimatedCycle animatedCycle = sface->animatedCycle(i);
5092 
5093         // Get node at time t.
5094         // It's guaranteed to points to a key cell, to have n->next(t) = n->next().
5095         // recursively, n->next() is guaranteed to have the same properties
5096         AnimatedCycleNode * firstNodeOfKeyCycle = animatedCycle.getNode(time);
5097 
5098         Cycle keyCycle;
5099         AnimatedCycleNode::CycleType keyCycleType = firstNodeOfKeyCycle->cycleType(time);
5100         if(keyCycleType == AnimatedCycleNode::SteinerCycle)
5101         {
5102             keyCycle = Cycle(firstNodeOfKeyCycle->cell()->toKeyVertex());
5103         }
5104         else if(keyCycleType == AnimatedCycleNode::SimpleCycle)
5105         {
5106             // Get closed halfedge
5107             KeyHalfedge halfedge(firstNodeOfKeyCycle->cell()->toKeyEdge(),firstNodeOfKeyCycle->side());
5108 
5109             // Compute how many time it's repeated
5110             int n = 1;
5111             AnimatedCycleNode * node = firstNodeOfKeyCycle->next();
5112             while(node != firstNodeOfKeyCycle)
5113             {
5114                 node = node->next();
5115                 ++n;
5116             }
5117 
5118             // Make cycle
5119             QList<KeyHalfedge> halfedgeList;
5120             for(int i=0; i<n; ++i)
5121                 halfedgeList << halfedge;
5122             keyCycle = Cycle(halfedgeList);
5123         }
5124         else if(keyCycleType == AnimatedCycleNode::NonSimpleCycle)
5125         {
5126             // node->next() alternatively points to key vertices and key edges
5127             // we are only interested int the key edges.
5128             AnimatedCycleNode * firstEdgeNode = firstNodeOfKeyCycle;
5129             if(firstEdgeNode->cell()->toKeyVertex())
5130                 firstEdgeNode = firstEdgeNode->next();
5131 
5132             // Make cycle
5133             AnimatedCycleNode * node = firstEdgeNode;
5134             QList<KeyHalfedge> halfedgeList;
5135             do
5136             {
5137                 halfedgeList << KeyHalfedge(node->cell()->toKeyEdge(),node->side());
5138                 node = node->next()->next();
5139             }
5140             while(node != firstEdgeNode);
5141             keyCycle = Cycle(halfedgeList);
5142         }
5143 
5144         keyFace->addCycle(keyCycle);
5145     }
5146 
5147     // Set temporal boundary
5148     inbetweenFaceBefore->setBeforeFaces(sface->beforeFaces());
5149     inbetweenFaceBefore->addAfterFace(keyFace);
5150     inbetweenFaceAfter->addBeforeFace(keyFace);
5151     inbetweenFaceAfter->setAfterFaces(sface->afterFaces());
5152 
5153     // Transfer properties
5154     Color color = sface->color();
5155     keyFace->setColor(color);
5156     inbetweenFaceBefore->setColor(color);
5157     inbetweenFaceAfter->setColor(color);
5158 
5159     // Transfer Z-ordering of old cell to new cells
5160     zOrdering_.moveBelow(inbetweenFaceBefore, sface);
5161     zOrdering_.moveBelow(keyFace, sface);
5162     zOrdering_.moveBelow(inbetweenFaceAfter, sface);
5163 
5164     // Delete old cell
5165     deleteCell(sface);
5166 
5167     // Postprocess
5168     keyframHelper.setKeyframe(keyFace);
5169 
5170     // Return keyframe
5171     return keyFace;
5172 }
5173 
5174 
5175 
createFace_computeCycles()5176 QList<Cycle> VAC::createFace_computeCycles()
5177 {
5178     // Create all cycles
5179     QList<Cycle> cycles;
5180 
5181     // Edges to use as non-Steiner cycles
5182     KeyEdgeSet edgeSet = selectedCells();
5183     SmartKeyEdgeSet smartKeyEdgeSet(edgeSet);
5184     for(int i=0; i<smartKeyEdgeSet.numConnectedComponents(); ++i)
5185     {
5186         SmartConnectedKeyEdgeSet & potentialCycle = smartKeyEdgeSet[i];
5187         if(potentialCycle.type() == SmartConnectedKeyEdgeSet::GENERAL )
5188         {
5189             global()->mainWindow()->statusBar()->showMessage(tr("Some selected edges were ambiguous and have been ignored"));
5190         }
5191         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::CLOSED_EDGE )
5192         {
5193             Cycle cycle(potentialCycle.edgeSet());
5194             if(cycle.isValid())
5195                 cycles << cycle;
5196             else
5197             {
5198                 //qDebug() << "Warning: invalid cycle while it is apparently a closed edge";
5199             }
5200         }
5201         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::OPEN_EDGE_LOOP )
5202         {
5203             Cycle cycle(potentialCycle.edgeSet());
5204             if(cycle.isValid())
5205                 cycles << cycle;
5206             else
5207             {
5208                 //qDebug() << "Warning: invalid cycle while it is apparently a looping open edge";
5209             }
5210         }
5211         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::SIMPLE_LOOP )
5212         {
5213             Cycle cycle(potentialCycle.edgeSet());
5214             if(cycle.isValid())
5215                 cycles << cycle;
5216             else
5217             {
5218                 //qDebug() << "Warning: invalid cycle while it is apparently a simple loop";
5219             }
5220         }
5221         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::OPEN_EDGE_PATH )
5222         {
5223             // Get edge
5224             KeyEdge * edge = potentialCycle.edge();
5225 
5226             // Create invisible edge
5227             KeyEdge * newEdge = newKeyEdge(edge->time(), edge->startVertex(), edge->endVertex());
5228 
5229             // Add it to cycle
5230             KeyEdgeSet newEdgeSet = potentialCycle.edgeSet();
5231             newEdgeSet << newEdge;
5232             Cycle cycle(newEdgeSet);
5233             if(cycle.isValid())
5234             {
5235                 cycles << cycle;
5236             }
5237             else
5238             {
5239                 deleteCell(newEdge);
5240                 //qDebug() << "Warning: invalid cycle while it is apparently a "
5241                 //            "non-looping open edge to which we added an invisible edge";
5242             }
5243         }
5244         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::SIMPLE_PATH )
5245         {
5246             // Get edge
5247             ProperPath path = potentialCycle.path();
5248 
5249             // Create invisible edge
5250             KeyEdge * newEdge = newKeyEdge(path.time(), path[0].startVertex(), path[path.size()-1].endVertex());
5251 
5252             // Add it to cycle
5253             KeyEdgeSet newEdgeSet = potentialCycle.edgeSet();
5254             newEdgeSet << newEdge;
5255             Cycle cycle(newEdgeSet);
5256             if(cycle.isValid())
5257             {
5258                 cycles << cycle;
5259             }
5260             else
5261             {
5262                 deleteCell(newEdge);
5263                 //qDebug() << "Warning: invalid cycle while it is apparently a "
5264                 //            "non-looping open edge to which we added an invisible edge";
5265             }
5266         }
5267         else if(potentialCycle.type() == SmartConnectedKeyEdgeSet::PATH_LOOP_DECOMPOSITION )
5268         {
5269             // Get edge
5270             CycleHelper hole = potentialCycle.hole();
5271 
5272             // --- Naive version for now, to be improved later ---
5273 
5274             // Create one cycle per loop
5275             for(int j=0; j<hole.nLoops(); ++j)
5276             {
5277                 ProperCycle loop = hole.loop(j);
5278                 KeyEdgeSet newEdgeSet;
5279                 for(int k=0; k<loop.size(); ++k)
5280                     newEdgeSet << loop[k].edge;
5281 
5282                 // Add it to cycle
5283                 Cycle cycle(newEdgeSet);
5284                 if(cycle.isValid())
5285                 {
5286                     cycles << cycle;
5287                 }
5288                 else
5289                 {
5290                     //qDebug() << "Warning: invalid cycle while it is made from a loop";
5291                 }
5292             }
5293         }
5294     }
5295 
5296     // vertices to use as Steiner cycles
5297     KeyVertexSet vertexSet = selectedCells();
5298     KeyVertexSet verticesInClosureOfEdges = Algorithms::closure(edgeSet);
5299     vertexSet.subtract(verticesInClosureOfEdges);
5300 
5301     // Create steiner cycles
5302     foreach(KeyVertex * v, vertexSet)
5303     {
5304         Cycle cycle(v);
5305         if(cycle.isValid())
5306             cycles << cycle;
5307     }
5308 
5309     return cycles;
5310 }
5311 
createFace()5312 void VAC::createFace()
5313 {
5314     // Compute cycles
5315     QList<Cycle> cycles = createFace_computeCycles();
5316 
5317     // Create face
5318     if(cycles.size() == 0)
5319     {
5320         QMessageBox::information(0, QObject::tr("operation aborted"),
5321                                  QObject::tr("Could not create a valid face from the selection"));
5322     }
5323     else
5324     {
5325         newKeyFace(cycles);
5326 
5327         emit needUpdatePicking();
5328         emit changed();
5329         emit checkpoint();
5330     }
5331 }
5332 
addCyclesToFace()5333 void VAC::addCyclesToFace()
5334 {
5335     // Compute cycles
5336     QList<Cycle> cycles = createFace_computeCycles();
5337 
5338     // The faces to which we should add the cycles
5339     KeyFaceSet faceSet = selectedCells();
5340     if(faceSet.size() == 0)
5341     {
5342         QMessageBox::information(0, QObject::tr("operation aborted"),
5343                                  QObject::tr("You need to select at least one face"));
5344         return;
5345     }
5346 
5347     // Add cycles to faces
5348     if(cycles.size() == 0)
5349     {
5350         QMessageBox::information(0, QObject::tr("operation aborted"),
5351                                  QObject::tr("Could not create a valid cycle from selection"));
5352     }
5353     else
5354     {
5355         foreach(KeyFace * face, faceSet)
5356             face->addCycles(cycles);
5357 
5358         emit needUpdatePicking();
5359         emit changed();
5360         emit checkpoint();
5361     }
5362 }
5363 
removeCyclesFromFace()5364 void VAC::removeCyclesFromFace()
5365 {
5366     // The faces to which we should add the cycles
5367     KeyFaceSet faceSet = selectedCells();
5368     if(faceSet.size() == 0)
5369     {
5370         QMessageBox::information(0, QObject::tr("operation aborted"),
5371                                  QObject::tr("You need to select at least one face"));
5372         return;
5373     }
5374 
5375     foreach(KeyFace * face, faceSet)
5376     {
5377         QList<Cycle> newCycles;
5378         for(int i=0; i<face->cycles_.size(); ++i)
5379         {
5380             bool keepCycle = true;
5381             foreach(KeyCell * cell, face->cycles_[i].cells())
5382             {
5383                 if(cell->isSelected())
5384                 {
5385                     keepCycle = false;
5386                     break;
5387                 }
5388             }
5389 
5390             if(keepCycle)
5391                 newCycles << face->cycles_[i];
5392         }
5393 
5394         if(newCycles.size() > 0)
5395         {
5396             face->setCycles(newCycles);
5397         }
5398         else
5399         {
5400             QMessageBox::information(0, QObject::tr("operation aborted"),
5401                                      QObject::tr("At least one cycle of the face "
5402                                                  "must be preserved"));
5403         }
5404     }
5405 
5406     emit needUpdatePicking();
5407     emit changed();
5408     emit checkpoint();
5409 
5410 }
5411 
changeColor()5412 void VAC::changeColor()
5413 {
5414     if(numSelectedCells() > 0)
5415     {
5416         QColor initialColor = (*selectedCells().begin())->color();
5417         QColor color = QColorDialog::getColor(initialColor, 0, tr("select the color for the selected cells"), QColorDialog::ShowAlphaChannel);
5418 
5419         if (color.isValid()) {
5420             foreach(Cell * cell, selectedCells())
5421             {
5422                 cell->setColor(color);
5423             }
5424         }
5425 
5426         //emit needUpdatePicking();
5427         emit changed();
5428         emit checkpoint();
5429     }
5430 }
5431 
raise()5432 void VAC::raise()
5433 {
5434     if(numSelectedCells() > 0)
5435     {
5436         zOrdering_.raise(selectedCells());
5437 
5438         emit needUpdatePicking();
5439         emit changed();
5440         emit checkpoint();
5441     }
5442 }
5443 
lower()5444 void VAC::lower()
5445 {
5446     if(numSelectedCells() > 0)
5447     {
5448         zOrdering_.lower(selectedCells());
5449 
5450         emit needUpdatePicking();
5451         emit changed();
5452         emit checkpoint();
5453     }
5454 }
5455 
raiseToTop()5456 void VAC::raiseToTop()
5457 {
5458     if(numSelectedCells() > 0)
5459     {
5460         zOrdering_.raiseToTop(selectedCells());
5461 
5462         emit needUpdatePicking();
5463         emit changed();
5464         emit checkpoint();
5465     }
5466 }
5467 
lowerToBottom()5468 void VAC::lowerToBottom()
5469 {
5470     if(numSelectedCells() > 0)
5471     {
5472         zOrdering_.lowerToBottom(selectedCells());
5473 
5474         emit needUpdatePicking();
5475         emit changed();
5476         emit checkpoint();
5477     }
5478 }
5479 
5480 
altRaise()5481 void VAC::altRaise()
5482 {
5483     if(numSelectedCells() > 0)
5484     {
5485         zOrdering_.altRaise(selectedCells());
5486 
5487         emit needUpdatePicking();
5488         emit changed();
5489         emit checkpoint();
5490     }
5491 }
5492 
altLower()5493 void VAC::altLower()
5494 {
5495     if(numSelectedCells() > 0)
5496     {
5497         zOrdering_.altLower(selectedCells());
5498 
5499         emit needUpdatePicking();
5500         emit changed();
5501         emit checkpoint();
5502     }
5503 }
5504 
altRaiseToTop()5505 void VAC::altRaiseToTop()
5506 {
5507     if(numSelectedCells() > 0)
5508     {
5509         zOrdering_.altRaiseToTop(selectedCells());
5510 
5511         emit needUpdatePicking();
5512         emit changed();
5513         emit checkpoint();
5514     }
5515 }
5516 
altLowerToBottom()5517 void VAC::altLowerToBottom()
5518 {
5519     if(numSelectedCells() > 0)
5520     {
5521         zOrdering_.altLowerToBottom(selectedCells());
5522 
5523         emit needUpdatePicking();
5524         emit changed();
5525         emit checkpoint();
5526     }
5527 }
5528 
changeEdgeWidth()5529 void VAC::changeEdgeWidth()
5530 {
5531     KeyEdgeSet iedges = selectedCells();
5532     if(iedges.size() > 0)
5533     {
5534         bool ok;
5535         int i = QInputDialog::getInt(0, tr("select new edge width"),
5536                                      tr("width:"), 10, 0, 100, 1, &ok);
5537         if (ok)
5538         {
5539             foreach(KeyEdge * iedge, iedges)
5540             {
5541                 iedge->setWidth((double) i);
5542             }
5543 
5544         }
5545 
5546         emit needUpdatePicking();
5547         emit changed();
5548         emit checkpoint();
5549     }
5550 }
5551 
5552 
glue()5553 void VAC::glue()
5554 {
5555     KeyVertexSet vertexSet = selectedCells();
5556     KeyEdgeSet edgeSet = selectedCells();
5557 
5558     if(edgeSet.size() == 2)
5559     {
5560         KeyEdgeList e = edgeSet.toList();
5561         glue_(e[0],e[1]);
5562     }
5563     else if (vertexSet.size() == 2)
5564     {
5565         KeyVertexList v = vertexSet.toList();
5566         glue_(v[0],v[1]);
5567     }
5568     else
5569     {
5570         QMessageBox::information(0, QObject::tr("Glue: operation aborted"),
5571                                  QObject::tr("Please select either two endpoints or two curves prior to trigger this action."));
5572         return;
5573     }
5574 
5575     emit needUpdatePicking();
5576     emit changed();
5577     emit checkpoint();
5578 }
5579 
unglue()5580 void VAC::unglue()
5581 {
5582     KeyVertexSet vertexSet = selectedCells();
5583     KeyEdgeSet edgeSet = selectedCells();
5584 
5585     foreach(KeyEdge * iedge, edgeSet)
5586         unglue_(iedge);
5587     foreach(KeyVertex * ivertex, vertexSet)
5588         unglue_(ivertex);
5589 
5590     emit needUpdatePicking();
5591     emit changed();
5592     emit checkpoint();
5593 }
5594 
uncut()5595 void VAC::uncut()
5596 {
5597     KeyVertexSet vertexSet = selectedCells();
5598     KeyEdgeSet edgeSet = selectedCells();
5599 
5600     bool hasbeenCut = false;
5601 
5602     foreach(KeyEdge * iedge, edgeSet)
5603         hasbeenCut |= uncut_(iedge);
5604     foreach(KeyVertex * ivertex, vertexSet)
5605         hasbeenCut |= uncut_(ivertex);
5606 
5607     if(hasbeenCut)
5608     {
5609         deselectAll();
5610 
5611         emit needUpdatePicking();
5612         emit changed();
5613         emit checkpoint();
5614     }
5615 }
5616 
cut(VAC * & clipboard)5617 void VAC::cut(VAC* & clipboard)
5618 {
5619     if(selectedCells().isEmpty())
5620         return;
5621 
5622     if(clipboard)
5623         delete clipboard;
5624 
5625     clipboard = subcomplex(selectedCells());
5626     clipboard->timeCopy_ = global()->activeTime();
5627 
5628     smartDelete_(selectedCells());
5629 
5630     emit needUpdatePicking();
5631     emit changed();
5632     emit checkpoint();
5633 }
5634 
copy(VAC * & clipboard)5635 void VAC::copy(VAC* & clipboard)
5636 {
5637     timeCopy_ = global()->activeTime();
5638 
5639     if(selectedCells().isEmpty())
5640         return;
5641 
5642     if(clipboard)
5643         delete clipboard;
5644 
5645     clipboard = subcomplex(selectedCells());
5646     clipboard->timeCopy_ = global()->activeTime();
5647 }
5648 
paste(VAC * & clipboard)5649 void VAC::paste(VAC *& clipboard)
5650 {
5651     if(!clipboard) return;
5652 
5653     // Get different between current time and copy time
5654     Time deltaTime = global()->activeTime() - clipboard->timeCopy_;
5655 
5656     // Offset clipboard VAC by deltaTime
5657     VAC * cloneOfClipboard = clipboard->clone();
5658     KeyCellSet keyCells = cloneOfClipboard->cells();
5659     foreach(KeyCell * kc, keyCells)
5660     {
5661         kc->time_ = kc->time_ + deltaTime;
5662     }
5663 
5664     // Import into this VAC and set as selection
5665     removeFromSelection(selectedCells());
5666     import(cloneOfClipboard, true);
5667 
5668     // Delete clone
5669     delete cloneOfClipboard;
5670 
5671     emit needUpdatePicking();
5672     emit changed();
5673     emit checkpoint();
5674 }
5675 
motionPaste(VAC * & clipboard)5676 void VAC::motionPaste(VAC* & clipboard)
5677 {
5678     if(!clipboard) return;
5679 
5680     // Check that it is possible to motion paste
5681     {
5682         InbetweenCellSet inbetweenCells = clipboard->cells();
5683         if(!inbetweenCells.isEmpty())
5684         {
5685             QMessageBox::information(0, QObject::tr("operation aborted"),
5686                                      QObject::tr("Cannot motion-paste: the clipboard contains inbetween cells."));
5687             return;
5688         }
5689 
5690         // Other checks should be done. For now, just assume it's possible, crash otherwise.
5691     }
5692 
5693     // Get different between current time and copy time
5694     Time deltaTime = global()->activeTime() - timeCopy_;
5695     if(deltaTime.frame() == 0)
5696     {
5697         QMessageBox::information(0, QObject::tr("operation aborted"),
5698                                  QObject::tr("Cannot motion-paste: the frame where you motion-paste must be different from the frame you copy."));
5699         return;
5700     }
5701 
5702     // Offset clipboard VAC by deltaTime
5703     VAC * cloneOfClipboard = clipboard->clone();
5704     KeyCellSet keyCells = cloneOfClipboard->cells();
5705     foreach(KeyCell * kc, keyCells)
5706     {
5707         kc->time_ = kc->time_ + deltaTime;
5708     }
5709 
5710     // Import into this VAC and set as selection
5711     removeFromSelection(selectedCells());
5712     QMap<int,int> idMap = import(cloneOfClipboard, true);
5713 
5714     // Separate vertices/edges/faces into different maps
5715     QMap<KeyVertex *, KeyVertex * > v1ToV2;
5716     QMap<KeyEdge *, KeyEdge * > e1ToE2;
5717     QMap<KeyFace *, KeyFace * > f1ToF2;
5718     QMapIterator<int, int> i(idMap);
5719     while (i.hasNext())
5720     {
5721         i.next();
5722 
5723         int copyID =  (deltaTime.frame() > 0) ? i.key()   : i.value();
5724         int pasteID = (deltaTime.frame() > 0) ? i.value() : i.key();
5725         Cell * copyCell = getCell(copyID);
5726         Cell * pasteCell = getCell(pasteID);
5727         KeyVertex * v1 = copyCell  ? copyCell->toKeyVertex()  : 0;
5728         KeyVertex * v2 = pasteCell ? pasteCell->toKeyVertex() : 0;
5729         KeyEdge * e1 = copyCell  ? copyCell->toKeyEdge()  : 0;
5730         KeyEdge * e2 = pasteCell ? pasteCell->toKeyEdge() : 0;
5731         KeyFace * f1 = copyCell  ? copyCell->toKeyFace()  : 0;
5732         KeyFace * f2 = pasteCell ? pasteCell->toKeyFace() : 0;
5733         if(v1 && v2)
5734             v1ToV2[v1] = v2;
5735         else if(e1 && e2)
5736             e1ToE2[e1] = e2;
5737         else if(f1 && f2)
5738             f1ToF2[f1] = f2;
5739     }
5740 
5741     // Create Inbetween vertices
5742     QMap<KeyVertex *, InbetweenVertex* > v1ToSTV;
5743     QMapIterator<KeyVertex *, KeyVertex * > iv(v1ToV2);
5744     while (iv.hasNext())
5745     {
5746         iv.next();
5747         KeyVertex * v1 = iv.key();
5748         KeyVertex * v2 = iv.value();
5749         InbetweenVertex * stv = inbetweenVertices_(v1,v2);
5750         assert(stv);
5751 
5752         v1ToSTV[v1] = stv;
5753     }
5754 
5755     // Create Inbetween edges
5756     QMap<KeyEdge *, InbetweenEdge* > e1ToSTE;
5757     QMapIterator<KeyEdge *, KeyEdge * > ie(e1ToE2);
5758     while (ie.hasNext())
5759     {
5760         ie.next();
5761         KeyEdge * e1 = ie.key();
5762         KeyEdge * e2 = ie.value();
5763         InbetweenEdge * ste = inbetweenEdges_(e1,e2);
5764         assert(ste);
5765 
5766         e1ToSTE[e1] = ste;
5767     }
5768 
5769     // Create Inbetween faces
5770     QMapIterator<KeyFace *, KeyFace * > iF(f1ToF2);
5771     while (iF.hasNext())
5772     {
5773         iF.next();
5774         KeyFace * f1 = iF.key();
5775         KeyFace * f2 = iF.value();
5776 
5777         // Some safety checks
5778         assert(f1->cycles_.size() == f2->cycles_.size());
5779         int nCycles = f1->cycles_.size();
5780         for(int k = 0; k<nCycles; ++k)
5781         {
5782             assert(f1->cycles_[k].halfedges_.size() == f2->cycles_[k].halfedges_.size());
5783         }
5784 
5785         // Create the inbetween face
5786         QSet<KeyFace*> beforeFaces; beforeFaces << f1;
5787         QSet<KeyFace*> afterFaces; afterFaces << f2;
5788         QList<AnimatedCycle> cycles;
5789         for(int k = 0; k<nCycles; ++k)
5790         {
5791             QList<AnimatedCycleNode *> nodes;
5792             AnimatedCycle cycle;
5793             int nHalfedges = f1->cycles_[k].halfedges_.size();
5794 
5795             // Create nodes. Set cell and side. Set before=after=NULL.
5796             for(int i=0; i<nHalfedges; i++)
5797             {
5798                 KeyHalfedge h = f1->cycles_[k].halfedges_[i];
5799                 KeyEdge * e1 = h.edge;
5800                 InbetweenEdge * ste = e1ToSTE[e1];
5801 
5802                 AnimatedCycleNode * edgeNode = new AnimatedCycleNode(ste);
5803                 nodes << edgeNode;
5804                 edgeNode->setSide(h.side);
5805                 edgeNode->setBefore(0);
5806                 edgeNode->setAfter(0);
5807 
5808                 if(!e1->isClosed())
5809                 {
5810                     KeyVertex * v1 = h.endVertex();
5811                     InbetweenVertex * stv = v1ToSTV[v1];
5812 
5813                     AnimatedCycleNode * vertexNode = new AnimatedCycleNode(stv);
5814                     nodes << vertexNode;
5815                     vertexNode->setBefore(0);
5816                     vertexNode->setAfter(0);
5817                 }
5818             }
5819 
5820             // Special case of Steiner Vertex
5821             if(f1->cycles_[k].vertex_)
5822             {
5823                 assert(nodes.isEmpty());
5824 
5825                 KeyVertex * v1 = f1->cycles_[k].vertex_;
5826                 InbetweenVertex * stv = v1ToSTV[v1];
5827 
5828                 AnimatedCycleNode * vertexNode = new AnimatedCycleNode(stv);
5829                 nodes << vertexNode;
5830                 vertexNode->setBefore(0);
5831                 vertexNode->setAfter(0);
5832 
5833             }
5834 
5835             // Set previous and next
5836             int nNodes = nodes.size();
5837             for(int i=1; i<=nNodes; i++) // Caution: (-1 % n) == -1
5838             {
5839                 nodes[i % nNodes]->setPrevious( nodes[ (i-1) % nNodes ] );
5840                 nodes[i % nNodes]->setNext( nodes[ (i+1) % nNodes ] );
5841             }
5842 
5843             // Create animated cycle
5844             assert(!nodes.isEmpty());
5845             cycles << AnimatedCycle(nodes.first());
5846         }
5847 
5848         // Create inbetween face
5849         InbetweenFace * stf = newInbetweenFace(cycles, beforeFaces, afterFaces);
5850         stf->setColor(f1->color());
5851     }
5852 
5853     // Delete clone
5854     delete cloneOfClipboard;
5855 
5856     informTimelineOfSelection();
5857     emit needUpdatePicking();
5858     emit changed();
5859     emit checkpoint();
5860 
5861 }
5862 
resetCellsToConsiderForCutting()5863 void VAC::resetCellsToConsiderForCutting()
5864 {
5865     facesToConsiderForCutting_.clear();
5866     edgesToConsiderForCutting_.clear();
5867 }
5868 
updateCellsToConsiderForCutting()5869 void VAC::updateCellsToConsiderForCutting()
5870 {
5871     if(hoveredCell_)
5872     {
5873         KeyFace * iface = hoveredCell_->toKeyFace();
5874         KeyEdge* iedge= hoveredCell_->toKeyEdge();
5875         if(iface)
5876             facesToConsiderForCutting_.insert(iface);
5877         if(iedge)
5878             edgesToConsiderForCutting_.insert(iedge);
5879     }
5880 }
5881 
5882 // ----- Selection -----
5883 
setHoveredCell(Cell * cell)5884 void VAC::setHoveredCell(Cell * cell)
5885 {
5886     if (cell != hoveredCell_)
5887     {
5888         setNoHoveredCell();
5889         if(cell)
5890         {
5891             hoveredCell_ = cell;
5892             hoveredCell_->setHovered(true);
5893         }
5894     }
5895 }
5896 
setNoHoveredCell()5897 void VAC::setNoHoveredCell()
5898 {
5899     if(hoveredCell_)
5900     {
5901         hoveredCell_->setHovered(false);
5902         hoveredCell_ = 0;
5903     }
5904 }
5905 
informTimelineOfSelection()5906 void VAC::informTimelineOfSelection()
5907 {
5908     int selectionType = 0;
5909     double t = 0;
5910     double t1 = 0;
5911     double t2 = 0;
5912 
5913     foreach(Cell * cell, selectedCells_)
5914     {
5915         KeyCell * keyCell = cell->toKeyCell();
5916         InbetweenCell * inbetweenCell = cell->toInbetweenCell();
5917         if(keyCell)
5918         {
5919             if(selectionType != 1)
5920             {
5921                 selectionType = 1;
5922                 t = keyCell->time().floatTime();
5923                 t1 = std::numeric_limits<double>::lowest(); // = -max
5924                 t2 = std::numeric_limits<double>::max();
5925             }
5926 
5927             InbetweenCellSet beforeCells = keyCell->temporalStarBefore();
5928             foreach(InbetweenCell * scell, beforeCells)
5929             {
5930                 double tbefore = scell->beforeTime().floatTime();
5931                 t1 = std::max(tbefore,t1);
5932             }
5933 
5934             InbetweenCellSet afterCells = keyCell->temporalStarAfter();
5935             foreach(InbetweenCell * scell, afterCells)
5936             {
5937                 double tafter = scell->afterTime().floatTime();
5938                 t2 = std::min(tafter,t2);
5939             }
5940         }
5941         else if(inbetweenCell && (selectionType!=1) )
5942         {
5943             selectionType = 2;
5944             t1 = inbetweenCell->beforeTime().floatTime();
5945             t2 = inbetweenCell->afterTime().floatTime();
5946             break; // i.e., ignore further cells
5947         }
5948     }
5949 
5950     if(selectionType == 1)
5951     {
5952         if(t1 == std::numeric_limits<double>::lowest())
5953             t1 = t;
5954         if(t2 == std::numeric_limits<double>::max())
5955             t2 = t;
5956     }
5957 
5958     Timeline * timeline = global()->timeline();
5959     timeline->setSelectionType(selectionType);
5960     timeline->setT(t);
5961     timeline->setT1(t1);
5962     timeline->setT2(t2);
5963 }
5964 
addToSelection(Cell * cell,bool emitSignal)5965 void VAC::addToSelection(Cell * cell, bool emitSignal)
5966 {
5967     if(cell && !cell->isSelected())
5968     {
5969         selectedCells_ << cell;
5970         cell->setSelected(true);
5971         emitSelectionChanged_();
5972         if(emitSignal)
5973         {
5974             emit changed();
5975         }
5976     }
5977 }
5978 
removeFromSelection(Cell * cell,bool emitSignal)5979 void VAC::removeFromSelection(Cell * cell, bool emitSignal)
5980 {
5981     if(cell && cell->isSelected())
5982     {
5983         selectedCells_.remove(cell);
5984         cell->setSelected(false);
5985         emitSelectionChanged_();
5986         if(emitSignal)
5987         {
5988             emit changed();
5989         }
5990     }
5991 }
5992 
toggleSelection(Cell * cell,bool emitSignal)5993 void VAC::toggleSelection(Cell * cell, bool emitSignal)
5994 {
5995     if(cell)
5996     {
5997         if(cell->isSelected())
5998             removeFromSelection(cell,emitSignal);
5999         else
6000             addToSelection(cell,emitSignal);
6001     }
6002 }
6003 
addToSelection(const CellSet & cells,bool emitSignal)6004 void VAC::addToSelection(const CellSet & cells, bool emitSignal)
6005 {
6006     beginAggregateSignals_();
6007     foreach(Cell * c, cells)
6008         addToSelection(c, false);
6009     endAggregateSignals_();
6010 
6011     if(emitSignal)
6012     {
6013         emit changed();
6014     }
6015 }
6016 
removeFromSelection(const CellSet & cells,bool emitSignal)6017 void VAC::removeFromSelection(const CellSet & cells, bool emitSignal)
6018 {
6019     beginAggregateSignals_();
6020     foreach(Cell * c, cells)
6021         removeFromSelection(c, false);
6022     endAggregateSignals_();
6023 
6024     if(emitSignal)
6025     {
6026         emit changed();
6027     }
6028 }
6029 
6030 
toggleSelection(const CellSet & cells,bool emitSignal)6031 void VAC::toggleSelection(const CellSet & cells, bool emitSignal)
6032 {
6033     beginAggregateSignals_();
6034     foreach(Cell * c, cells)
6035         toggleSelection(c, false);
6036     endAggregateSignals_();
6037 
6038     if(emitSignal)
6039     {
6040         emit changed();
6041     }
6042 }
6043 
setSelectedCell(Cell * cell,bool emitSignal)6044 void VAC::setSelectedCell(Cell * cell, bool emitSignal)
6045 {
6046     if(cell)
6047     {
6048         CellSet cells;
6049         cells.insert(cell);
6050         setSelectedCells(cells, emitSignal);
6051     }
6052 }
6053 
setSelectedCells(const CellSet & cells,bool emitSignal)6054 void VAC::setSelectedCells(const CellSet & cells, bool emitSignal)
6055 {
6056     bool changing = false;
6057 
6058     // Detect if any new cell is added to the selection, and set
6059     // all new cells as unselected.
6060     foreach(Cell * cell, cells)
6061     {
6062         if (cell->isSelected())
6063         {
6064             cell->setSelected(false);
6065         }
6066         else
6067         {
6068             changing = true;
6069         }
6070     }
6071 
6072     // Detect if any cell is removed from the selection, and set
6073     // all old cells as unselected.
6074     // This works due to the previous step: any cell in selectedCells_
6075     // which is still selected is *not* in the new cells.
6076     foreach(Cell * cell, selectedCells_)
6077     {
6078         if (cell->isSelected())
6079         {
6080             changing = true;
6081             cell->setSelected(false);
6082         }
6083     }
6084 
6085     // Set new cells as selected
6086     foreach(Cell * cell, cells)
6087         cell->setSelected(true);
6088     selectedCells_ = cells;
6089 
6090     if (changing)
6091     {
6092         emitSelectionChanged_();
6093         if(emitSignal)
6094         {
6095             emit changed();
6096         }
6097     }
6098 }
6099 
selectAll(bool emitSignal)6100 void VAC::selectAll(bool emitSignal)
6101 {
6102     addToSelection(cells(), emitSignal);
6103 }
6104 
selectAllAtTime(Time time,bool emitSignal)6105 void VAC::selectAllAtTime(Time time, bool emitSignal)
6106 {
6107     setSelectedCells(cells(time), emitSignal);
6108 }
6109 
selectConnected(bool emitSignal)6110 void VAC::selectConnected(bool emitSignal)
6111 {
6112     addToSelection(Algorithms::connected(selectedCells()), emitSignal);
6113 }
6114 
selectClosure(bool emitSignal)6115 void VAC::selectClosure(bool emitSignal)
6116 {
6117     addToSelection(Algorithms::closure(selectedCells()), emitSignal);
6118 }
6119 
selectVertices(bool emitSignal)6120 void VAC::selectVertices(bool emitSignal)
6121 {
6122     CellSet cellsToSelect;
6123     foreach(Cell * c, selectedCells())
6124         if(c->toKeyVertex())
6125             cellsToSelect.insert(c);
6126 
6127     setSelectedCells(cellsToSelect,emitSignal);
6128 }
6129 
selectEdges(bool emitSignal)6130 void VAC::selectEdges(bool emitSignal)
6131 {
6132     CellSet cellsToSelect;
6133     foreach(Cell * c, selectedCells())
6134         if(c->toKeyEdge())
6135             cellsToSelect.insert(c);
6136 
6137     setSelectedCells(cellsToSelect,emitSignal);
6138 }
6139 
selectFaces(bool emitSignal)6140 void VAC::selectFaces(bool emitSignal)
6141 {
6142     CellSet cellsToSelect;
6143     foreach(Cell * c, selectedCells())
6144         if(c->toKeyFace())
6145             cellsToSelect.insert(c);
6146 
6147     setSelectedCells(cellsToSelect,emitSignal);
6148 }
6149 
deselectVertices(bool emitSignal)6150 void VAC::deselectVertices(bool emitSignal)
6151 {
6152     CellSet cellsToSelect;
6153     foreach(Cell * c, selectedCells())
6154         if(!c->toKeyVertex())
6155             cellsToSelect.insert(c);
6156 
6157     setSelectedCells(cellsToSelect,emitSignal);
6158 }
6159 
deselectEdges(bool emitSignal)6160 void VAC::deselectEdges(bool emitSignal)
6161 {
6162     CellSet cellsToSelect;
6163     foreach(Cell * c, selectedCells())
6164         if(!c->toKeyEdge())
6165             cellsToSelect.insert(c);
6166 
6167     setSelectedCells(cellsToSelect,emitSignal);
6168 }
6169 
deselectFaces(bool emitSignal)6170 void VAC::deselectFaces(bool emitSignal)
6171 {
6172     CellSet cellsToSelect;
6173     foreach(Cell * c, selectedCells())
6174         if(!c->toKeyFace())
6175             cellsToSelect.insert(c);
6176 
6177     setSelectedCells(cellsToSelect,emitSignal);
6178 }
6179 
prepareDragAndDrop(double x0,double y0,Time time)6180 void VAC::prepareDragAndDrop(double x0, double y0, Time time)
6181 {
6182     draggedVertices_.clear();
6183     draggedEdges_.clear();
6184 
6185     // do nothing if the highlighted object is not a node object
6186     if(!hoveredCell_)
6187         return;
6188 
6189     // Contextual help
6190     global()->setDragAndDropping(true);
6191 
6192     // Prepare drag and drop of transform tool first so it's aware
6193     // of drag and drop before cells are keyframed
6194     transformTool_.prepareDragAndDrop();
6195 
6196     // get which cells must be dragged
6197     CellSet cellsToDrag;
6198     if(hoveredCell_->isSelected() && global()->toolMode() == Global::SELECT)
6199         cellsToDrag = selectedCells();
6200     else
6201         cellsToDrag << hoveredCell_;
6202 
6203     // Partition into three sets of cells
6204     CellSet cellsNotToKeyframe;
6205     CellSet cellsToKeyframe;
6206     foreach(Cell * c, cellsToDrag)
6207     {
6208         InbetweenCell * sc = c->toInbetweenCell();
6209         if(sc)
6210         {
6211             if(sc->exists(time))
6212             {
6213                 cellsToKeyframe << sc;
6214             }
6215             else
6216             {
6217                 cellsNotToKeyframe << sc;
6218             }
6219         }
6220         else
6221         {
6222             cellsNotToKeyframe << c;
6223         }
6224     }
6225 
6226     // Keyframe cells
6227     KeyCellSet keyframedCells = keyframe_(cellsToKeyframe,time);
6228 
6229     // Update which cells to drag
6230     cellsToDrag = cellsNotToKeyframe;
6231     foreach(KeyCell * c, keyframedCells)
6232         cellsToDrag << c;
6233     cellsToDrag = Algorithms::closure(cellsToDrag);
6234 
6235     // todo: add the non-loop edges whose end vertices are dragged
6236     draggedVertices_ = KeyVertexSet(cellsToDrag);
6237     draggedEdges_ = KeyEdgeSet(cellsToDrag);
6238 
6239     // prepare drag and drop
6240     foreach(KeyEdge * iedge, draggedEdges_)
6241         iedge->geometry()->prepareDragAndDrop();
6242     foreach(KeyVertex * v, draggedVertices_)
6243         v->prepareDragAndDrop();
6244 
6245     x0_ = x0;
6246     y0_ = y0;
6247 }
6248 
performDragAndDrop(double x,double y)6249 void VAC::performDragAndDrop(double x, double y)
6250 {
6251     double dx = x-x0_;
6252     double dy = y-y0_;
6253 
6254     // Constrain along 45 degree axes
6255     if (global()->keyboardModifiers().testFlag(Qt::ShiftModifier))
6256     {
6257         double d = 0.5*(std::abs(dx)+std::abs(dy));
6258         const double theta = std::atan2(dy, dx); // in [-PI, PI]
6259 
6260         if      (std::abs(theta)          > 7*PI/8) dy = 0;
6261         else if (std::abs(theta)          <   PI/8) dy = 0;
6262         else if (std::abs(theta -   PI/2) <   PI/8) dx = 0;
6263         else if (std::abs(theta +   PI/2) <   PI/8) dx = 0;
6264         else if (std::abs(theta - 3*PI/4) <   PI/8) { dx = -d; dy =  d; }
6265         else if (std::abs(theta -   PI/4) <   PI/8) { dx =  d; dy =  d; }
6266         else if (std::abs(theta +   PI/4) <   PI/8) { dx =  d; dy = -d; }
6267         else if (std::abs(theta + 3*PI/4) <   PI/8) { dx = -d; dy = -d; }
6268     }
6269 
6270     foreach(KeyEdge * iedge, draggedEdges_)
6271     {
6272         iedge->geometry()->performDragAndDrop(dx, dy);
6273         iedge->processGeometryChanged_();
6274     }
6275 
6276     foreach(KeyVertex * v, draggedVertices_)
6277         v->performDragAndDrop(dx, dy);
6278 
6279 
6280     foreach(KeyVertex * v, draggedVertices_)
6281         v->correctEdgesGeometry();
6282 
6283     transformTool_.performDragAndDrop(dx, dy);
6284 
6285     //emit changed();
6286 }
6287 
completeDragAndDrop()6288 void VAC::completeDragAndDrop()
6289 {
6290     transformTool_.endDragAndDrop();
6291     global()->setDragAndDropping(false);
6292 
6293     //emit changed();
6294     emit checkpoint();
6295 }
6296 
beginTransformSelection(double x0,double y0,Time time)6297 void VAC::beginTransformSelection(double x0, double y0, Time time)
6298 {
6299     transformTool_.beginTransform(x0, y0, time);
6300 }
6301 
continueTransformSelection(double x,double y)6302 void VAC::continueTransformSelection(double x, double y)
6303 {
6304     transformTool_.continueTransform(x, y);
6305 }
6306 
endTransformSelection()6307 void VAC::endTransformSelection()
6308 {
6309     transformTool_.endTransform();
6310     emit checkpoint();
6311 }
6312 
prepareTemporalDragAndDrop(Time t0)6313 void VAC::prepareTemporalDragAndDrop(Time t0)
6314 {
6315     t0_ = t0;
6316     draggedKeyCells_ = KeyCellSet(selectedCells());
6317     draggedKeyCellTime_.clear();
6318 
6319     // TODO: Use smth like Time::min();
6320     deltaTMin_ = Time(-1000);
6321     deltaTMax_ = Time(1000);
6322 
6323     foreach(KeyCell * keyCell, draggedKeyCells_)
6324     {
6325         Time deltaTMin = keyCell->temporalDragMinTime() - keyCell->time();
6326         if(deltaTMin_ < deltaTMin)
6327             deltaTMin_ = deltaTMin;
6328 
6329         Time deltaTMax = keyCell->temporalDragMaxTime() - keyCell->time();
6330         if(deltaTMax < deltaTMax_)
6331             deltaTMax_ = deltaTMax;
6332 
6333         draggedKeyCellTime_[keyCell] = keyCell->time();
6334     }
6335 }
6336 
performTemporalDragAndDrop(Time t)6337 void VAC::performTemporalDragAndDrop(Time t)
6338 {
6339     Time deltaTime = t-t0_;
6340     if(deltaTime <= deltaTMin_)
6341         return;
6342     if(deltaTime >= deltaTMax_)
6343         return;
6344 
6345     foreach(KeyCell * keyCell, draggedKeyCells_)
6346         keyCell->setTime(draggedKeyCellTime_[keyCell] + deltaTime);
6347 
6348     emit changed();
6349 }
6350 
completeTemporalDragAndDrop()6351 void VAC::completeTemporalDragAndDrop()
6352 {
6353     emit checkpoint();
6354 }
6355 
6356 
6357 
split(double x,double y,Time time,bool interactive)6358 KeyVertex * VAC::split(double x, double y, Time time, bool interactive)
6359 {
6360     KeyVertex * res = 0;
6361 
6362     if(hoveredCell_)
6363     {
6364         KeyVertex * ivertex = hoveredCell_->toKeyVertex();
6365         KeyEdge * iedge = hoveredCell_->toKeyEdge();
6366         KeyFace * iface = hoveredCell_->toKeyFace();
6367 
6368         InbetweenVertex * svertex = hoveredCell_->toInbetweenVertex();
6369         InbetweenEdge * sedge = hoveredCell_->toInbetweenEdge();
6370         InbetweenFace * sface = hoveredCell_->toInbetweenFace();
6371 
6372         // Create keyframe
6373         if(svertex)
6374             ivertex = keyframe_(svertex,time);
6375         if(sedge)
6376             iedge = keyframe_(sedge,time);
6377         if(sface)
6378             iface = keyframe_(sface,time);
6379 
6380         if(ivertex)
6381         {
6382             // if sketch mode, select it
6383             res = ivertex;
6384         }
6385         else if(iedge)
6386         {
6387             double radius = 1000;
6388             iedge->updateSculpt(x, y, radius);
6389             double s = iedge->geometry()->arclengthOfSculptVertex();
6390             res = cutEdgeAtVertex_(iedge, s);
6391         }
6392         else if(iface)
6393         {
6394             // Cut face by adding a steiner cycle, unless we are in sketch
6395             // mode without planar map mode on
6396             if(!(global()->toolMode() == Global::SKETCH && !global()->planarMapMode()))
6397             {
6398                 res = cutFaceAtVertex_(iface, x, y);
6399             }
6400         }
6401     }
6402 
6403     // create something anyway
6404     if(!res)
6405     {
6406         res = newKeyVertex(time);
6407         res->setPos(Eigen::Vector2d(x,y));
6408     }
6409 
6410     // create straight line in sketch mode.
6411     // Note: never happens anymore, as split() is only called in
6412     if(global()->toolMode() == Global::SKETCH)
6413     {
6414         // --------------------------------------------------------------------
6415         // --------- If non-planar map mode, just create new edges ------------
6416         // --------------------------------------------------------------------
6417 
6418         if(!global()->planarMapMode())
6419         {
6420             // If a vertex is selected, create a new edge between this
6421             // selected vertex and res, where res is either the vertex that
6422             // was highlighted, or a newly created vertex
6423             // This possibly craete many straight lines at once
6424             KeyVertexSet selectedVertices = selectedCells();
6425             KeyEdgeSet newEdges;
6426             foreach(KeyVertex * selectedVertex, selectedVertices)
6427             {
6428                 newEdges << newKeyEdge(time, selectedVertex, res, 0, global()->edgeWidth());
6429             }
6430         }
6431 
6432         // --------------------------------------------------------------------
6433         // ---- If planar map mode, cut edges/faces with these new edges --------
6434         // --------------------------------------------------------------------
6435 
6436         if(global()->planarMapMode())
6437         {
6438             KeyVertexSet selectedVertices = selectedCells();
6439 
6440             foreach(KeyVertex * selectedVertex, selectedVertices)
6441             {
6442                 // Tolerance accounting for floating point errors
6443                 double tolerance = 1e-6;
6444 
6445                 // Emulate begin/continue/end PMR sketch to get same behaviour
6446 
6447                 // Begin
6448                 timeInteractivity_ = time;
6449                 sketchedEdge_ = new LinearSpline(ds_);
6450                 sketchedEdge_->beginSketch(EdgeSample(selectedVertex->pos()[0],selectedVertex->pos()[1],global()->edgeWidth()));
6451                 hoveredFaceOnMouseRelease_ = 0;
6452                 hoveredFaceOnMousePress_ = 0;
6453 
6454                 // Continue
6455                 sketchedEdge_->continueSketch(EdgeSample(res->pos()[0], res->pos()[1], global()->edgeWidth()));
6456 
6457                 // End
6458                 sketchedEdge_->endSketch();
6459                 sketchedEdge_->resample();
6460                 CellSet allCells = cells();
6461                 //facesToConsiderForCutting_ = KeyFaceSet(allCells);
6462                 insertSketchedEdgeInVAC(tolerance, false);
6463                 delete sketchedEdge_;
6464                 sketchedEdge_ = 0;
6465             }
6466         }
6467 
6468         // In any case, select the newly created vertex
6469         CellSet newSeletedCells;
6470         newSeletedCells << res;
6471         setSelectedCells(newSeletedCells);
6472     }
6473     else
6474     {
6475         // nothing
6476     }
6477 
6478     if(interactive)
6479     {
6480         emit needUpdatePicking();
6481         emit changed();
6482         emit checkpoint();
6483     }
6484 
6485     return res;
6486 }
6487 
check() const6488 bool VAC::check() const
6489 {
6490     foreach(Cell * c, cells_)
6491         if(!(c->check()))
6492             return false;
6493     return true;
6494 }
6495 
checkContains(const Cell * c) const6496 bool VAC::checkContains(const Cell * c) const
6497 {
6498     int id = c->id();
6499     return (cells_.contains(id)) && (cells_[id] == c);
6500 }
6501 
updateToBePaintedFace(double x,double y,Time time)6502 void VAC::updateToBePaintedFace(double x, double y, Time time)
6503 {
6504     // Init face
6505     if(!toBePaintedFace_)
6506         toBePaintedFace_ = new PreviewKeyFace;
6507 
6508     // Erase previous results
6509     toBePaintedFace_->clear();
6510 
6511     // Check if highlighted cell
6512     if(hoveredCell())
6513     {
6514         // In this case, painting would change the color of the
6515         // highlighted cell, instead of creating a new face
6516         return;
6517     }
6518 
6519     // From here, we try to find a list of cycles such that
6520     // the corresponding face would intersect with the cursor
6521 
6522     // Compute distances to all edges
6523     QMap<KeyEdge*,EdgeGeometry::ClosestVertexInfo> distancesToEdges;
6524     foreach(KeyEdge * e, instantEdges())
6525         distancesToEdges[e] = e->geometry()->closestPoint(x,y);
6526 
6527     // First, we try to create such a face assuming that the
6528     // VGC is actually planar (cells are not overlapping).
6529     bool foundPlanarFace = false;
6530     {
6531         // Find external boundary: the closest planar cycle containing mouse cursor
6532         QSet<KeyEdge*> potentialExternalBoundaryEdges;
6533         foreach(KeyEdge* e, instantEdges())
6534         {
6535             if(e->exists(time))
6536                 potentialExternalBoundaryEdges.insert(e);
6537         }
6538         PreviewKeyFace externalBoundary;
6539         bool foundExternalBoundary = false;
6540         while(!(foundExternalBoundary || potentialExternalBoundaryEdges.isEmpty()))
6541         {
6542             // Find closest potential edge
6543             KeyEdge * closestPotentialExternalBoundaryEdge = 0;
6544             EdgeGeometry::ClosestVertexInfo cvi;
6545             cvi.s = 0;
6546             cvi.d = std::numeric_limits<double>::max();
6547             foreach(KeyEdge * e, potentialExternalBoundaryEdges)
6548             {
6549                 EdgeGeometry::ClosestVertexInfo cvi_e = distancesToEdges[e];
6550                 if(cvi_e.d < cvi.d) // TODO: cvi_e.d could be NaN, in which case it returns false, and closestPotentialExternalBoundaryEdge can be null, resulting in a segfault 8 lines below.
6551                 {
6552                     closestPotentialExternalBoundaryEdge = e;
6553                     cvi = cvi_e;
6554                 }
6555             }
6556 
6557             // Find direction of halfedge
6558             Eigen::Vector2d der = closestPotentialExternalBoundaryEdge->geometry()->der(cvi.s);
6559             double cross = der[0] * (y - cvi.p.y()) - der[1] * (x - cvi.p.x());
6560             KeyHalfedge h(closestPotentialExternalBoundaryEdge, (cross>0 ? false : true) ); // be careful here, canvas is left-handed
6561 
6562             // Find potential external boundary
6563             if(closestPotentialExternalBoundaryEdge->isClosed())
6564             {
6565                 KeyEdgeSet edgeSet;
6566                 edgeSet << closestPotentialExternalBoundaryEdge;
6567                 Cycle cycle(edgeSet);
6568                 if(cycle.isValid())
6569                 {
6570                     externalBoundary << cycle;
6571                     if(externalBoundary.intersects(x,y))
6572                     {
6573                         foundExternalBoundary = true;
6574                     }
6575                     else
6576                     {
6577                         potentialExternalBoundaryEdges.remove(closestPotentialExternalBoundaryEdge);
6578                         externalBoundary.clear();
6579                     }
6580                 }
6581                 else
6582                 {
6583                     potentialExternalBoundaryEdges.remove(closestPotentialExternalBoundaryEdge);
6584                 }
6585             }
6586             else // i.e., if closestPotentialExternalBoundaryEdge is open
6587             {
6588                 // First halfedge of non-simple-cycle
6589                 KeyHalfedge h0 = h;
6590                 QList<KeyHalfedge> potentialPlanarCycle;
6591                 potentialPlanarCycle << h;
6592 
6593                 // Find the corresponding planar map cycle
6594                 int maxIter = 2 * potentialExternalBoundaryEdges.size() + 2;
6595                 bool foundPotentialPlanarCycle = false;
6596                 for(int i=0; i<maxIter; i++)
6597                 {
6598                     // Find next halfedge in cycle
6599                     h = h.next();
6600 
6601                     // Check it has not already been rejected
6602                     if(!potentialExternalBoundaryEdges.contains(h.edge))
6603                     {
6604                         break;
6605                     }
6606 
6607                     // Test if cycle completed or not
6608                     if(h == h0)
6609                     {
6610                         // Cycle completed: leave loop
6611                         foundPotentialPlanarCycle = true;
6612                         break;
6613                     }
6614                     else
6615                     {
6616                         // Cycle not completed: insert and iterate
6617                         potentialPlanarCycle << h;
6618                     }
6619                 }
6620 
6621                 // If not found (maxIter reached or edge already rejected)
6622                 if(!foundPotentialPlanarCycle)
6623                 {
6624                     foreach(KeyHalfedge he, potentialPlanarCycle)
6625                     {
6626                         potentialExternalBoundaryEdges.remove(he.edge);
6627                     }
6628                 }
6629                 else
6630                 {
6631                     Cycle cycle(potentialPlanarCycle);
6632                     if(cycle.isValid())
6633                     {
6634                         externalBoundary << cycle;
6635                         if(externalBoundary.intersects(x,y))
6636                         {
6637                             foundExternalBoundary = true;
6638                         }
6639                         else
6640                         {
6641                             foreach(KeyHalfedge he, potentialPlanarCycle)
6642                             {
6643                                 potentialExternalBoundaryEdges.remove(he.edge);
6644                             }
6645                             externalBoundary.clear();
6646                         }
6647                     }
6648                     else
6649                     {
6650                         foreach(KeyHalfedge he, potentialPlanarCycle)
6651                         {
6652                             potentialExternalBoundaryEdges.remove(he.edge);
6653                         }
6654                     }
6655                 }
6656             } // end if/then/else "closestPotentialExternalBoundaryEdge is closed?"
6657 
6658         }// end while( !( found external boundary || isEmpty) )
6659 
6660         // We left the while loop, so either we found an external boundary, or there's no hope to find one
6661         if(foundExternalBoundary)
6662         {
6663             // Great, so we know we have a valid planar face!
6664             // Plus, it's already stored as a PreviewFace :)
6665             *toBePaintedFace_ = externalBoundary;
6666             foundPlanarFace = true;
6667 
6668             // Now, let's try to add holes to the external boundary
6669             QSet<KeyEdge*> potentialHoleEdges;
6670             foreach(KeyEdge* e, instantEdges())
6671             {
6672                 if(e->exists(time))
6673                     potentialHoleEdges.insert(e);
6674             }
6675             CellSet cellsInExternalBoundary = externalBoundary.cycles()[0].cells();
6676             KeyEdgeSet edgesInExternalBoundary = cellsInExternalBoundary;
6677             foreach(KeyEdge * e, edgesInExternalBoundary)
6678                 potentialHoleEdges.remove(e);
6679             QList<PreviewKeyFace> holes;
6680             while(!potentialHoleEdges.isEmpty())
6681             {
6682                 // Ordered by distance to mouse cursor p, add planar cycles gamma which:
6683                 //   - Do not contain p
6684                 //   - Are contained in external boundary
6685                 //   - Are not contained in holes already added
6686                 addHoleToPaintedFace(potentialHoleEdges, *toBePaintedFace_, distancesToEdges, x, y);
6687             }
6688         }
6689         else
6690         {
6691             // If we haven't found an external boundary, then we can't find a planar face
6692             // Just continue the method to find a non-planar face
6693             foundPlanarFace = false;
6694         }
6695     } // end of trying to find a planar face
6696 
6697     if(foundPlanarFace)
6698     {
6699         // Great, nothing to do! Everything has already been taken care of.
6700     }
6701     else
6702     {
6703         // TODO: try to find any valid face, even if it's not planar
6704     }
6705 }
6706 
paint(double,double,Time)6707 Cell * VAC::paint(double /*x*/, double /*y*/, Time /*time*/)
6708 {
6709     // The created face, if any
6710     Cell * res = 0;
6711 
6712     // Paint existing cell
6713     if(hoveredCell())
6714     {
6715         hoveredCell()->setColor(global()->faceColor());
6716         res = hoveredCell();
6717     }
6718 
6719     // Create a new face
6720     else if(toBePaintedFace_->numCycles() > 0)
6721     {
6722         res = newKeyFace(toBePaintedFace_->cycles());
6723     }
6724 
6725     if (res)
6726     {
6727         emit needUpdatePicking();
6728         emit changed();
6729         emit checkpoint();
6730     }
6731 
6732     // Return
6733     return res;
6734 }
6735 
test()6736 void VAC::test()
6737 {
6738     // This function is for debug purposes
6739     // Insert below the code you want to execute by pressing "T" within VPaint
6740     // Note: for this to work, you also have to uncomment in MainWindow.cpp the line:
6741     //             menuEdit->addAction(actionTest);
6742 
6743     emit needUpdatePicking();
6744     emit changed();
6745     emit checkpoint();
6746 }
6747 
6748 }
6749 
6750 // GUI
6751 
6752 #include <QAction>
6753 #include <QToolBar>
6754 #include "../Scene.h"
6755 #include "../ColorSelector.h"
6756 
6757 namespace VectorAnimationComplex
6758 {
6759 
populateToolBar(QToolBar *,Scene *)6760 void VAC::populateToolBar(QToolBar * /*toolBar*/, Scene * /*scene*/)
6761 {
6762 }
6763 
6764 }
6765 
6766 
6767