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