1138 lines
35 KiB
C++
Executable File
1138 lines
35 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
#include "symbol_exporter.h"
|
|
#include "primitive.h"
|
|
#include "symbol_table.h"
|
|
#include "attribute_data.h"
|
|
#include "symbol_custom_graphics_item_group.h"
|
|
|
|
// test #include <NGLLogger/NGLLoggerBootstrap.h>
|
|
|
|
#include <QtDebug>
|
|
#include <QBrush>
|
|
#include <QBuffer>
|
|
#include <QFont>
|
|
#include <QFontDatabase>
|
|
#include <QFontMetrics>
|
|
#include <QGraphicsPathItem>
|
|
#include <QGraphicsScene>
|
|
#include <QMetaType>
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QPen>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
namespace SymbologyXML
|
|
{
|
|
|
|
#define BOUNDING_RECT 423
|
|
#define HEADQUARTER_LINE 424
|
|
|
|
#define REDUCE_LINEWIDTH_F 4./5 // 80 %
|
|
#define LINEWIDTH_FRAME_SOLID 0.04
|
|
#define LINEWIDTH_FRAME_DASHED_DOTTED 0.08
|
|
#define LINEWIDTH_HEADQUARTER 0.06
|
|
|
|
static const bool BLACK_AND_WHITE_DOTTED_LINE = true;
|
|
|
|
static QFont* defaultFont = nullptr;
|
|
|
|
static const QFont::StyleStrategy defaultStyleStrategy = QFont::PreferAntialias;
|
|
|
|
|
|
bool isColorOfOwnForce(const QColor& color)
|
|
{
|
|
// Sind wir bei der 'eigenen' Partei? (Hack über die Farben)
|
|
return ( ( (color.red() == 0xFF) && (color.green() == 0x0 ) && (color.blue() == 0x0 ) ) // color of team 'red' (0xFF0000)
|
|
|| ( (color.red() == 0xFF) && (color.green() == 0x7F) && (color.blue() == 0x7F) ) // lightcolor of team 'red' (0xFF7F7F)
|
|
);
|
|
}
|
|
|
|
|
|
|
|
void SymbolExporter::drawFrameSymbol(const Symbol& symbol,
|
|
const SymbolTypes::AdditionalSymbolData& additionalData,
|
|
QGraphicsScene* scene, const QColor& color, const QColor& fillColor,
|
|
double z, bool antialias)
|
|
{
|
|
Q_UNUSED(antialias);
|
|
|
|
SymbolTypes::t_affil affil = symbol.getAffil();
|
|
|
|
Primitive::t_linestyle linestyleSymbol = Primitive::SOLID;
|
|
if((affil == SymbolTypes::ASSUMED_FRIEND) ||
|
|
(affil == SymbolTypes::SUSPECT) ||
|
|
(affil == SymbolTypes::PENDING)) {
|
|
linestyleSymbol = Primitive::DOTTED;
|
|
} else {
|
|
if(additionalData.m_uncertainty == SymbolTypes::UNCERTAINTY_UNCERTAIN) {
|
|
linestyleSymbol = Primitive::DOTTED;
|
|
} else if(additionalData.m_state == SymbolTypes::STATE_ANTICIPATED) {
|
|
linestyleSymbol = Primitive::DASHED;
|
|
}
|
|
}
|
|
// Draw all primitives of the frame symbol
|
|
QLinkedList<Primitive*>p = symbol.getPrimitives();
|
|
QLinkedListIterator<Primitive*> piter(p);
|
|
|
|
while ( piter.hasNext() ) {
|
|
Primitive prim = *piter.next();
|
|
double lineWidth = prim.getLineWidth();
|
|
if(lineWidth >= 0) {
|
|
if(linestyleSymbol == Primitive::SOLID) {
|
|
lineWidth = LINEWIDTH_FRAME_SOLID;
|
|
} else {
|
|
lineWidth = LINEWIDTH_FRAME_DASHED_DOTTED;
|
|
}
|
|
prim.setLineStyle(linestyleSymbol);
|
|
} else { // lineWidth < 0 :
|
|
prim.setLineStyle(Primitive::SOLID);
|
|
}
|
|
if (additionalData.m_filltype == SymbolTypes::FILLTYPE_OUTLINED) {
|
|
prim.setLineWidth(lineWidth*2.0);
|
|
}
|
|
else {
|
|
prim.setLineWidth(lineWidth);
|
|
}
|
|
bool isAttrib = true;
|
|
// filltype:
|
|
if(prim.fill()) {
|
|
// prims with filltype == FILLED : e.g. small filled rectangles for t_dimen activity
|
|
prim.setLineStyle(Primitive::SOLID);
|
|
isAttrib = false;
|
|
} else {
|
|
prim.setFill(additionalData.m_filltype == SymbolTypes::FILLTYPE_FILLED);
|
|
}
|
|
QGraphicsItem *gitem = nullptr;
|
|
if(BLACK_AND_WHITE_DOTTED_LINE &&
|
|
(linestyleSymbol == Primitive::DOTTED) && (prim.getLineStyle() == Primitive::DOTTED)) {
|
|
// additional prim (white):
|
|
Primitive prim2(prim);
|
|
prim2.setLineStyle(Primitive::SOLID);
|
|
prim2.setFill(false);
|
|
gitem = SymbolExporter::drawPrimitive(prim2, Qt::white, fillColor, z, isAttrib);
|
|
if(gitem) {
|
|
scene->addItem(gitem);
|
|
gitem->setZValue(z);
|
|
}
|
|
// current prim (black-dotted):
|
|
gitem = SymbolExporter::drawPrimitive(prim, Qt::black, fillColor, z, isAttrib);
|
|
} else {
|
|
gitem = SymbolExporter::drawPrimitive(prim, color, fillColor, z, isAttrib);
|
|
}
|
|
if(gitem) {
|
|
scene->addItem(gitem);
|
|
gitem->setZValue(z);
|
|
}
|
|
}
|
|
|
|
} // void SymbolExporter::drawFrameSymbol(const Symbol& symbol, ...
|
|
|
|
void SymbolExporter::drawHeadquarterPrims(QGraphicsScene *scene, bool headquarter,
|
|
SymbolTypes::t_dimen dimen, SymbolTypes::t_affil affil,
|
|
const QColor& color)
|
|
{
|
|
QGraphicsItem *hqItem = nullptr;
|
|
const auto items = scene->items();
|
|
for (QGraphicsItem *item : items)
|
|
{
|
|
if (item->data(HEADQUARTER_LINE).toBool())
|
|
{
|
|
hqItem = item;
|
|
break;
|
|
}
|
|
}
|
|
if (hqItem)
|
|
{
|
|
scene->removeItem(hqItem);
|
|
delete hqItem;
|
|
}
|
|
if (headquarter)
|
|
{
|
|
// headquarter:
|
|
QGraphicsLineItem *hqLine = new QGraphicsLineItem();
|
|
QPen hqLinePen;
|
|
hqLinePen.setWidthF(LINEWIDTH_HEADQUARTER);
|
|
hqLinePen.setColor(color);
|
|
hqLine->setPen(hqLinePen);
|
|
hqLine->setData(HEADQUARTER_LINE, true);
|
|
QRectF frameRect = Symbol::getSymbolFrameRect(dimen, affil);
|
|
hqLine->setLine(frameRect.left(), frameRect.center().y(), frameRect.left(), -2.0);
|
|
scene->addItem(hqLine);
|
|
}
|
|
}
|
|
|
|
void SymbolExporter::drawSymbol(const Symbol& symbol, const SymbolTypes::t_symbolTableCont& symTableCont,
|
|
QGraphicsScene* scene, const QColor& color, const QColor& fillColor,
|
|
double z, bool isAttrib, bool antialias, QFont* font_p,
|
|
QMap<QGraphicsItem*, Primitive*> *mapItemPrimitives_p, bool drawBoundRect)
|
|
{
|
|
|
|
Q_UNUSED(fillColor);
|
|
|
|
// If this Symbol should be tracked in the Primitives-Map, clear the map first
|
|
if ( mapItemPrimitives_p )
|
|
{
|
|
mapItemPrimitives_p->clear();
|
|
}
|
|
|
|
// Draw all primitives (and ICONS/TEXTS) of the given Symbol
|
|
|
|
QLinkedList<Primitive*>p = symbol.getPrimitives();
|
|
QLinkedListIterator<Primitive*> piter(p);
|
|
|
|
while ( piter.hasNext() )
|
|
{
|
|
Primitive *item = piter.next();
|
|
SymbolExporter::drawSymbolPrimitive(item, symTableCont, scene,
|
|
item->getColor().isValid() ? item->getColor() : color, item->getColor().isValid() ? item->getColor() : color,
|
|
z, isAttrib, mapItemPrimitives_p, drawBoundRect);
|
|
} // while
|
|
|
|
|
|
if ( symbol.getTextType() != Symbol::TEXT_UNDEFINED )
|
|
{
|
|
|
|
#if defined (SYMBOL_TEXT_IN_BLACK) && (SYMBOL_TEXT_IN_BLACK == 1)
|
|
// Sind wir bei der 'eigenen' Partei? (Hack über die Farben)
|
|
if ( isColorOfOwnForce(color) )
|
|
{
|
|
drawSymbolText(symbol, scene, Qt::black, antialias, font_p);
|
|
} else {
|
|
drawSymbolText(symbol, scene, color, antialias, font_p);
|
|
}
|
|
#else
|
|
drawSymbolText(symbol, scene, color, antialias, font_p);
|
|
#endif // #if defined (SYMBOL_TEXT_IN_BLACK)...
|
|
}
|
|
|
|
} // void SymbolExporter::drawSymbol(Symbol* symbol, SymbolTable* symTableSectorIcons_p...)
|
|
|
|
|
|
void SymbolExporter::drawSymbolPrimitive(Primitive *primitive,
|
|
const SymbolTypes::t_symbolTableCont& symTableCont,
|
|
QGraphicsScene* scene,
|
|
const QColor& color, const QColor& fillColor,
|
|
double z, bool isAttrib,
|
|
QMap<QGraphicsItem*, Primitive*> *mapItemPrimitives_p,
|
|
bool drawBoundRect)
|
|
{
|
|
QGraphicsItem *gitem = nullptr;
|
|
if(primitive->type() == Primitive::ICON) {
|
|
gitem = SymbolExporter::drawICON(*primitive, symTableCont, scene,
|
|
color, fillColor,
|
|
z, isAttrib, drawBoundRect);
|
|
} else if(primitive->type() == Primitive::TEXT) {
|
|
gitem = SymbolExporter::drawText(*primitive, symTableCont, scene,
|
|
color, fillColor,
|
|
z, isAttrib, drawBoundRect);
|
|
} else {
|
|
gitem = SymbolExporter::drawPrimitive(*primitive, color, fillColor, z,
|
|
isAttrib, drawBoundRect);
|
|
if(gitem) {
|
|
scene->addItem(gitem);
|
|
}
|
|
}
|
|
if(gitem) {
|
|
if(!isAttrib) {
|
|
gitem->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
|
}
|
|
gitem->setSelected(false);
|
|
gitem->setZValue(z);
|
|
|
|
if(mapItemPrimitives_p) {
|
|
mapItemPrimitives_p->operator[](gitem) = primitive;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef APP6C
|
|
void SymbolExporter::drawSymbolText(const Symbol &symbol,
|
|
QGraphicsScene* scene,
|
|
const QColor& color,
|
|
bool antialias,
|
|
QFont* font_p)
|
|
{
|
|
// first check if we really need to draw text
|
|
bool bEmpty = true;
|
|
for (int i=0; bEmpty && i<(int)symbol.getTextType(); ++i) {
|
|
bEmpty = symbol.getText(i+1).isEmpty();
|
|
}
|
|
if(bEmpty)
|
|
return;
|
|
|
|
// Find a fixed Font, if possible
|
|
QFont font = SymbolExporter::getMatchFont(font_p, antialias);
|
|
|
|
// Font ist ausgewaehlt, weiter gehts:
|
|
QFontMetricsF metrics(font);
|
|
|
|
for (int i=0; i<(int)symbol.getTextType(); ++i) {
|
|
QString txt = symbol.getText(i+1);
|
|
if(txt.length()>0) {
|
|
Symbol::t_alignment align = symbol.getTextAlign(i+1);
|
|
|
|
QGraphicsSimpleTextItem *textItem = scene->addSimpleText(txt, font);
|
|
textItem->setBrush(color);
|
|
textItem->setZValue(0.9);
|
|
|
|
// QRectF metricsRect = metrics.boundingRect(txt); // no effect
|
|
// metricsRect.moveCenter(QPointF(0.0, 0.0)); // no effect
|
|
double textHeight = metrics.height();
|
|
double textWidth = metrics.width(txt);
|
|
|
|
|
|
double maxWidth, maxHeight, leftX, topY;
|
|
if(i == 1) {
|
|
maxWidth = 1.7;
|
|
maxHeight = 0.8;
|
|
}
|
|
else {
|
|
maxWidth = 1.4;
|
|
maxHeight = 0.4;
|
|
}
|
|
if(align == Symbol::LEFT || align == Symbol::RIGHT) {
|
|
maxWidth /= 2.0;
|
|
}
|
|
|
|
double scaleX = maxWidth / textWidth;
|
|
double scaleY = maxHeight / textHeight;
|
|
double scale = 1;
|
|
if(scaleX > scaleY) {
|
|
scale = scaleY;
|
|
}
|
|
else {
|
|
scale = scaleX;
|
|
}
|
|
textItem->setTransform(QTransform::fromScale(scale, -scale), true);
|
|
textHeight*=scale;
|
|
textWidth*=scale;
|
|
|
|
|
|
if(i == 0) {
|
|
topY = 0.35+textHeight;
|
|
}
|
|
else if(i == 1) {
|
|
topY = textHeight/2;
|
|
}
|
|
else {
|
|
topY = -0.35;
|
|
}
|
|
|
|
switch (align) {
|
|
case Symbol::LEFT:
|
|
leftX = -0.7;
|
|
break;
|
|
case Symbol::RIGHT:
|
|
leftX = 0.7-textWidth;
|
|
break;
|
|
case Symbol::CENTER:
|
|
default:
|
|
leftX = -textWidth/2.0;
|
|
break;
|
|
}
|
|
|
|
textItem->setPos(leftX, topY);
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// replaced by rotation in PixmapSymboCache:
|
|
////////////////////////////////////////////////////////////////////////
|
|
// // rotation of 'text',
|
|
// int rotAngle = 60;
|
|
// textItem->setRotation(rotAngle); // angle is interpreted clockwise;
|
|
// // Qt4.6 introduced setRotation Otherwise try:
|
|
// // textItem->rotate(rotAngle); // angle is interpreted clockwise;
|
|
// // textItem->setTransform( QTransform().rotate(rotAngle), true ); // angle is interpreted clockwise;
|
|
//
|
|
// QTransform transView;
|
|
// transView.rotate(-rotAngle); // angle is interpreted counterclockwise
|
|
// textItem->setPos( transView.map(QPointF(leftX,topY)) );
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
}
|
|
|
|
} // for
|
|
} // void SymbolExporter::drawSymbolText(const Symbol &symbol, ...
|
|
#else
|
|
void SymbolExporter::drawSymbolText(const Symbol &symbol,
|
|
QGraphicsScene* scene,
|
|
const QColor& color,
|
|
bool antialias,
|
|
QFont* font_p)
|
|
{
|
|
// first check if we really need to draw text
|
|
bool bEmpty = true;
|
|
for (int i=0; bEmpty && i<(int)symbol.getTextType(); ++i) {
|
|
bEmpty = symbol.getText(i+1).isEmpty();
|
|
}
|
|
if(bEmpty)
|
|
return;
|
|
|
|
// Find a fixed Font, if possible
|
|
QFont font = SymbolExporter::getMatchFont(font_p, antialias);
|
|
|
|
// Font ist ausgewaehlt, weiter gehts:
|
|
QFontMetricsF metrics(font);
|
|
|
|
// TextBox Width
|
|
double len = (double)symbol.maxStringLength();
|
|
double textBoxW = len* metrics.maxWidth();
|
|
|
|
// TextBox Height
|
|
Symbol::t_text textType = symbol.getTextType();
|
|
double textBoxLineH = metrics.lineSpacing();
|
|
double textBoxH = (double)(textBoxLineH*textType + (int)textType-1);
|
|
|
|
// Scale TextBox
|
|
double maxWidth;
|
|
switch (textType) {
|
|
case Symbol::TEXT1:
|
|
maxWidth = 1.7;
|
|
break;
|
|
case Symbol::TEXT2:
|
|
maxWidth = 1.5;
|
|
break;
|
|
case Symbol::TEXT3:
|
|
default:
|
|
maxWidth = 1.3;
|
|
break;
|
|
}
|
|
double scale = maxWidth/textBoxW;
|
|
|
|
// Add Text
|
|
QRectF textBox(0.0, 0.0, textBoxW, textBoxH);
|
|
textBox.moveCenter(QPointF(0.0, 0.0));
|
|
|
|
for (int i=0; i<(int)textType; ++i) {
|
|
QString txt = symbol.getText(i+1);
|
|
Symbol::t_alignment align = symbol.getTextAlign(i+1);
|
|
|
|
QGraphicsTextItem *textItem = scene->addText(txt, font);
|
|
textItem->setDefaultTextColor(color);
|
|
QRectF metricsRect = metrics.boundingRect(txt);
|
|
metricsRect.moveCenter(QPointF(0.0, 0.0));
|
|
QPointF center = textItem->boundingRect().center();
|
|
textItem->setZValue(0.9);
|
|
textItem->setTransform(QTransform::fromScale(scale, -scale), true);
|
|
|
|
// Place horizontal according to alignment
|
|
double moveX = -center.x();
|
|
switch (align) {
|
|
case Symbol::LEFT:
|
|
moveX = moveX-(metricsRect.left()-textBox.left());
|
|
break;
|
|
case Symbol::RIGHT:
|
|
moveX = moveX+(textBox.right()-metricsRect.right());
|
|
break;
|
|
case Symbol::CENTER:
|
|
default:
|
|
// Do nothing, it's x-centered by default
|
|
break;
|
|
}
|
|
moveX = moveX*scale;
|
|
|
|
// Place vertical according to text-type
|
|
double moveY = center.y();
|
|
switch (textType) {
|
|
case Symbol::TEXT3:
|
|
moveY = moveY - ((i-1)*metricsRect.height());
|
|
break;
|
|
case Symbol::TEXT2:
|
|
moveY = moveY - ((i==0?-1:1)*(metricsRect.height()/2.0));
|
|
break;
|
|
case Symbol::TEXT1:
|
|
default:
|
|
// Do nothing, it's y-centered by default
|
|
break;
|
|
}
|
|
moveY = moveY*scale;
|
|
|
|
textItem->moveBy(moveX, moveY);
|
|
}
|
|
} // void SymbolExporter::drawSymbolText(const Symbol &symbol, ...
|
|
#endif
|
|
|
|
|
|
QFont SymbolExporter::getMatchFont(QFont* font_p, bool antialias)
|
|
{
|
|
QFont retFont;
|
|
if(font_p) {
|
|
retFont = fontMatch(*font_p);
|
|
} else {
|
|
if(!defaultFont) {
|
|
defaultFont = new QFont(QStringLiteral("Monospace"), 10);
|
|
defaultFont->setStyleStrategy(defaultStyleStrategy);
|
|
QFont matchFont = fontMatch(*defaultFont);
|
|
delete defaultFont;
|
|
defaultFont = new QFont(matchFont);
|
|
}
|
|
retFont = *defaultFont;
|
|
}
|
|
QFont::StyleStrategy styleStrategy = QFont::PreferAntialias;
|
|
if(!antialias) {
|
|
styleStrategy = QFont::NoAntialias;
|
|
}
|
|
if(styleStrategy != retFont.styleStrategy()) {
|
|
retFont.setStyleStrategy(styleStrategy);
|
|
retFont = fontMatch(retFont);
|
|
}
|
|
retFont.setBold(true);
|
|
return retFont;
|
|
}
|
|
|
|
QFont SymbolExporter::fontMatch(const QFont &font)
|
|
{
|
|
QFont retFont = font;
|
|
if(!font.exactMatch()) {
|
|
QFontDatabase fdb;
|
|
QStringList fontFamilies = fdb.families(QFontDatabase::Latin);
|
|
for (int i = 0; i < fontFamilies.size(); ++i) {
|
|
QFont tmpFont(fontFamilies.at(i), 10);
|
|
if ( tmpFont.fixedPitch() ) {
|
|
retFont = tmpFont;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return retFont;
|
|
}
|
|
|
|
QGraphicsItem* SymbolExporter::redraw(QGraphicsItem *g, bool drawBoundRect)
|
|
{
|
|
Primitive *prim = g->data(primitiveKey).value<Primitive*>();
|
|
|
|
if(prim->type() == Primitive::TEXT) {
|
|
|
|
// Primitive::TEXT:
|
|
|
|
CustomGraphicsItemGroup* ggroup = dynamic_cast<CustomGraphicsItemGroup*>(g);
|
|
|
|
if(ggroup) {
|
|
QPolygonF points = prim->getPoints();
|
|
if(points.size()!=2) {
|
|
return nullptr;
|
|
}
|
|
|
|
ggroup->setTransform(QTransform());
|
|
ggroup->setPos(0, 0);
|
|
|
|
const QList<QGraphicsItem*> children = ggroup->childItems();
|
|
for(int i = children.size() - 1; i >=0 ; i--) {
|
|
QGraphicsItem *child = children.at(i);
|
|
child->setTransform(QTransform());
|
|
child->setPos(0, 0);
|
|
if(child->data(BOUNDING_RECT).toBool()) {
|
|
ggroup->removeFromGroup(child);
|
|
delete child;
|
|
}
|
|
}
|
|
QRectF wantedBox(points.at(0), points.at(1));
|
|
// prim->text kann auch mehrzeilig sein:
|
|
int metricFlags = 0;
|
|
QFontMetrics metrics(SymbolExporter::getMatchFont(nullptr, true));
|
|
// einzeilig war mal: QRectF boundingBox =
|
|
// QRectF(0, 0, metrics.width(prim->text()), metrics.height());
|
|
QSize textSize = metrics.size(metricFlags, prim->text());
|
|
QRectF boundingBox = QRectF(0, 0, textSize.width(), textSize.height());
|
|
int baselinePixel = 0;
|
|
if(prim->text().contains(QStringLiteral("\n"))) {
|
|
baselinePixel = 2;
|
|
}
|
|
boundingBox.setHeight(boundingBox.height() + baselinePixel);
|
|
qreal dx, dy, dtaken;
|
|
dx = wantedBox.width() / boundingBox.width();
|
|
dy = wantedBox.height() / boundingBox.height();
|
|
dtaken = qMin<qreal>(dx, dy);
|
|
|
|
ggroup->moveBy(-boundingBox.width()*dtaken/2, boundingBox.height()*dtaken/2);
|
|
ggroup->setTransform(QTransform::fromScale(dtaken, -dtaken), true);
|
|
ggroup->moveBy(wantedBox.center().x(), wantedBox.center().y());
|
|
|
|
if(drawBoundRect) {
|
|
QGraphicsRectItem *selectRect = new QGraphicsRectItem();
|
|
QPen rectpen(Qt::DotLine);
|
|
rectpen.setColor(Qt::red);
|
|
rectpen.setWidthF(0.01);
|
|
selectRect->setData(BOUNDING_RECT, true);
|
|
selectRect->setPen(rectpen);
|
|
selectRect->setBrush(Qt::NoBrush);
|
|
selectRect->setRect(wantedBox);
|
|
ggroup->addToGroup(selectRect);
|
|
}
|
|
|
|
// rotate:
|
|
double angle = prim->getRotation();
|
|
ggroup->setTransform(QTransform().rotate(angle), true); // rotation point is not the center of ggroup ! :-(
|
|
//
|
|
ggroup->update();
|
|
|
|
return ggroup;
|
|
}
|
|
} else if(prim->type() == Primitive::ICON) {
|
|
|
|
// Primitive::ICON:
|
|
|
|
CustomGraphicsItemGroup* ggroup = dynamic_cast<CustomGraphicsItemGroup*>(g);
|
|
|
|
if(ggroup) {
|
|
QPolygonF points = prim->getPoints();
|
|
if(points.size()!=2) {
|
|
return nullptr;
|
|
}
|
|
const QList<QGraphicsItem*> children = ggroup->childItems();
|
|
for(int i = children.size() - 1; i >=0 ; i--) {
|
|
QGraphicsItem *child = children.at(i);
|
|
if(child->data(BOUNDING_RECT).toBool()) {
|
|
ggroup->removeFromGroup(child);
|
|
delete child;
|
|
}
|
|
}
|
|
ggroup->setTransform(QTransform());
|
|
ggroup->setPos(0, 0);
|
|
|
|
QRectF wantedBox(points.at(0), points.at(1));
|
|
|
|
#ifdef NEVER
|
|
bool scalingOfLinewidth = false; // false == linewidth will not be changed
|
|
if (scalingOfLinewidth)
|
|
{
|
|
// war mal so: ( nur proportional !!!) :
|
|
QRectF boundingBox = ggroup->boundingRect();
|
|
qreal dtaken = qMin<qreal>(wantedBox.width() / boundingBox.width(),
|
|
wantedBox.height() / boundingBox.height());
|
|
|
|
ggroup->setTransform(QTransform::fromScale(dtaken, dtaken), true);
|
|
ggroup->moveBy(-boundingBox.center().x()*dtaken, -boundingBox.center().y()*dtaken);
|
|
ggroup->moveBy(wantedBox.center().x(), wantedBox.center().y());
|
|
}
|
|
else
|
|
#endif
|
|
{ // let the linewith's be constant
|
|
bool proport = !(prim->scalemode() == Primitive::Scalemode_Unproport);
|
|
scaleGeometry(ggroup, wantedBox, proport);
|
|
}
|
|
if(drawBoundRect) {
|
|
QGraphicsRectItem *selectRect = new QGraphicsRectItem();
|
|
QPen rectpen(Qt::DotLine);
|
|
rectpen.setColor(Qt::red);
|
|
rectpen.setWidthF(0.01);
|
|
selectRect->setData(BOUNDING_RECT, true);
|
|
selectRect->setPen(rectpen);
|
|
selectRect->setBrush(Qt::NoBrush);
|
|
selectRect->setRect(wantedBox);
|
|
ggroup->addToGroup(selectRect);
|
|
}
|
|
// rotate:
|
|
double angle = prim->getRotation();
|
|
QPointF centerF = ggroup->boundingRect().center();
|
|
ggroup->setTransform(QTransform());
|
|
ggroup->setTransform(QTransform().translate(centerF.x(), centerF.y())
|
|
.rotate(angle).translate(-centerF.x(), -centerF.y()));
|
|
//
|
|
ggroup->update();
|
|
|
|
return ggroup;
|
|
}
|
|
}
|
|
else {
|
|
|
|
// other Primitives:
|
|
|
|
QGraphicsPathItem* pathItem = dynamic_cast<QGraphicsPathItem*>(g);
|
|
if(pathItem) {
|
|
QPainterPath path = SymbolExporter::createPath(prim, false);
|
|
pathItem->setPath(path);
|
|
// rotate:
|
|
double angle = prim->getRotation();
|
|
double cx = 0.0;
|
|
double cy = 0.0;
|
|
prim->getCenter(cx, cy);
|
|
pathItem->setTransform(QTransform());
|
|
pathItem->setTransform(QTransform().translate(cx, cy).rotate(angle).translate(-cx, -cy));
|
|
//
|
|
pathItem->update();
|
|
}
|
|
}
|
|
|
|
return g;
|
|
}
|
|
|
|
void SymbolExporter::scaleGeometry(QGraphicsItemGroup* ggroup, const QRectF &wantedBox,
|
|
bool proport)
|
|
{
|
|
// test NGL::INGLLogger &mLogger =
|
|
// test NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger( "SymbolEditor" );
|
|
|
|
// try and try a scale, at least it seams as if its ok
|
|
// and do not vis Qt-errors !
|
|
qreal last_scalex = -1;
|
|
qreal scalex = 0;
|
|
qreal scaley = scalex;
|
|
QRectF boundingBox;
|
|
int countWhile = 0;
|
|
|
|
while((qAbs(last_scalex - scalex) > 0.001) &&
|
|
(countWhile < 10) && // max tries
|
|
((scalex < 0.999) || (scalex > 1.001))) { // dtaken should go to 1.000
|
|
// set new scalex, scaley:
|
|
boundingBox = ggroup->boundingRect();
|
|
qreal dx, dy;
|
|
dx = wantedBox.width() / boundingBox.width();
|
|
dy = wantedBox.height() / boundingBox.height();
|
|
last_scalex = scalex;
|
|
if(proport) {
|
|
scalex = qMin<qreal>(dx, dy);
|
|
scaley = scalex;
|
|
} else {
|
|
scalex = dx;
|
|
scaley = dy;
|
|
}
|
|
// test ERROR_LOG(mLogger) << "scaleGeometry: countWhile = " << countWhile
|
|
// test << "scalex = " << scalex ;
|
|
SymbolExporter::tryScaleGeometry(ggroup, scalex, scaley);
|
|
++countWhile;
|
|
}
|
|
ggroup->moveBy(-boundingBox.center().x()*scalex, -boundingBox.center().y()*scaley);
|
|
ggroup->moveBy(wantedBox.center().x(), wantedBox.center().y());
|
|
}
|
|
|
|
void SymbolExporter::tryScaleGeometry(QGraphicsItemGroup* ggroup,
|
|
qreal scalex, qreal scaley)
|
|
{
|
|
// items from group :
|
|
QList<QGraphicsItem*> gi_l;
|
|
while(ggroup->childItems().size() > 0) {
|
|
QGraphicsItem* gi_p = ggroup->childItems().at(0);
|
|
gi_l << gi_p;
|
|
ggroup->removeFromGroup(gi_p);
|
|
}
|
|
//
|
|
QTransform matrix;
|
|
matrix.scale(scalex, scaley);
|
|
|
|
for(QGraphicsItem* gi_p : qAsConst(gi_l)) {
|
|
QGraphicsPathItem* pathItem = dynamic_cast<QGraphicsPathItem*>(gi_p);
|
|
if(pathItem) {
|
|
QPainterPath painterPath = matrix.map(pathItem->path());
|
|
pathItem->setPath(painterPath);
|
|
}
|
|
}
|
|
// items to group :
|
|
while(gi_l.size() > 0) {
|
|
ggroup->addToGroup(gi_l.at(0));
|
|
gi_l.takeAt(0);
|
|
}
|
|
}
|
|
|
|
QGraphicsItem* SymbolExporter::drawPrimitive(const Primitive& primitive,
|
|
const QColor& color, const QColor& fillColor,
|
|
double z, bool isAttrib, bool drawBoundRect)
|
|
{
|
|
Q_UNUSED(drawBoundRect);
|
|
|
|
Primitive *item = const_cast<Primitive*>(&primitive);
|
|
|
|
QColor localColor = color;
|
|
if (item->getColor().isValid())
|
|
{
|
|
localColor = item->getColor();
|
|
localColor.setAlpha(color.alpha()); // Evtl. nur wenn mapItemPrimitives_p != 0
|
|
}
|
|
|
|
QBrush brush;
|
|
QPen pen;
|
|
|
|
double pWidth = item->getLineWidth();
|
|
if ( isAttrib ) {
|
|
if(item->fill()) {
|
|
// filled :
|
|
if(pWidth < 0.0) {
|
|
pen.setColor(QColor(0,0,0,0));
|
|
pWidth = 0.0;
|
|
} else if(pWidth == 0.0) {
|
|
//pen.setColor(localColor);
|
|
QColor blackAlpha = Qt::black;
|
|
blackAlpha.setAlpha(localColor.alpha());
|
|
pen.setColor(blackAlpha);
|
|
} else {
|
|
pen.setColor(localColor);
|
|
}
|
|
} else {
|
|
// outlined :
|
|
pen.setColor(localColor);
|
|
if(pWidth < 0.0) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
brush.setColor(fillColor);
|
|
} else {
|
|
// !isAttrib :
|
|
pen.setColor(localColor);
|
|
brush.setColor(fillColor);
|
|
}
|
|
pen.setWidthF(pWidth);
|
|
|
|
brush.setStyle(item->fill()?(Qt::SolidPattern):(Qt::NoBrush));
|
|
|
|
// pen style:
|
|
switch (item->getLineStyle())
|
|
{
|
|
case Primitive::DASHED_DOTTED:
|
|
pen.setStyle(Qt::DashDotLine);
|
|
break;
|
|
case Primitive::DOTTED:
|
|
pen.setDashPattern(QVector<qreal>() << 1 << 1); // the same length for dot and space
|
|
// war mal so: pen.setStyle(Qt::DotLine);
|
|
break;
|
|
case Primitive::DASHED:
|
|
pen.setStyle(Qt::DashLine);
|
|
break;
|
|
case Primitive::SOLID:
|
|
default:
|
|
pen.setStyle(Qt::SolidLine);
|
|
break;
|
|
} // switch
|
|
|
|
pen.setCapStyle(Qt::FlatCap);
|
|
pen.setJoinStyle(Qt::BevelJoin);
|
|
|
|
QPainterPath qpath = SymbolExporter::createPath(item, isAttrib);
|
|
|
|
if ( !qpath.isEmpty() )
|
|
{
|
|
QGraphicsPathItem *pathItem = new QGraphicsPathItem(qpath);
|
|
QVariant data = QVariant::fromValue(item);
|
|
pathItem->setData(primitiveKey, data); // primitiveKey=42 from symbolexporter.h
|
|
|
|
pathItem->setPen(pen);
|
|
pathItem->setBrush(brush);
|
|
// rotate:
|
|
double angle = item->getRotation();
|
|
double cx, cy;
|
|
item->getCenter(cx, cy);
|
|
if(angle != 0.0) {
|
|
pathItem->setTransform(QTransform());
|
|
pathItem->setTransform(QTransform().translate(cx, cy).rotate(angle).translate(-cx, -cy));
|
|
}
|
|
//
|
|
pathItem->setZValue(z);
|
|
|
|
return pathItem;
|
|
} // if ( !qpath.isEmpty() )
|
|
|
|
return nullptr;
|
|
} // SymbolExporter::drawPrimitive
|
|
|
|
QGraphicsItem* SymbolExporter::drawICON(const Primitive& primitive,
|
|
const SymbolTypes::t_symbolTableCont& symTableCont,
|
|
QGraphicsScene* scene,
|
|
const QColor& color, const QColor& fillColor,
|
|
double z, bool isAttrib, bool drawBoundRect)
|
|
{
|
|
if ( ! scene)
|
|
return nullptr;
|
|
|
|
CustomGraphicsItemGroup * ggroup = nullptr;
|
|
Primitive *primitive_p = const_cast<Primitive*>(&primitive);
|
|
|
|
if(primitive_p->type() == Primitive::ICON)
|
|
{
|
|
SymbolTypes::t_sectoricon primIconId = (SymbolTypes::t_sectoricon)primitive_p->icon();
|
|
SymbolTypes::t_icon_type iconType = primitive_p->iconType();
|
|
SymbolTable* symTableSectorIcons_p = nullptr;
|
|
if ( (iconType>= 0) &&
|
|
(iconType < SymbolTypes::ICON_TYPE_END) &&
|
|
(symTableCont.size() == SymbolTypes::ICON_TYPE_END) ) {
|
|
symTableSectorIcons_p = symTableCont[iconType];
|
|
}
|
|
|
|
// endgueltige id des (Sub-)Symbols ermitteln.
|
|
// Dazu je nach iconType den passenden Offset einbezuiehen:
|
|
int tmpID = -1;
|
|
|
|
switch (iconType)
|
|
{
|
|
case SymbolTypes::ICON_TYPE_SECTOR_ICON:
|
|
tmpID = SymbolTable::getSectorIconSymbolID(primIconId);
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_INTRINSIC_MOBILITY:
|
|
tmpID = SymbolTable::getIntrinsicMobilitySymbolID( (SymbolTypes::t_intrinsicmob)primIconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_VEHICLE:
|
|
tmpID = SymbolTable::getVehicleSymbolID( (SymbolTypes::t_vehicle)primIconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_ARMING:
|
|
tmpID = SymbolTable::getArmingSymbolID( (SymbolTypes::t_arming)primIconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_MISC:
|
|
tmpID = SymbolTable::getMiscSymbolID( (SymbolTypes::t_misc)primIconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_UNDEFINED:
|
|
case SymbolTypes::ICON_TYPE_END:
|
|
{
|
|
// emtpy - avoiding compiler warning
|
|
|
|
}
|
|
} // switch
|
|
|
|
// Und nun mit der endgueltige id des (Sub-)Symbols den passdenden SymboTable
|
|
// um das (Sub-)Symbol bitten:
|
|
|
|
if ( symTableSectorIcons_p && symTableSectorIcons_p->contains(tmpID) )
|
|
{
|
|
Symbol *secIconSymbol = new Symbol(*(symTableSectorIcons_p->value(tmpID)));
|
|
|
|
ggroup = new CustomGraphicsItemGroup();
|
|
scene->addItem(ggroup);
|
|
|
|
QLinkedList<Primitive*>plist = secIconSymbol->getPrimitives();
|
|
|
|
// linewidth:
|
|
double resultLinewidth = primitive_p->getLineWidth();
|
|
if(resultLinewidth < 0) {
|
|
QLinkedListIterator<Primitive*> piterlw(plist);
|
|
while(piterlw.hasNext()) {
|
|
Primitive *subPrim = piterlw.next();
|
|
if(subPrim->getLineWidth() > resultLinewidth) {
|
|
resultLinewidth = subPrim->getLineWidth();
|
|
}
|
|
}
|
|
if(resultLinewidth < 0) {
|
|
resultLinewidth = 0;
|
|
}
|
|
if(primitive_p->position() != SymbolTypes::SECTORMAIN) {
|
|
resultLinewidth = resultLinewidth * REDUCE_LINEWIDTH_F;
|
|
}
|
|
if(primitive_p->rectpos() == SymbolTypes::SECTOR_RECTPOS_LARGE) {
|
|
resultLinewidth = resultLinewidth * 2;
|
|
}
|
|
primitive_p->setLineWidth(resultLinewidth);
|
|
}
|
|
// :linewidth
|
|
|
|
QLinkedListIterator<Primitive*> piter(plist);
|
|
|
|
while ( piter.hasNext() )
|
|
{
|
|
Primitive *prim = piter.next();
|
|
if(prim->getLineWidth() > 0) {
|
|
prim->setLineWidth(primitive_p->getLineWidth());
|
|
}
|
|
QGraphicsItem *gitem = SymbolExporter::drawPrimitive(*prim, color, fillColor,
|
|
z, isAttrib);
|
|
if(gitem) {
|
|
gitem->setData(primitiveKey, QVariant());
|
|
ggroup->addToGroup(gitem);
|
|
}
|
|
} // while
|
|
|
|
ggroup->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
|
ggroup->setSelected(false);
|
|
|
|
QVariant temp;
|
|
temp.setValue<Primitive*>(primitive_p);
|
|
ggroup->setData(primitiveKey, temp);
|
|
|
|
redraw(ggroup, drawBoundRect);
|
|
|
|
ggroup->setSelected(false);
|
|
ggroup->setZValue(z);
|
|
|
|
delete secIconSymbol;
|
|
|
|
}// if ( symTableSectorIcons_p.contains(tmpID) )
|
|
|
|
|
|
} // if(primitive_p->type() == Primitive::ICON)
|
|
return ggroup;
|
|
|
|
} // QGraphicsItem* SymbolExporter::drawICON
|
|
|
|
QGraphicsItem* SymbolExporter::drawText(const Primitive &primitive,
|
|
const SymbolTypes::t_symbolTableCont& symTableCont,
|
|
QGraphicsScene* scene,
|
|
const QColor& color, const QColor& fillColor,
|
|
double z, bool isAttrib, bool drawBoundRect)
|
|
{
|
|
Q_UNUSED(symTableCont);
|
|
Q_UNUSED(fillColor);
|
|
Q_UNUSED(isAttrib);
|
|
Q_UNUSED(drawBoundRect);
|
|
|
|
if ( ! scene)
|
|
return nullptr;
|
|
|
|
QColor finalColor = color;
|
|
#if defined (SYMBOL_TEXT_IN_BLACK) && (SYMBOL_TEXT_IN_BLACK == 1)
|
|
// Sind wir bei der 'eigenen' Partei? (Hack über die Farben)
|
|
if ( isColorOfOwnForce(color) )
|
|
{
|
|
finalColor = Qt::black;
|
|
}
|
|
#endif // #if defined (SYMBOL_TEXT_IN_BLACK)...
|
|
|
|
CustomGraphicsItemGroup * ggroup = nullptr;
|
|
Primitive *primitive_p = const_cast<Primitive*>(&primitive);
|
|
|
|
if(primitive_p->type() == Primitive::TEXT) {
|
|
ggroup = new CustomGraphicsItemGroup();
|
|
scene->addItem(ggroup);
|
|
|
|
QGraphicsSimpleTextItem *gitem = new QGraphicsSimpleTextItem();
|
|
gitem->setBrush(finalColor);
|
|
gitem->setFont(SymbolExporter::getMatchFont(nullptr, true));
|
|
gitem->setText(primitive_p->text());
|
|
ggroup->addToGroup(gitem);
|
|
|
|
ggroup->setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable);
|
|
ggroup->setSelected(false);
|
|
|
|
QVariant temp;
|
|
temp.setValue<Primitive*>(primitive_p);
|
|
ggroup->setData(primitiveKey, temp); // primitiveKey=42 from symbolexporter.h
|
|
|
|
redraw(ggroup, drawBoundRect);
|
|
|
|
ggroup->setSelected(false);
|
|
ggroup->setZValue(z);
|
|
}
|
|
return ggroup;
|
|
} // QGraphicsItem* SymbolExporter::drawText
|
|
|
|
|
|
QPainterPath SymbolExporter::createPath(const Primitive* primitive_p, bool isAttrib)
|
|
{
|
|
QPainterPath qpath;
|
|
double w, h, xmin, ymin;
|
|
QPolygonF points = primitive_p->getPoints();
|
|
switch (primitive_p->type())
|
|
{
|
|
case Primitive::ELLIPSE :
|
|
{
|
|
w = fabs(points.at(0).x()-points.at(1).x());
|
|
h = fabs(points.at(0).y()-points.at(1).y());
|
|
xmin = std::min(points.at(0).x(), points.at(1).x());
|
|
ymin = std::min(points.at(0).y(), points.at(1).y());
|
|
if ( primitive_p->closed() || (primitive_p->getExtent() >= 360.0) )
|
|
{
|
|
qpath.addEllipse(xmin, ymin, w, h);
|
|
}
|
|
else
|
|
{
|
|
if ( primitive_p->fill() && !isAttrib )
|
|
{
|
|
qpath.moveTo(xmin+(w/2.0), ymin+(h/2.0));
|
|
}
|
|
else
|
|
{
|
|
qpath.arcMoveTo(xmin, ymin, w, h, -(primitive_p->getStartAngle()) );
|
|
}
|
|
qpath.arcTo(xmin, ymin, w, h,
|
|
-(primitive_p->getStartAngle()), -(primitive_p->getExtent()) );
|
|
}
|
|
} break;
|
|
|
|
case Primitive::LINE :
|
|
{
|
|
qpath.moveTo(points.at(0));
|
|
qpath.lineTo(points.at(1));
|
|
} break;
|
|
|
|
case Primitive::POLYGON :
|
|
{
|
|
qpath.addPolygon(points);
|
|
if ( primitive_p->closed() )
|
|
{
|
|
qpath.closeSubpath();
|
|
}
|
|
} break;
|
|
|
|
case Primitive::RECT :
|
|
{
|
|
// TODO: QRectF rect(points.at(0), points.at(1)) ??
|
|
w = fabs(points.at(0).x()-points.at(1).x());
|
|
h = fabs(points.at(0).y()-points.at(1).y());
|
|
xmin = std::min(points.at(0).x(), points.at(1).x());
|
|
ymin = std::min(points.at(0).y(), points.at(1).y());
|
|
qpath.addRect(xmin, ymin, w, h);
|
|
} break;
|
|
|
|
default : break;
|
|
}
|
|
return qpath;
|
|
} // QPainterPath SymbolExporter::createPath(Primitive* primitive, bool isAttrib)
|
|
|
|
|
|
Primitive *SymbolExporter::newPrimitiveICON(SymbolTypes::t_icon_type iconType,
|
|
SymbolTypes::t_sector_position pos,
|
|
SymbolTypes::t_sector_rectpos rectpos,
|
|
int id)
|
|
{
|
|
Primitive *p = new Primitive(Primitive::ICON);
|
|
p->setIcon(id);
|
|
p->setIconType(iconType);
|
|
QRectF rect = SymbolTypes::getDefaultRect(pos, rectpos);
|
|
QPolygonF poly;
|
|
poly.append(rect.topLeft());
|
|
poly.append(rect.bottomRight());
|
|
p->setPoints(poly);
|
|
p->setPosition(pos);
|
|
p->setRectpos(rectpos);
|
|
p->setLineWidth(-1); // will be set in drawICON
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
Symbol *SymbolExporter::newSecIconSymbol(const SymbolTypes::t_symbolTableCont& symTableCont,
|
|
SymbolTypes::t_icon_type iconType, int iconId)
|
|
{
|
|
if(iconId == SymbolTypes::SECICON_UNDEFINED) { // undefined
|
|
return nullptr;
|
|
}
|
|
|
|
SymbolTable* symTableSectorIcons_p = nullptr;
|
|
if((iconType>= 0) &&
|
|
(iconType < SymbolTypes::ICON_TYPE_END) &&
|
|
(symTableCont.size() == SymbolTypes::ICON_TYPE_END)) {
|
|
symTableSectorIcons_p = symTableCont[iconType];
|
|
}
|
|
|
|
int tmpID = -1;
|
|
switch (iconType) {
|
|
case SymbolTypes::ICON_TYPE_SECTOR_ICON:
|
|
tmpID = SymbolTable::getSectorIconSymbolID((SymbolTypes::t_sectoricon)iconId);
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_INTRINSIC_MOBILITY:
|
|
tmpID = SymbolTable::getIntrinsicMobilitySymbolID( (SymbolTypes::t_intrinsicmob)iconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_VEHICLE:
|
|
tmpID = SymbolTable::getVehicleSymbolID( (SymbolTypes::t_vehicle)iconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_ARMING:
|
|
tmpID = SymbolTable::getArmingSymbolID( (SymbolTypes::t_arming)iconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_MISC:
|
|
tmpID = SymbolTable::getMiscSymbolID( (SymbolTypes::t_misc)iconId );
|
|
break;
|
|
case SymbolTypes::ICON_TYPE_UNDEFINED:
|
|
case SymbolTypes::ICON_TYPE_END:
|
|
break;
|
|
} // switch
|
|
|
|
if(!symTableSectorIcons_p || !symTableSectorIcons_p->contains(tmpID)) {
|
|
return nullptr;
|
|
}
|
|
Symbol *secIconSymbol = new Symbol(*(symTableSectorIcons_p->value(tmpID)));
|
|
return secIconSymbol;
|
|
}
|
|
|
|
}; // namespace SymbologyXML
|