#include "winter.h"
#include "misc.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QPen>
SnowFlake::SnowFlake(QGraphicsScene *scene)
{
size=qrand()%10+3;
int s4=size/4;
int s3=size/3;
int s6=size/6;
for (int a=0; a<6; a++)
{
lines.append(scene->addLine(0, -s6, 0, -size));
lines.last()->setRotation(a*60);
lines.append(scene->addLine(-s4, -size + s6, 0, -size + s3));
lines.last()->setRotation(a*60);
lines.append(scene->addLine( s4, -size + s6, 0, -size + s3));
lines.last()->setRotation(a*60);
}
QPen p(Qt::white);
foreach (QGraphicsLineItem *l, lines)
{
l->setZValue(1000);
l->setPen(p);
l->setParentItem(this);
}
dv=QPointF(qrand()%10/10.0-0.5, qrand()%10/10.0 +1);
da=qrand()%20 / 10.0 - 1;
}
SnowFlake::~SnowFlake()
{
//qDebug()<<"Destr. SnowFlake";
while(lines.isEmpty())
delete lines.takeFirst();
}
QRectF SnowFlake::boundingRect() const
{
return QRectF (-size, -size, size*2, size*2);
}
void SnowFlake::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
{
}
void SnowFlake::animate()
{
moveBy(dv.x() + dblow.x(), dv.y() + dblow.y());
setRotation(rotation() + da);
dblow = dblow *0.9;
}
void SnowFlake::blow(const QPointF &v)
{
dblow=v;
}
Winter::Winter(QGraphicsView *v)
{
view=v;
updateView();
/*
test=view->scene()->addLine(
QLineF(viewRect.topLeft(), viewRect.bottomRight()),
QPen(Qt::blue) );
*/
maxFlakes=1500;
maxFalling=140;
maxUnfreeze=50;
makeSnow();
animTimer = new QTimer;
connect (animTimer, SIGNAL (timeout()), this, SLOT (animate() ));
animTimer->start(50);
snowTimer = new QTimer;
connect (snowTimer, SIGNAL (timeout()), this, SLOT (makeSnow() ));
snowTimer->start(1000);
}
Winter::~Winter()
{
delete animTimer;
delete snowTimer;
while (!fallingSnow.isEmpty())
delete fallingSnow.takeFirst();
while (!frozenSnow.isEmpty())
delete frozenSnow.takeFirst();
}
void Winter::updateView()
{
QPointF p0=view->mapToScene( QPoint(0,0));
QPointF p1=view->mapToScene( view->rect().width(), view->rect().height() );
viewRect=QRectF(p0,p1);
}
void Winter::setObstacles(QList <QRectF> obslist)
{
obstacles=obslist;
QList <SnowFlake*> unfreeze;
// Find frozen snowflakes, which are free again
QPointF p;
int i=0;
bool frozen;
while (i < frozenSnow.count())
{
p=frozenSnow.at(i)->pos();
frozen=false;
int j=0;
while (j<obstacles.count() && !frozen)
{
if (obstacles.at(j).contains(p) )
frozen=true;
j++;
}
if (!frozen)
{
unfreeze.append(frozenSnow.at(i));
frozenSnow.removeAt(i);
} else
i++;
}
// Remove some flakes, if too many
while (fallingSnow.count() + unfreeze.count() > maxFalling + maxUnfreeze)
delete unfreeze.takeFirst();
while (!unfreeze.isEmpty())
{
// Blow a bit up
unfreeze.first()->blow( QPointF(qrand()%10/10.0-0.5, qrand()%10/10.0 -5));
fallingSnow.append(unfreeze.takeFirst());
}
}
void Winter::animate()
{
updateView();
//test->setLine(QLineF(viewRect.topLeft(), viewRect.bottomRight()));
QPointF p;
int i=0;
bool cont;
while (i<fallingSnow.count())
{
p=fallingSnow.at(i)->pos();
cont=true;
int j=0;
while (j<obstacles.count() && cont)
{
if (obstacles.at(j).contains(p) && qrand()%(obstacles.count()+1) > obstacles.count()-1)
{
// Freeze snowflake on obstacle
// Probality is equale for obstacles or falling through
frozenSnow.append(fallingSnow.at(i));
fallingSnow.removeAt(i);
cont=false;
}
j++;
}
if (cont && p.y() > viewRect.y() + viewRect.height() + 20)
{
delete fallingSnow.takeAt(i);
cont=false;
}
// Let snowflake fall further
if (cont) fallingSnow.at(i)->animate();
i++;
}
}
void Winter::makeSnow()
{
//qDebug()<<"falling: "<<fallingSnow.count()<<" frozen: "<<frozenSnow.count();
if (fallingSnow.count() + frozenSnow.count() <maxFlakes)
{
if (fallingSnow.count() < maxFalling)
{
// Create more snowflakes
SnowFlake *snowflake;
for (int i=0; i<10; i++)
{
snowflake=new SnowFlake(view->scene());
snowflake->setPos( 0,0);
snowflake->setRotation(qrand()%60);
view->scene()->addItem(snowflake);
snowflake->setPos(
rand()%round_int(viewRect.width()) + viewRect.x(),
viewRect.y() -20
);
fallingSnow.append(snowflake);
}
}
} else
{
// Remove some of the existing frozen flakes
for (int i=0; i<10; i++)
{
if (frozenSnow.count()>0)
{
int j=qrand()%frozenSnow.count();
delete frozenSnow.takeAt(j);
}
}
}
}