source: trunk/examples/animation/stickman/stickman.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 8.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "stickman.h"
43#include "node.h"
44
45#include <QPainter>
46#include <QTimer>
47
48#define _USE_MATH_DEFINES
49#include <math.h>
50
51#ifndef M_PI
52#define M_PI 3.14159265358979323846
53#endif
54
55static const qreal Coords[NodeCount * 2] = {
56 0.0, -150.0, // head, #0
57
58 0.0, -100.0, // body pentagon, top->bottom, left->right, #1 - 5
59 -50.0, -50.0,
60 50.0, -50.0,
61 -25.0, 50.0,
62 25.0, 50.0,
63
64 -100.0, 0.0, // right arm, #6 - 7
65 -125.0, 50.0,
66
67 100.0, 0.0, // left arm, #8 - 9
68 125.0, 50.0,
69
70 -35.0, 75.0, // lower body, #10 - 11
71 35.0, 75.0,
72
73 -25.0, 200.0, // right leg, #12 - 13
74 -30.0, 300.0,
75
76 25.0, 200.0, // left leg, #14 - 15
77 30.0, 300.0
78
79};
80
81static const int Bones[BoneCount * 2] = {
82 0, 1, // neck
83
84 1, 2, // body
85 1, 3,
86 1, 4,
87 1, 5,
88 2, 3,
89 2, 4,
90 2, 5,
91 3, 4,
92 3, 5,
93 4, 5,
94
95 2, 6, // right arm
96 6, 7,
97
98 3, 8, // left arm
99 8, 9,
100
101 4, 10, // lower body
102 4, 11,
103 5, 10,
104 5, 11,
105 10, 11,
106
107 10, 12, // right leg
108 12, 13,
109
110 11, 14, // left leg
111 14, 15
112
113};
114
115StickMan::StickMan()
116{
117 m_sticks = true;
118 m_isDead = false;
119 m_pixmap = QPixmap("images/head.png");
120 m_penColor = Qt::white;
121 m_fillColor = Qt::black;
122
123 // Set up start position of limbs
124 for (int i=0; i<NodeCount; ++i) {
125 m_nodes[i] = new Node(QPointF(Coords[i * 2], Coords[i * 2 + 1]), this);
126 connect(m_nodes[i], SIGNAL(positionChanged()), this, SLOT(childPositionChanged()));
127 }
128
129 for (int i=0; i<BoneCount; ++i) {
130 int n1 = Bones[i * 2];
131 int n2 = Bones[i * 2 + 1];
132
133 Node *node1 = m_nodes[n1];
134 Node *node2 = m_nodes[n2];
135
136 QPointF dist = node1->pos() - node2->pos();
137 m_perfectBoneLengths[i] = sqrt(pow(dist.x(),2) + pow(dist.y(),2));
138 }
139
140 startTimer(10);
141}
142
143StickMan::~StickMan()
144{
145}
146
147void StickMan::childPositionChanged()
148{
149 prepareGeometryChange();
150}
151
152void StickMan::setDrawSticks(bool on)
153{
154 m_sticks = on;
155 for (int i=0;i<nodeCount();++i) {
156 Node *node = m_nodes[i];
157 node->setVisible(on);
158 }
159}
160
161QRectF StickMan::boundingRect() const
162{
163 // account for head radius=50.0 plus pen which is 5.0
164 return childrenBoundingRect().adjusted(-55.0, -55.0, 55.0, 55.0);
165}
166
167int StickMan::nodeCount() const
168{
169 return NodeCount;
170}
171
172Node *StickMan::node(int idx) const
173{
174 if (idx >= 0 && idx < NodeCount)
175 return m_nodes[idx];
176 else
177 return 0;
178}
179
180void StickMan::timerEvent(QTimerEvent *)
181{
182 update();
183}
184
185void StickMan::stabilize()
186{
187 static const qreal threshold = 0.001;
188
189 for (int i=0; i<BoneCount; ++i) {
190 int n1 = Bones[i * 2];
191 int n2 = Bones[i * 2 + 1];
192
193 Node *node1 = m_nodes[n1];
194 Node *node2 = m_nodes[n2];
195
196 QPointF pos1 = node1->pos();
197 QPointF pos2 = node2->pos();
198
199 QPointF dist = pos1 - pos2;
200 qreal length = sqrt(pow(dist.x(),2) + pow(dist.y(),2));
201 qreal diff = (length - m_perfectBoneLengths[i]) / length;
202
203 QPointF p = dist * (0.5 * diff);
204 if (p.x() > threshold && p.y() > threshold) {
205 pos1 -= p;
206 pos2 += p;
207
208 node1->setPos(pos1);
209 node2->setPos(pos2);
210 }
211 }
212}
213
214QPointF StickMan::posFor(int idx) const
215{
216 return m_nodes[idx]->pos();
217}
218
219//#include <QTime>
220void StickMan::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
221{
222 /* static int frames = 0;
223 static QTime time;
224 if (frames++ % 100 == 0) {
225 frames = 1;
226 time.restart();
227 }
228
229 if (time.elapsed() > 0) {
230 painter->setPen(Qt::white);
231 painter->drawText(0, 0, QString::number(frames / (time.elapsed() / 1000.0)));
232 }*/
233
234 stabilize();
235 if (m_sticks) {
236 painter->setPen(Qt::white);
237 for (int i=0; i<BoneCount; ++i) {
238 int n1 = Bones[i * 2];
239 int n2 = Bones[i * 2 + 1];
240
241 Node *node1 = m_nodes[n1];
242 Node *node2 = m_nodes[n2];
243
244 painter->drawLine(node1->pos(), node2->pos());
245 }
246 } else {
247 // first bone is neck and will be used for head
248
249 QPainterPath path;
250 path.moveTo(posFor(0));
251 path.lineTo(posFor(1));
252
253 // right arm
254 path.lineTo(posFor(2));
255 path.lineTo(posFor(6));
256 path.lineTo(posFor(7));
257
258 // left arm
259 path.moveTo(posFor(3));
260 path.lineTo(posFor(8));
261 path.lineTo(posFor(9));
262
263 // body
264 path.moveTo(posFor(2));
265 path.lineTo(posFor(4));
266 path.lineTo(posFor(10));
267 path.lineTo(posFor(11));
268 path.lineTo(posFor(5));
269 path.lineTo(posFor(3));
270 path.lineTo(posFor(1));
271
272 // right leg
273 path.moveTo(posFor(10));
274 path.lineTo(posFor(12));
275 path.lineTo(posFor(13));
276
277 // left leg
278 path.moveTo(posFor(11));
279 path.lineTo(posFor(14));
280 path.lineTo(posFor(15));
281
282 painter->setPen(QPen(m_penColor, 5.0, Qt::SolidLine, Qt::RoundCap));
283 painter->drawPath(path);
284
285 {
286 int n1 = Bones[0];
287 int n2 = Bones[1];
288 Node *node1 = m_nodes[n1];
289 Node *node2 = m_nodes[n2];
290
291 QPointF dist = node2->pos() - node1->pos();
292
293 qreal sinAngle = dist.x() / sqrt(pow(dist.x(), 2) + pow(dist.y(), 2));
294 qreal angle = asin(sinAngle) * 180.0 / M_PI;
295
296 QPointF headPos = node1->pos();
297 painter->translate(headPos);
298 painter->rotate(-angle);
299
300 painter->setBrush(m_fillColor);
301 painter->drawEllipse(QPointF(0,0), 50.0, 50.0);
302
303 painter->setBrush(m_penColor);
304 painter->setPen(QPen(m_penColor, 2.5, Qt::SolidLine, Qt::RoundCap));
305
306 // eyes
307 if (m_isDead) {
308 painter->drawLine(-30.0, -30.0, -20.0, -20.0);
309 painter->drawLine(-20.0, -30.0, -30.0, -20.0);
310
311 painter->drawLine(20.0, -30.0, 30.0, -20.0);
312 painter->drawLine(30.0, -30.0, 20.0, -20.0);
313 } else {
314 painter->drawChord(QRectF(-30.0, -30.0, 25.0, 70.0), 30.0*16, 120.0*16);
315 painter->drawChord(QRectF(5.0, -30.0, 25.0, 70.0), 30.0*16, 120.0*16);
316 }
317
318 // mouth
319 if (m_isDead) {
320 painter->drawLine(-28.0, 2.0, 29.0, 2.0);
321 } else {
322 painter->setBrush(QColor(128, 0, 64 ));
323 painter->drawChord(QRectF(-28.0, 2.0-55.0/2.0, 57.0, 55.0), 0.0, -180.0*16);
324 }
325
326 // pupils
327 if (!m_isDead) {
328 painter->setPen(QPen(m_fillColor, 1.0, Qt::SolidLine, Qt::RoundCap));
329 painter->setBrush(m_fillColor);
330 painter->drawEllipse(QPointF(-12.0, -25.0), 5.0, 5.0);
331 painter->drawEllipse(QPointF(22.0, -25.0), 5.0, 5.0);
332 }
333 }
334 }
335}
336
337
338
Note: See TracBrowser for help on using the repository browser.