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