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 "InbetweenVertex.h"
18 #include "KeyVertex.h"
19 
20 #include "VAC.h"
21 
22 #include "../OpenGL.h"
23 #include "../SaveAndLoad.h"
24 #include "../DevSettings.h"
25 #include "../Global.h"
26 
27 #include <QtDebug>
28 #include <QTextStream>
29 
30 #include "../XmlStreamReader.h"
31 #include "../XmlStreamWriter.h"
32 
33 namespace VectorAnimationComplex
34 {
35 
36 // Constructor
InbetweenVertex(VAC * vac,KeyVertex * beforeVertex,KeyVertex * afterVertex)37 InbetweenVertex::InbetweenVertex(VAC * vac,
38                    KeyVertex * beforeVertex,
39                    KeyVertex * afterVertex):
40     Cell(vac),
41     InbetweenCell(vac),
42     VertexCell(vac),
43 
44     beforeVertex_(beforeVertex),
45     afterVertex_(afterVertex)
46 {
47     // color
48     color_[0] = 0;
49     color_[1] = 0;
50     color_[2] = 0;
51     color_[3] = 1;
52 
53     // add the boundary to this
54     addMeToTemporalStarAfterOf_(beforeVertex_);
55     addMeToTemporalStarBeforeOf_(afterVertex_);
56 }
57 
~InbetweenVertex()58 InbetweenVertex::~InbetweenVertex()
59 {
60 }
61 
InbetweenVertex(VAC * vac,QTextStream & in)62 InbetweenVertex::InbetweenVertex(VAC * vac, QTextStream & in) :
63     Cell(vac, in),
64     InbetweenCell(vac, in),
65     VertexCell(vac, in),
66 
67     beforeVertex_(0),
68     afterVertex_(0)
69 {
70     color_[0] = 0;
71     color_[1] = 0;
72     color_[2] = 0;
73     color_[3] = 1;
74 
75     Field field;
76     tmp_ = new TempRead();
77 
78     // Before node / After node
79     in >> field >> tmp_->before;
80     in >> field >> tmp_->after;
81 }
read2ndPass()82 void InbetweenVertex::read2ndPass()
83 {
84     // Base classes
85     Cell::read2ndPass();
86     InbetweenCell::read2ndPass();
87     VertexCell::read2ndPass();
88 
89     // Before node / After node
90     beforeVertex_ = getCell(tmp_->before)->toKeyVertex();
91     afterVertex_ = getCell(tmp_->after)->toKeyVertex();
92 
93     delete tmp_;
94 }
95 
96 
save_(QTextStream & out)97 void InbetweenVertex::save_(QTextStream & out)
98 {
99     // Base classes
100     Cell::save_(out);
101     InbetweenCell::save_(out);
102     VertexCell::save_(out);
103 
104     // Before node / After node
105     out << Save::newField("BeforeVertex") << beforeVertex_->id();
106     out << Save::newField("AfterVertex") << afterVertex_->id();
107 }
108 
xmlType_() const109 QString InbetweenVertex::xmlType_() const
110 {
111     return "inbetweenvertex";
112 
113 }
write_(XmlStreamWriter & xml) const114 void InbetweenVertex::write_(XmlStreamWriter & xml) const
115 {
116     // Base classes
117     Cell::write_(xml);
118     InbetweenCell::write_(xml);
119     VertexCell::write_(xml);
120 
121     // Before/After Vertices
122     xml.writeAttribute("beforevertex", QString().setNum(beforeVertex_->id()));
123     xml.writeAttribute("aftervertex", QString().setNum(afterVertex_->id()));
124 }
125 
InbetweenVertex(VAC * vac,XmlStreamReader & xml)126 InbetweenVertex::InbetweenVertex(VAC * vac, XmlStreamReader & xml) :
127     Cell(vac, xml),
128     InbetweenCell(vac, xml),
129     VertexCell(vac, xml),
130 
131     beforeVertex_(0),
132     afterVertex_(0)
133 {
134     color_[0] = 0;
135     color_[1] = 0;
136     color_[2] = 0;
137     color_[3] = 1;
138 
139     tmp_ = new TempRead();
140     tmp_->before = xml.attributes().value("beforevertex").toInt();
141     tmp_->after = xml.attributes().value("aftervertex").toInt();
142 }
143 
clone()144 InbetweenVertex * InbetweenVertex::clone()
145 {
146     return new InbetweenVertex(this);
147 }
148 
remapPointers(VAC * newVAC)149 void InbetweenVertex::remapPointers(VAC * newVAC)
150 {
151     Cell::remapPointers(newVAC);
152     InbetweenCell::remapPointers(newVAC);
153     VertexCell::remapPointers(newVAC);
154 
155     // no pointers in this class
156     beforeVertex_ = newVAC->getCell(beforeVertex_->id())->toKeyVertex();
157     afterVertex_ = newVAC->getCell(afterVertex_->id())->toKeyVertex();
158 }
159 
160 
InbetweenVertex(InbetweenVertex * other)161 InbetweenVertex::InbetweenVertex(InbetweenVertex * other):
162     Cell(other),
163     InbetweenCell(other),
164     VertexCell(other),
165 
166     beforeVertex_(other->beforeVertex_),
167     afterVertex_(other->afterVertex_)
168 {
169 }
170 
beforeCells() const171 KeyCellSet InbetweenVertex::beforeCells() const
172 {
173     KeyCellSet res;
174     res << beforeVertex();
175     return res;
176 }
177 
afterCells() const178 KeyCellSet InbetweenVertex::afterCells() const
179 {
180     KeyCellSet res;
181     res << afterVertex();
182     return res;
183 }
184 
beforeVertex() const185 KeyVertex * InbetweenVertex::beforeVertex() const
186 {
187     return beforeVertex_;
188 }
189 
afterVertex() const190 KeyVertex * InbetweenVertex::afterVertex() const
191 {
192     return afterVertex_;
193 }
194 
195 // Update Boundary
updateBoundary_impl(KeyVertex * oldVertex,KeyVertex * newVertex)196 void InbetweenVertex::updateBoundary_impl(KeyVertex * oldVertex, KeyVertex * newVertex)
197 {
198     if(beforeVertex_ == oldVertex)
199         beforeVertex_ = newVertex;
200     if(afterVertex_ == oldVertex)
201         afterVertex_ = newVertex;
202 }
203 
204 // Drawing
205 
glColor3D_()206 void InbetweenVertex::glColor3D_()
207 {
208     glColor4d(0,0,0,1);
209 }
drawRaw3D(View3DSettings & viewSettings)210 void InbetweenVertex::drawRaw3D(View3DSettings & viewSettings)
211 {
212     double eps = 1e-5;
213 
214     int k = 5; // number of samples per frame
215     double t1 = beforeTime().floatTime();
216     double t2 = afterTime().floatTime();
217     double dt = 1 / (double) k;
218 
219     int lineWidth = 3;
220     glLineWidth(lineWidth);
221     glBegin(GL_LINE_STRIP);
222     for(double t=t1; t<t2+eps; t+=dt)
223     {
224         Eigen::Vector2d p = pos(Time(t));
225         double x = viewSettings.xFromX2D(p[0]);
226         double y = viewSettings.yFromY2D(p[1]);
227         double z = viewSettings.zFromT(t);
228         glVertex3d(x,y,z);
229     }
230     glEnd();
231 
232     glLineWidth(1);
233 }
234 
235 // Geometry
pos(Time time) const236 Eigen::Vector2d InbetweenVertex::pos(Time time) const
237 {
238     return posCubic(time);
239 }
240 
241 // --------- Cubic spline interpolation---------
242 
posCubic(Time time) const243 Eigen::Vector2d InbetweenVertex::posCubic(Time time) const
244 {
245     // a notation like var_ means it is in the [t1,t2] domain
246     // a notation like var  means it is in the [0 ,1 ] domain
247 
248     // --- get parameters in the [t1,t2] domain ---
249 
250     Eigen::Vector2d p1_ = beforeVertex()->pos();
251     //Eigen::Vector2d m1_ = beforeVertex()->catmullRomTangent(true);
252     //Eigen::Vector2d m1_ = beforeVertex()->dividedDifferencesTangent(true);
253     Eigen::Vector2d m1_ = beforeVertex()->dividedDifferencesTangent(false);
254     double t1_ = beforeVertex()->time().floatTime();
255 
256     Eigen::Vector2d p2_ = afterVertex()->pos();
257     //Eigen::Vector2d m2_ = afterVertex()->catmullRomTangent(true);
258     //Eigen::Vector2d m2_ = afterVertex()->dividedDifferencesTangent(true);
259     Eigen::Vector2d m2_ = afterVertex()->dividedDifferencesTangent(false);
260     double t2_ = afterVertex()->time().floatTime();
261 
262     double t_ = time.floatTime();
263     double dt_ = t2_-t1_;
264 
265 
266     // --- convert in the [0,1] domain ---
267 
268     double t;
269     if(dt_ > 0)      t = (t_-t1_)/dt_;
270     else if(t_<t1_)  t = 0;
271     else             t = 1;
272 
273     Eigen::Vector2d p1 = p1_;
274     Eigen::Vector2d p2 = p2_;
275     Eigen::Vector2d m1 = m1_ * dt_;
276     Eigen::Vector2d m2 = m2_ * dt_;
277 
278 
279     // --- compute cubic Hermite ---
280 
281     double t2 = t*t;
282     double t3 = t2*t;
283     return (2*t3-3*t2+1) * p1
284         + (t3-2*t2+t) * m1
285         + (-2*t3+3*t2) * p2
286         + (t3-t2) * m2;
287 }
288 
posLinear(Time time) const289 Eigen::Vector2d InbetweenVertex::posLinear(Time time) const
290 {
291     double t = time.floatTime();
292 
293     double t1 = beforeVertex()->time().floatTime();
294     double t2 = afterVertex()->time().floatTime();
295     double dt = t2-t1;
296 
297     Eigen::Vector2d p1 = beforeVertex()->pos();
298     Eigen::Vector2d p2 = afterVertex()->pos();
299 
300     if(dt>0)
301         return p1 + (t-t1)/dt * (p2-p1);
302     else if (t<t1)
303         return p1;
304     else
305         return p2;
306 }
307 
check_() const308 bool InbetweenVertex::check_() const
309 {
310     // todo
311     return true;
312 }
313 
314 }
315