arena.cc

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
00003  *
00004  * This file is part of rob08
00005  *
00006  * rob08 is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 3 of the License, or
00009  * any later version.
00010  *
00011  * rob08 is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with rob08.  If not, see <http://www.gnu.org/licenses/>.
00018  */
00019 
00020 #include "config.h"
00021 #include "arena.h"
00022 
00023 #include "core.h"
00024 #include "coresync.h"
00025 #include "physics.h"
00026 #include "robIO.h"
00027 #include "trilobot.h"
00028 
00029 #ifndef BUILDING_DOX
00030 #   include <assert.h>
00031 #   include <QPainter>
00032 #   include <QTimer>
00033 #endif
00034 
00035 using std::string;
00036 using namespace StreamDecorator;
00037 
00038 static const int        dtRepaint = 50;     // 50 ms repaint period
00039 
00040 static const qreal      botPathGranulatiry = 0.1;
00041 
00042 static const qreal      botPenWidth = 2.0;
00043 static const qreal      objPenWidth = 1.0;
00044 static const qreal      envPenWidth = 3.0;
00045 
00046 // /////////////////////////////////////////////////////////////////////////////
00047 // Arena implementation
00048 struct Arena::Private {
00049     Arena       *arena;
00050     CoreSync    *cs;
00051     QTimer      timer;
00052     unsigned    ticks;
00053     QSizeF      envSize;
00054     qreal       botSize;
00055     qreal       zoomRatio;
00056     Position    botPosition;
00057     QPointF     botLastPosition;
00058     BotPath     botPath;
00059     CoreInfo    coreInfo;
00060     bool        drawSurface;
00061 
00062     void        render(QPainter &, LockedCore &);
00063     void        renderBot(QPainter &, LockedCore &);
00064     QPointF     cToA(Point);
00065     QPointF     botPosF();
00066     QPoint      botPosPx();
00067     void        drawCircle(QPainter &, const IObject &);
00068 };
00069 Arena::Arena(CoreSync *cs, QWidget *parent):
00070     QWidget(parent),
00071     d(new Private)
00072 {
00073     QWidget::setBackgroundRole(QPalette::Light);
00074 
00075     // initialize members
00076     d->arena        = this;
00077     d->cs           = cs;
00078     d->ticks        = 0;
00079     d->drawSurface  = false;
00080 
00081     // lock core (till end of block)
00082     LockedCore core(cs);
00083 
00084     // set correct widget size
00085     const Point &rightTop = core->GetEnviroment().RightTop();
00086     d->envSize.setWidth(rightTop.x);
00087     d->envSize.setHeight(rightTop.y);
00088     assert(d->envSize.isValid());
00089     this->zoom(1.0);
00090 
00091     // read bot position and size
00092     d->botPosition = core->GetTrilobot().Position();
00093     d->botLastPosition = d->botPosF();
00094     d->botPath.addPos(d->botLastPosition);
00095     d->botSize = core->GetTrilobot().Size();
00096     assert(0.0 < d->botSize);
00097     readCoreInfo(core, d->coreInfo);
00098 
00099     // initialize timer
00100     QTimer &timer = d->timer;
00101     connect(&timer, SIGNAL(timeout()), this, SLOT(animate()));
00102     timer.start(dtRepaint);
00103 }
00104 Arena::~Arena() {
00105     d->timer.stop();
00106     delete d;
00107 }
00108 QSize Arena::envSize() const {
00109     QSize size(
00110             static_cast<int>(d->envSize.width()),
00111             static_cast<int>(d->envSize.height()));
00112     assert(size.isValid());
00113     return size;
00114 }
00115 int Arena::botSize() const {
00116     return static_cast<int>(d->botSize * d->zoomRatio);
00117 }
00118 const CoreInfo& Arena::coreInfo() const {
00119     return d->coreInfo;
00120 }
00121 void Arena::animate() {
00122     d->ticks ++;
00123     this->repaint();
00124 }
00125 void Arena::zoom(qreal ratio) {
00126     assert(0.0 < ratio);
00127     d->zoomRatio = ratio;
00128 
00129     // compute real size
00130     QSizeF size(d->envSize);
00131     size += QSizeF(envPenWidth*2.0, envPenWidth*2.0);
00132     size *= ratio;
00133 
00134     // compute environment size in pixels
00135     QSize pxSize(
00136             static_cast<int>(size.width()),
00137             static_cast<int>(size.height())
00138             );
00139     assert(pxSize.isValid());
00140     this->setFixedSize(pxSize);
00141 
00142     // scrool to view
00143     emit preferredPosChanged(d->botPosPx());
00144 }
00145 void Arena::setShrinkPathEnabled(bool enabled) {
00146     d->botPath.setShrinkEnabled(enabled);
00147     //this->repaint();
00148 }
00149 void Arena::setDrawSurfaceEnabled(bool enabled) {
00150     d->drawSurface = enabled;
00151     //this->repaint();
00152 }
00153 void Arena::paintEvent(QPaintEvent *) {
00154     // lock core (till end of block)
00155     LockedCore core(d->cs);
00156     d->botPosition = core->GetTrilobot().Position();
00157     readCoreInfo(core, d->coreInfo);
00158 
00159     // initialize Qt painting system
00160     QPainter painter;
00161     painter.begin(this);
00162     if (d->zoomRatio < 3.0)
00163         painter.setRenderHints(QPainter::Antialiasing|QPainter::SmoothPixmapTransform);
00164     else
00165         painter.setRenderHint(QPainter::Antialiasing);
00166 
00167     // apply zoom ratio
00168     QMatrix matrix;
00169     matrix.translate(0, this->size().height());
00170     matrix.scale(d->zoomRatio, -d->zoomRatio);
00171     painter.setMatrix(matrix);
00172 
00173     // render
00174     d->render(painter, core);
00175 
00176     // deinitialize Qt painting system
00177     painter.end();
00178 
00179     if (d->botLastPosition != d->botPosF()) {
00180         d->botLastPosition = d->botPosF();
00181 
00182         // break repaint recursion using event loop
00183         QTimer::singleShot(0, this, SLOT(botPosChanged()));
00184     }
00185 }
00186 void Arena::botPosChanged() {
00187     d->botPath.addPos(d->botLastPosition);
00188     emit coreInfoChanged();
00189     emit preferredPosChanged(d->botPosPx());
00190 }
00191 void Arena::Private::render(QPainter &painter, LockedCore &core) {
00192     // draw environment margin
00193     const qreal envOffset = envPenWidth/2.0;
00194     QRectF envRect(envOffset, envOffset,
00195             envSize.width() + envPenWidth,
00196             envSize.height() + envPenWidth);
00197     QPen envPen(QBrush(Qt::black), envPenWidth, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
00198     painter.setPen(envPen);
00199     painter.drawRect(envRect);
00200 
00201     // move inner objects relative to margin
00202     QMatrix matrix;
00203     matrix.translate(envPenWidth, envPenWidth);
00204     painter.setMatrix(matrix, true);
00205 
00206     // draw objects
00207     const IObjectContainer &objs = core->GetEnviroment().Objects();
00208     for(unsigned i=0; i<objs.size(); i++)
00209         drawCircle(painter, *(objs[i]));
00210 
00211     // draw bot path
00212     botPath.drawPath(painter);
00213 
00214     // initialize bot matrix
00215     QMatrix botMatrix;
00216     QPointF botPos(cToA(botPosition));
00217     botMatrix.translate(botPos.x(), botPos.y());
00218     botMatrix.rotate(- botPosition.angle);
00219 
00220     // draw Trilobot
00221     QMatrix mSaved(painter.matrix());
00222     painter.setMatrix(botMatrix, true);
00223     renderBot(painter, core);
00224     painter.setMatrix(mSaved);
00225 }
00226 void Arena::Private::renderBot(QPainter &painter, LockedCore &core) {
00227     Trilobot &bot = core->GetTrilobot();
00228     const qreal size = bot.Size() - botPenWidth/2.0;
00229 
00230     // set gradient
00231     const QColor fgColor("#444");
00232     const QColor bgColor("#CCC");
00233     QRadialGradient gradient(QPointF(), bot.Size());
00234     gradient.setColorAt(0, bgColor);
00235     gradient.setColorAt(1, fgColor);
00236 
00237     // blink
00238     QBrush brush(gradient);
00239     if (!(ticks%16))
00240         brush = QBrush(Qt::green);
00241     QPen botPen(brush, botPenWidth, Qt::SolidLine, Qt::RoundCap);
00242 
00243     // draw bot
00244     painter.setPen(botPen);
00245     painter.setBrush(QBrush());
00246     painter.drawEllipse(QPointF(), size, size);
00247     painter.drawLine(QPointF(0, 0), QPointF(0, size));
00248 }
00249 QPointF Arena::Private::cToA(Point p) {
00250     return QPointF(p.x, p.y);
00251 }
00252 void Arena::Private::drawCircle(QPainter &painter, const IObject &cObj) {
00253     // don't tell kubson anything and everything will be good
00254     IObject &obj = const_cast<IObject &>(cObj);
00255     const qreal size = obj.Size() - objPenWidth/2.0;
00256     const QPointF center = cToA(obj.Position());
00257 
00258     // initialize matrix
00259     QMatrix matrix;
00260     matrix.translate(center.x(), center.y());
00261     matrix.scale(size, size);
00262 
00263     // set pen/brush
00264     const QColor color("#C00");
00265     QBrush brush;
00266     if (drawSurface) {
00267         brush = QBrush(color, Qt::HorPattern);
00268         QMatrix brushMatrix(matrix.inverted());
00269         brushMatrix.scale(0.5, 0.5);
00270         brush.setMatrix(brushMatrix);
00271     }
00272     painter.setPen(QPen(color, objPenWidth/size));
00273 
00274     // draw circle
00275     QMatrix mSaved(painter.matrix());
00276     matrix.rotate(-45);
00277     painter.setMatrix(matrix, true);
00278     painter.setBrush(QBrush(Qt::white));
00279     painter.drawEllipse(QPointF(), 1.0, 1.0);
00280     if (drawSurface) {
00281         painter.setBrush(brush);
00282         painter.drawEllipse(QPointF(), 1.0, 1.0);
00283     }
00284     painter.setMatrix(mSaved);
00285 }
00286 QPointF Arena::Private::botPosF() {
00287     return cToA(botPosition);
00288 }
00289 QPoint Arena::Private::botPosPx() {
00290     QMatrix matrix;
00291     matrix.translate(0, arena->size().height());
00292     matrix.scale(zoomRatio, -zoomRatio);
00293     matrix.translate(envPenWidth, envPenWidth);
00294 
00295     QPointF pos(matrix.map(botLastPosition));
00296     return QPoint(
00297         static_cast<int>(pos.x()),
00298         static_cast<int>(pos.y()));
00299 }
00300 
00301 // /////////////////////////////////////////////////////////////////////////////
00302 // BotPath implementation
00303 struct BotPath::Private {
00304     bool            first;
00305     bool            shrinkEnabled;
00306     QPointF         last;
00307     QPainterPath    path;
00308     QPainterPath    fullPath;
00309 
00310     bool            farFromLast(QPointF);
00311     void            shrink();
00312 };
00313 BotPath::BotPath():
00314     d(new Private)
00315 {
00316     d->first = true;
00317     d->shrinkEnabled = true;
00318 }
00319 BotPath::~BotPath() {
00320     delete d;
00321 }
00322 void BotPath::addPos(QPointF pos) {
00323     if (d->first) {
00324         d->first = false;
00325         d->last = pos;
00326         d->path.moveTo(pos);
00327         d->fullPath.moveTo(pos);
00328         return;
00329     }
00330     if (d->farFromLast(pos)) {
00331         d->last = pos;
00332         d->path.lineTo(pos);
00333         d->fullPath.lineTo(pos);
00334         if (256 <= d->path.elementCount())
00335             d->shrink();
00336     }
00337 }
00338 void BotPath::drawPath(QPainter &painter) {
00339     QPen pen(Qt::black, 0.5, Qt::DotLine);
00340     painter.setPen(pen);
00341     painter.setBrush(QBrush());
00342     painter.drawPath(d->shrinkEnabled
00343             ? d->path
00344             : d->fullPath
00345             );
00346 }
00347 void BotPath::setShrinkEnabled(bool enabled) {
00348     d->shrinkEnabled = enabled;
00349 }
00350 bool BotPath::Private::farFromLast(QPointF pos) {
00351     const qreal dx = last.x() - pos.x();
00352     const qreal dy = last.y() - pos.y();
00353     const qreal squareOfDist = dx*dx + dy*dy;
00354     return botPathGranulatiry < squareOfDist;
00355 }
00356 void BotPath::Private::shrink() {
00357 #if DEBUG_SHRINK_PATH
00358     std::cerr << "BotPath: "
00359         << Color(C_YELLOW) << "shrinking path" 
00360         << Color(C_NO_COLOR) << ": " << path.elementCount() << " -> "
00361         << std::flush;
00362 #endif
00363     QPainterPath shrinked;
00364     shrinked.moveTo(path.elementAt(4));
00365 
00366     const unsigned size = path.elementCount();
00367     for (unsigned i = 5; i < size; i++) {
00368         QPointF current(path.elementAt(i));
00369         if (!(i % 64))
00370             continue;
00371         shrinked.lineTo(current);
00372     }
00373 
00374     path = shrinked;
00375 #if DEBUG_SHRINK_PATH
00376     std::cerr << path.elementCount() << std::endl;
00377 #endif
00378 }

Generated on Fri Jul 10 22:42:01 2009 for rob08 by  doxygen 1.5.4