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