examples/animation/stickman/stickman.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    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 
       
    55 static 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 
       
    81 static 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 
       
   115 StickMan::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 
       
   143 StickMan::~StickMan()
       
   144 {
       
   145 }
       
   146 
       
   147 void StickMan::childPositionChanged()
       
   148 {
       
   149     prepareGeometryChange();
       
   150 }
       
   151 
       
   152 void 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 
       
   161 QRectF 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 
       
   167 int StickMan::nodeCount() const
       
   168 {
       
   169     return NodeCount;
       
   170 }
       
   171 
       
   172 Node *StickMan::node(int idx) const
       
   173 {
       
   174     if (idx >= 0 && idx < NodeCount)
       
   175         return m_nodes[idx];
       
   176     else
       
   177         return 0;
       
   178 }
       
   179 
       
   180 void StickMan::timerEvent(QTimerEvent *)
       
   181 {
       
   182     update();
       
   183 }
       
   184 
       
   185 void 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 
       
   214 QPointF StickMan::posFor(int idx) const
       
   215 {
       
   216     return m_nodes[idx]->pos();
       
   217 }
       
   218 
       
   219 //#include <QTime>
       
   220 void 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