All Classes Namespaces Functions Variables Enumerations Properties Pages
test_viewmanager.cpp
1 /*
2 
3 Pencil2D - Traditional Animation Software
4 Copyright (C) 2012-2020 Matthew Chiawen Chang
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; version 2 of the License.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 */
16 #include "catch.hpp"
17 
18 #include <cmath>
19 #include "viewmanager.h"
20 #include "editor.h"
21 #include "object.h"
22 #include "camera.h"
23 #include "layercamera.h"
24 #include "cameraeasingtype.h"
25 
26 
27 TEST_CASE("ViewManager: Init")
28 {
29  Object* object = new Object;
30  Editor* editor = new Editor;
31  editor->setObject(object);
32 
33  SECTION("init")
34  {
35  ViewManager* viewMgr = new ViewManager(editor);
36  REQUIRE(viewMgr->getView() == QTransform());
37  REQUIRE(viewMgr->getView().isIdentity());
38  }
39  delete editor;
40 }
41 
42 TEST_CASE("ViewManager: Translations")
43 {
44  Object* object = new Object;
45  Editor* editor = new Editor;
46  editor->setObject(object);
47 
48  SECTION("translate(x, y) = (10, 20)")
49  {
50  ViewManager v(editor);
51  v.init();
52 
53  v.translate(10, 20);
54  REQUIRE(v.mapCanvasToScreen(QPointF(0, 0)) == QPointF(10, 20));
55  }
56 
57  SECTION("translate twice")
58  {
59  ViewManager v(editor);
60  v.init();
61 
62  v.translate(0, 15);
63  REQUIRE(v.mapCanvasToScreen(QPointF(0, 0)) == QPointF(0, 15));
64 
65  v.translate(0, 30);
66  REQUIRE(v.mapCanvasToScreen(QPointF(0, 0)) == QPointF(0, 30));
67  }
68 
69  delete editor;
70 }
71 
72 TEST_CASE("ViewManager: Rotate")
73 {
74  Object* object = new Object;
75  Editor* editor = new Editor;
76  editor->setObject(object);
77 
78  SECTION("Rotate 90 degrees")
79  {
80  ViewManager v(editor);
81  v.init();
82 
83  v.rotate(90.f); // counter-clockwise rotation
84  REQUIRE(v.rotation() == 90.f);
85  REQUIRE(v.mapCanvasToScreen(QPointF(1, 0)) == QPointF(0, 1));
86  REQUIRE(v.mapCanvasToScreen(QPointF(23.6, 0)) == QPointF(0, 23.6));
87  }
88 
89  SECTION("Rotate 180 degrees")
90  {
91  ViewManager v(editor);
92  v.init();
93 
94  v.rotate(180.f); // counter-clockwise rotation
95  REQUIRE(v.rotation() == 180.f);
96  REQUIRE(v.mapCanvasToScreen(QPointF(1, 0)) == QPointF(-1, 0));
97  REQUIRE(v.mapCanvasToScreen(QPointF(92.1, 0)) == QPointF(-92.1, 0));
98  }
99 
100  SECTION("Rotate twice")
101  {
102  ViewManager v(editor);
103  v.init();
104 
105  v.rotate(45.f); // counter-clockwise rotation
106  REQUIRE(v.rotation() == 45.f);
107  REQUIRE(v.mapCanvasToScreen(QPointF(1, 0)) == QPointF(cos(M_PI / 4), sin(M_PI / 4)));
108 
109  v.rotate(90);
110  REQUIRE(v.rotation() == 90.f);
111  REQUIRE(v.mapCanvasToScreen(QPointF(1, 0)) == QPointF(0, 1));
112  }
113 
114  delete editor;
115 }
116 
117 TEST_CASE("ViewManager: Scaling")
118 {
119  Object* object = new Object;
120  Editor* editor = new Editor;
121  editor->setObject(object);
122 
123  SECTION("Scale 2.0")
124  {
125  ViewManager v(editor);
126  v.init();
127 
128  v.scale(2);
129  REQUIRE(v.scaling() == 2.0f);
130  REQUIRE(v.mapCanvasToScreen(QPointF(1, 1)) == QPointF(2, 2));
131  }
132 
133  SECTION("Scale twice")
134  {
135  ViewManager v(editor);
136  v.init();
137 
138  v.scale(2);
139  REQUIRE(v.scaling() == 2.f);
140  REQUIRE(v.mapCanvasToScreen(QPointF(1, 1)) == QPointF(2, 2));
141 
142  v.scale(6);
143  REQUIRE(v.scaling() == 6.f);
144  REQUIRE(v.mapCanvasToScreen(QPointF(1, 1)) == QPointF(6, 6));
145  REQUIRE(v.mapCanvasToScreen(QPointF(-1, 2)) == QPointF(-6, 12));
146  }
147 
148  SECTION("Scale over the maximum value")
149  {
150  ViewManager v(editor);
151  v.init();
152 
153  // set a ridiculously large number
154  // should be clamp to 100.f, the maximum scaling value
155  v.scale(10000);
156  REQUIRE(v.mapCanvasToScreen(QPointF(1, 1)) == QPointF(100, 100));
157  }
158 
159  SECTION("Scale over the minimum value")
160  {
161  ViewManager v(editor);
162  v.init();
163 
164  v.scale(0.00005f);
165 
166  QPointF p1 = v.mapCanvasToScreen(QPointF(1, 1));
167  QPointF p2 = QPointF(0.01, 0.01);
168 
169  REQUIRE(std::fabs(p1.x() - p2.x()) < 0.000001);
170  REQUIRE(std::fabs(p1.y() - p2.y()) < 0.000001);
171  }
172 
173  delete editor;
174 }
175 
176 TEST_CASE("ViewManager: Mixed tranformations")
177 {
178  Object* object = new Object;
179  Editor* editor = new Editor;
180  editor->setObject(object);
181 
182  SECTION("translate + rotate")
183  {
184  ViewManager v(editor);
185  v.init();
186 
187  v.translate(10, 0);
188  v.rotate(90);
189  // translation is always applied first
190  // (1, 1) => translate 10 units on x => (11, 1)
191  // (11, 1) => rotate 90 deg => (-1, 11)
192  REQUIRE(v.mapCanvasToScreen(QPointF(1, 1)) == QPointF(-1, 11));
193  }
194 
195  delete editor;
196 }
197 
198 TEST_CASE("ViewManager: Reset view")
199 {
200  Object* object = new Object;
201  Editor* editor = new Editor;
202  editor->setObject(object);
203 
204  SECTION("Reset view matrix")
205  {
206  ViewManager v(editor);
207  v.init();
208 
209  v.translate(15, 25);
210  v.scale(3.25);
211 
212  v.resetView(); // Reset! view matrix will be identity.
213 
214  REQUIRE(v.getView().isIdentity());
215  REQUIRE(v.mapCanvasToScreen(QPointF(10, 10)) == QPointF(10, 10));
216  REQUIRE(v.mapScreenToCanvas(QPointF(99, 10)) == QPointF(99, 10));
217  }
218  delete editor;
219 }
220 
221 TEST_CASE("ViewManager: working with camera layers")
222 {
223  Object* object = new Object;
224  Editor* editor = new Editor;
225  editor->setObject(object);
226 
227  SECTION("Empty Camera Layer")
228  {
229  ViewManager v(editor);
230  v.init();
231 
232  LayerCamera* layerCam = editor->object()->addNewCameraLayer();
233  REQUIRE(layerCam != nullptr);
234 
235  Camera* k = static_cast<Camera*>(layerCam->getKeyFrameAt(1));
236  k->translate(100, 0);
237  v.setCameraLayer(layerCam);
238 
239  REQUIRE(k->getView() == v.getView());
240  REQUIRE(v.translation() == QPointF(100, 0));
241 
242  editor->object()->deleteLayer(0);
243  }
244 
245  SECTION("Camera Layer with 2 keys")
246  {
247  ViewManager v(editor);
248  v.init();
249 
250  // a default key at frame 0
251  // 2nd key at frame 10
252  LayerCamera* layerCam = editor->object()->addNewCameraLayer();
253  layerCam->addKeyFrame(10, new Camera(QPointF(100, 0), 0, 1, CameraEasingType::LINEAR));
254 
255  v.setCameraLayer(layerCam);
256  editor->scrubTo(10);
257 
258  // get the view matrix from camera layer at frame 10
259  QTransform t = v.getView();
260  REQUIRE(t.dx() == 100.0);
261  REQUIRE(t.dy() == 0);
262  REQUIRE(v.mapCanvasToScreen(QPointF(1, 5)) == QPointF(101, 5));
263 
264  editor->object()->deleteLayer(0);
265  }
266 
267  SECTION("Set CameraLayer And then remove it")
268  {
269  ViewManager v(editor);
270  v.init();
271 
272  QPointF originalOffset(0, 100);
273  v.translate(originalOffset.x(), originalOffset.y());
274 
275  LayerCamera* layerCam = editor->object()->addNewCameraLayer();
276 
277  auto cam = layerCam->getCameraAtFrame(1);
278  cam->translate(100, 0);
279 
280  layerCam->addKeyFrame(5, new Camera(QPoint(200, 0), 0, 2.0, CameraEasingType::LINEAR));
281 
282  v.setCameraLayer(layerCam);
283  v.setCameraLayer(nullptr);
284 
285  REQUIRE(v.translation() == originalOffset);
286  }
287 
288  delete editor;
289 }
290 
291 
292 TEST_CASE("ViewManager: canvas size")
293 {
294  Object* object = new Object;
295  Editor* editor = new Editor;
296  editor->setObject(object);
297 
298  SECTION("Canvas size(100, 200)")
299  {
300  ViewManager v(editor);
301  v.init();
302  v.setCanvasSize(QSize(100, 200));
303 
304  QTransform t = v.getView();
305 
306  REQUIRE(t.dx() == 50.0); // should be half of the canvas width
307  REQUIRE(t.dy() == 100.0); // should be half of the canvas height
308  REQUIRE(t.isRotating() == false);
309  REQUIRE(t.isScaling() == false);
310  }
311 
312  SECTION("Canvas size(480, 360) + view translations")
313  {
314  ViewManager v(editor);
315  v.init();
316  v.setCanvasSize(QSize(480, 360));
317 
318  v.translate(200, 200);
319 
320  QTransform t = v.getView();
321 
322  REQUIRE(t.dx() == 240.0 + 200.0); // should be half of the canvas width + translation x offset
323  REQUIRE(t.dy() == 180.0 + 200.0); // should be half of the canvas height + translation y offset
324  REQUIRE(t.isRotating() == false);
325  REQUIRE(t.isScaling() == false);
326  }
327 
328  delete editor;
329 }
330 
331 /*
332 void TestViewManager::testLoadViewFromObject1()
333 {
334  ViewManager v(mEditor);
335  v.setEditor(mEditor);
336  v.init();
337 
338  v.setCanvasSize( QSize( 100, 100 ) );
339  QTransform t = v.getView();
340  REQUIRE( t.dx(), 50.0 );
341  REQUIRE( t.dy(), 50.0 );
342 }
343 
344 void TestViewManager::testLoadViewFromObject2()
345 {
346  ViewManager v(mEditor);
347  v.setEditor(mEditor);
348  v.init();
349 
350  v.setCanvasSize( QSize( 100, 100 ) );
351  //QTransform t0;
352  //mEditor->object()->data()->setCurrentView( t0.translate( 50.0, 80.0 ) );
353  v.load(mEditor->object());
354 
355  QTransform t1 = v.getView();
356  REQUIRE( t1.dx(), 50.0 );
357  REQUIRE( t1.dy(), 50.0 ); // center of canvas
358 }
359 
360 void TestViewManager::testSetCameraKey()
361 {
362  ViewManager v(mEditor);
363  v.setEditor(mEditor);
364  v.init();
365  v.setCanvasSize( QSize( 100, 100 ) );
366 
367  // add a keyframe into camera layer whenever view change.
368  auto camLayer = mEditor->object()->getLayersByType<LayerCamera>()[ 0 ];
369  v.setCameraLayer( camLayer );
370  v.translate( 20, 20 );
371 
372  QTransform t0 = v.getView();
373 
374  Camera* c = dynamic_cast<Camera*>( camLayer->getKeyFrameAt( 1 ) );
375 
376  QTransform canvasShift = QTransform::fromTranslate(50, 50);
377  REQUIRE( t0, c->view * canvasShift);
378 }
379 */
qreal dx() const const
qreal dy() const const
bool isScaling() const const
Definition: camera.h:24
qreal x() const const
qreal y() const const
bool isIdentity() const const
bool isRotating() const const
Definition: object.h:41
Definition: editor.h:55