209 lines
6.7 KiB
C++
Executable File
209 lines
6.7 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "icons.h"
|
|
#include "polygons.h"
|
|
|
|
#include <AreaEffectSimulation/aes.hpp>
|
|
#include <LtsCoordTrans/lts_coord_trans.h>
|
|
#include <QGuiApplication>
|
|
#include <QIcon>
|
|
#include <QPainter>
|
|
#include <QPixmap>
|
|
#include <QTransform>
|
|
|
|
namespace AreaEffectSimulation
|
|
{
|
|
namespace Icons
|
|
{
|
|
|
|
// Todo: Remove
|
|
const int NEBEL = 1;
|
|
|
|
struct PolygonData
|
|
{
|
|
QPolygonF poly;
|
|
QColor color;
|
|
Qt::BrushStyle fillPattern = Qt::NoBrush;
|
|
|
|
PolygonData() = default;
|
|
PolygonData(const QPolygonF &_poly,
|
|
const QColor &_color,
|
|
const Qt::BrushStyle &_fillPattern)
|
|
: poly(_poly)
|
|
, color(_color)
|
|
, fillPattern(_fillPattern)
|
|
{}
|
|
};
|
|
|
|
static QPixmap pixmapFromPolygons(const QVector<PolygonData> &datas,
|
|
int width,
|
|
const QColor &bgcolor = Qt::transparent)
|
|
{
|
|
if (datas.isEmpty() || datas.first().poly.isEmpty())
|
|
return {};
|
|
|
|
QPolygonF polyUtm;
|
|
QVector<QPolygonF> polysUtm;
|
|
polysUtm.reserve(datas.size() * 10);
|
|
int zone = LtsCoordTrans::UtmCoordinate::fromGeographic(datas.first().poly.first()).zone;
|
|
for (const PolygonData &data : datas)
|
|
{
|
|
polyUtm.clear();
|
|
for (const QPointF &point : qAsConst(data.poly))
|
|
{
|
|
LtsCoordTrans::UtmCoordinate pointUtm = LtsCoordTrans::UtmCoordinate::fromGeographic(point, zone);
|
|
polyUtm << QPointF(pointUtm.x, pointUtm.y);
|
|
}
|
|
polysUtm << polyUtm;
|
|
}
|
|
|
|
QPolygonF bounding;
|
|
bounding.reserve(4 * datas.size());
|
|
// Does not matter, how the total polygon looks as we just need the bounding rect.
|
|
// << is cheaper than .united()
|
|
for (const QPolygonF &polyUtmLocal : qAsConst(polysUtm))
|
|
bounding << polyUtmLocal;
|
|
|
|
// center to center / Todo:: Does it always work?
|
|
const QTransform mTrans(QTransform::fromTranslate(-bounding.boundingRect().bottomLeft().x(), -bounding.boundingRect().bottomLeft().y()));
|
|
|
|
const auto dpr = qApp->devicePixelRatio();
|
|
width *= dpr;
|
|
qreal w = bounding.boundingRect().width();
|
|
qreal h = bounding.boundingRect().height();
|
|
double scale = w > h ? width / w : width / h;
|
|
w *= scale;
|
|
h *= scale;
|
|
scale *= 0.96; // Leave 4% border (i.e. 2% each side)
|
|
const QTransform mScale(QTransform::fromScale(scale, -scale));
|
|
const QTransform mTransSmall(QTransform::fromTranslate(0.02 * width + (width - w) / 2, 0.02 * width + (width - h) / 2));
|
|
|
|
QPixmap pix(width, width);
|
|
pix.setDevicePixelRatio(dpr);
|
|
pix.fill(bgcolor);
|
|
|
|
QPainter p(&pix);
|
|
int i = 0;
|
|
for (const PolygonData &d : qAsConst(datas))
|
|
{
|
|
QPolygonF mPoly = mTrans.map(polysUtm.at(i++));
|
|
mPoly = mScale.map(mPoly);
|
|
mPoly = mTransSmall.map(mPoly);
|
|
|
|
|
|
p.setBrush(QBrush(d.color, d.fillPattern));
|
|
p.setPen(QPen(p.brush(), 2));
|
|
p.drawPolygon(mPoly);
|
|
}
|
|
p.end();
|
|
|
|
return pix;
|
|
}
|
|
|
|
static QPixmap pixmapFromPolygon(const QPolygonF &poly,
|
|
const QColor &color,
|
|
const Qt::BrushStyle &fillPattern,
|
|
const int width,
|
|
const QColor &bgcolor = Qt::transparent)
|
|
{
|
|
return pixmapFromPolygons({PolygonData(poly, color, fillPattern)}, width, bgcolor);
|
|
}
|
|
|
|
QIcon nContamination(const Database::AesNContamination &awf, int size)
|
|
{
|
|
const QPolygonF poly = Polygons::nContamination(awf);
|
|
return QIcon(pixmapFromPolygon(poly, Qt::yellow, Qt::Dense4Pattern, size, QColor(0, 0, 0, 128)));
|
|
}
|
|
|
|
QIcon bcContamination(const Database::AesBCContamination &cwf,
|
|
ProjectDataManagement::VolatilityType volatilityType,
|
|
double expansionFactor,
|
|
const QDateTime ¤tTime,
|
|
int size)
|
|
{
|
|
const QPolygonF poly = Polygons::bcContamination(cwf, volatilityType, expansionFactor, currentTime);
|
|
return QIcon(pixmapFromPolygon(poly, Qt::yellow, Qt::Dense4Pattern, size, QColor(0, 0, 0, 128)));
|
|
}
|
|
|
|
QIcon explosionSingle(const Database::AesExplosionSingle &es, double chargeRadius, int size)
|
|
{
|
|
QPolygonF poly = Polygons::explosionSingle(es, chargeRadius);
|
|
|
|
// Todo!
|
|
QColor color = (es.chargeTypeId == NEBEL) ? Qt::lightGray : Qt::yellow;
|
|
QColor bgrnd = Qt::transparent;
|
|
if (es.chargeTypeId != NEBEL) // Nebel / Smoke
|
|
{
|
|
color = Qt::red; // Todo: Teamcolor! teams->color(ef.partei_id);
|
|
bgrnd = QColor(0, 0, 0, 128);
|
|
}
|
|
return QIcon(pixmapFromPolygon(poly, color, Qt::Dense4Pattern, size, bgrnd));
|
|
}
|
|
|
|
QIcon explosionArea(const Database::AesExplosionArea &ea, int size)
|
|
{
|
|
// Todo!
|
|
QColor color = (ea.chargeTypeId == NEBEL) ? Qt::lightGray : Qt::yellow;
|
|
QColor bgrnd = Qt::transparent;
|
|
if (ea.chargeTypeId != NEBEL) // Nebel / Smoke
|
|
{
|
|
color = Qt::red; // Todo: Teamcolor! teams->color(ff.partei_id);
|
|
bgrnd = QColor(0, 0, 0, 128);
|
|
}
|
|
QPolygonF area = Polygons::explosionArea(ea);
|
|
return QIcon(pixmapFromPolygon(area, color, Qt::Dense4Pattern, size, bgrnd));
|
|
}
|
|
|
|
QIcon explosionAreaSingleExplosions(const Database::AesExplosionArea &ea, int size)
|
|
{
|
|
// Todo!
|
|
QColor color = (ea.chargeTypeId == NEBEL) ? Qt::lightGray : Qt::yellow;
|
|
if (ea.chargeTypeId != NEBEL) // Nebel / Smoke
|
|
color = Qt::red; // Todo: Teamcolor! teams->color(ea.partei_id);
|
|
|
|
const QVector<QPointF> singleExplosions = Polygons::explosionAreaSingleExplosions(ea);
|
|
QVector<PolygonData> datas;
|
|
datas.reserve(singleExplosions.size() + 1);
|
|
datas << PolygonData(Polygons::explosionArea(ea), color, Qt::Dense4Pattern);
|
|
for (const QPointF &explosion : singleExplosions)
|
|
{
|
|
/* TODO
|
|
if (explosion.time() < QDateTime::currentMSecsSinceEpoch())
|
|
datas << PolygonData(Polygons::circle(explosion.position(), 5), Qt::yellow, Qt::Dense4Pattern);
|
|
else
|
|
*/
|
|
datas << PolygonData(Polygons::circle(explosion, 5), Qt::green, Qt::Dense4Pattern);
|
|
}
|
|
|
|
return QIcon(pixmapFromPolygons(datas, size));
|
|
}
|
|
|
|
QIcon mineArea(const Database::AesMineArea &area, const QVector<Database::AesMineAreaSegment> &segments, int size)
|
|
{
|
|
QPolygonF gesamtPolygon = Polygons::mineArea(segments, area.width, area.density, area.isCenterLine);
|
|
|
|
const QVector<QPointF> minePositions = Polygons::minePositions(area, segments);
|
|
QVector<PolygonData> datas;
|
|
datas.reserve(minePositions.size() + 1);
|
|
datas << PolygonData(gesamtPolygon, Qt::green, Qt::Dense4Pattern);
|
|
for (const QPointF minePos : minePositions)
|
|
datas << PolygonData(Polygons::circle(minePos, 5), Qt::red, Qt::Dense4Pattern);
|
|
|
|
return QIcon(pixmapFromPolygons(datas, size));
|
|
}
|
|
|
|
|
|
QIcon mineCorridor(const QVector<Database::AesMineCorridorSegment> &segments, int width, int size)
|
|
{
|
|
const QPolygonF poly = Polygons::mineCorridor(segments, width);
|
|
return QIcon(pixmapFromPolygon(poly, Qt::yellow, Qt::Dense4Pattern, size, QColor(0, 0, 0, 128)));
|
|
}
|
|
|
|
} // Namespace
|
|
} // Namespace
|