345 lines
11 KiB
C++
Executable File
345 lines
11 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* GraphicalObjectText
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*/
|
|
|
|
// Own
|
|
#include "graphical_object_text.h"
|
|
#include <Map/situation_map_utils.h> // operator<<
|
|
|
|
|
|
// ESRI
|
|
#include <GraphicsOverlay.h>
|
|
#include <TextSymbol.h>
|
|
#include <PictureMarkerSymbol.h>
|
|
#include <SymbolTypes.h>
|
|
#include <Graphic.h>
|
|
#include <Point.h>
|
|
#include <SpatialReference.h>
|
|
|
|
// Qt
|
|
#include <QString>
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
namespace SituationMap
|
|
{
|
|
|
|
GraphicalObjectText::GraphicalObjectText(const Esri::ArcGISRuntime::GeoView *geoView
|
|
, Esri::ArcGISRuntime::GraphicsOverlay *graphicsLayer
|
|
, const QString &debugInfo
|
|
, const UniqueMapId &uniqueMapId)
|
|
: BaseClass(geoView, graphicsLayer, debugInfo, uniqueMapId)
|
|
, m_textSymbol(nullptr)
|
|
, m_logger(getLogger("GraphicalObjectText"))
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'";
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'";
|
|
}
|
|
|
|
GraphicalObjectText::~GraphicalObjectText()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'";
|
|
|
|
delete m_textSymbol;
|
|
m_textSymbol = nullptr;
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'";
|
|
}
|
|
|
|
QString GraphicalObjectText::toString() const
|
|
{
|
|
QString str;
|
|
// str.append( BaseClass::toString() );
|
|
|
|
if (!m_debugInfo.isEmpty())
|
|
str.append(QStringLiteral("debugInfo=%1").arg(m_debugInfo));
|
|
|
|
if (m_graphicsLayer)
|
|
str.append(QStringLiteral(" layer='%1'").arg(m_graphicsLayer->objectName()));
|
|
|
|
if (m_graphic)
|
|
str.append(QStringLiteral(" zIndex='%1'").arg(m_graphic->zIndex()));
|
|
|
|
std::ostringstream stream;
|
|
stream << this->origin();
|
|
str.append(QLatin1String(stream.str().c_str()));
|
|
|
|
if (!m_text.value().isEmpty())
|
|
str.append(QStringLiteral("text=%1").arg(m_text.value()));
|
|
|
|
return str;
|
|
}
|
|
|
|
QString GraphicalObjectText::text() const
|
|
{
|
|
return m_text.value();
|
|
}
|
|
|
|
void GraphicalObjectText::setText(const QString &text)
|
|
{
|
|
m_text = text;
|
|
}
|
|
|
|
TextStyle GraphicalObjectText::textStyle() const
|
|
{
|
|
return m_textStyle.value();
|
|
}
|
|
TextStyle &GraphicalObjectText::rTextStyle()
|
|
{
|
|
return m_textStyle.refValue();
|
|
}
|
|
void GraphicalObjectText::setTextStyle(const TextStyle &textStyle)
|
|
{
|
|
m_textStyle = textStyle;
|
|
}
|
|
|
|
float GraphicalObjectText::xOffset() const
|
|
{
|
|
return m_offset.value().x();
|
|
}
|
|
void GraphicalObjectText::setXOffset(float xOffset)
|
|
{
|
|
QPointF temp = m_offset.value();
|
|
temp.rx() = xOffset;
|
|
m_offset = temp;
|
|
}
|
|
float GraphicalObjectText::yOffset() const
|
|
{
|
|
return m_offset.value().y();
|
|
}
|
|
void GraphicalObjectText::setYOffset(float yOffset)
|
|
{
|
|
QPointF temp = m_offset.value();
|
|
temp.ry() = yOffset;
|
|
m_offset = temp;
|
|
}
|
|
|
|
|
|
bool GraphicalObjectText::create()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'"
|
|
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
|
<< " visibility=" << m_visibility;
|
|
bool success = true;
|
|
|
|
// some checks:
|
|
if (!m_graphicsLayer)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
|
<< " no graphicsLayer";
|
|
return false;
|
|
}
|
|
|
|
BaseClass::create();
|
|
|
|
if (!m_textSymbol)
|
|
m_textSymbol = new Esri::ArcGISRuntime::TextSymbol();
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'"
|
|
<< " success=" << success
|
|
<< " drawOrder = " << m_graphic->zIndex();
|
|
return success;
|
|
}
|
|
|
|
bool GraphicalObjectText::updateViewImpl()
|
|
{
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " START, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'"
|
|
<< " origin =" << this->origin() // .x() << " , " << this->origin().y()
|
|
<< " visibility=" << m_visibility
|
|
<< " m_textStyle=" << m_textStyle
|
|
<< " offset=" << m_offset;
|
|
|
|
// some checks:
|
|
if (!this->isSinglePoint())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
|
<< " incorrect number of positions"
|
|
<< " (" << this->positions().count() << ")";
|
|
return false;
|
|
}
|
|
|
|
bool success = true;
|
|
if (m_visibility.value())
|
|
{
|
|
success = create(); // create only if visible
|
|
if (!success)
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
|
<< " create failed";
|
|
return false;
|
|
}
|
|
|
|
if (! BaseClass::updateViewImpl())
|
|
{
|
|
ERROR_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
|
<< " updateViewImpl failed";
|
|
}
|
|
|
|
// FATAL_LOG(m_logger) << LOGFUNCTION << " debugInfo='" << m_debugInfo << "'"
|
|
// << " text='" << m_text << "'"
|
|
// << " changed1=" << m_text.changed()
|
|
// << " changed2="<< m_textStyle.changed();
|
|
|
|
bool assignTextSymbol = false;
|
|
|
|
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
|
if (m_text.changed() || m_visibility.changed())
|
|
{
|
|
m_textSymbol->setText(m_text.value());
|
|
assignTextSymbol = true;
|
|
}
|
|
|
|
// TextStyle to TextSymbol@ESRI :
|
|
if (m_textStyle.changed()
|
|
|| m_scale.changed()
|
|
|| m_visibility.changed() // -> szenario: create invisible object and make it visible
|
|
)
|
|
{
|
|
const TextStyle &textStyle = m_textStyle.value();
|
|
m_textSymbol->setColor(textStyle.textColor());
|
|
|
|
// High values can lead to coredump with 'SymbolDrawHelper::create_line_image FAILED, SkBitmap is NULL or empty' -> limit
|
|
m_textSymbol->setSize(std::min(500.0f, textStyle.size() * m_scale.value()));
|
|
m_textSymbol->setAngle(textStyle.angle());
|
|
|
|
m_textSymbol->setFontFamily(textStyle.fontFamily());
|
|
|
|
m_textSymbol->setFontWeight(textStyle.bold() ? Esri::ArcGISRuntime::FontWeight::Bold : Esri::ArcGISRuntime::FontWeight::Normal);
|
|
m_textSymbol->setFontStyle(textStyle.italic() ? Esri::ArcGISRuntime::FontStyle::Italic : Esri::ArcGISRuntime::FontStyle::Normal);
|
|
|
|
Esri::ArcGISRuntime::FontDecoration fd = Esri::ArcGISRuntime::FontDecoration::None;
|
|
if (textStyle.underline())
|
|
fd = Esri::ArcGISRuntime::FontDecoration::Underline;
|
|
if (textStyle.strikeThrough())
|
|
fd = Esri::ArcGISRuntime::FontDecoration::LineThrough;
|
|
m_textSymbol->setFontDecoration(fd);
|
|
|
|
float outlineWidth = 0;
|
|
if (textStyle.textOutlineWidth() > 0)
|
|
outlineWidth = textStyle.textOutlineWidth() * m_scale.value();
|
|
if (m_textSymbol->size() <= 15) // small size -> outline reduces readability :-(
|
|
outlineWidth = 0.0;
|
|
m_textSymbol->setHaloWidth(outlineWidth);
|
|
|
|
if (textStyle.textOutlineColor().isValid())
|
|
m_textSymbol->setHaloColor(textStyle.textOutlineColor());
|
|
|
|
// qWarning() << " haloWidth = " << m_textSymbol->haloWidth();
|
|
|
|
// m_textSymbol->setHaloColor(Qt::white);
|
|
// m_textSymbol->setHaloWidth(outlineWidth);
|
|
|
|
// qWarning() << " fontSize " << textStyle.size() * m_scale.value()
|
|
// <<" (textStyle.size() " << textStyle.size()
|
|
// << " m_scale.value() " << m_scale.value() << ")";
|
|
|
|
// qWarning() << " outlineWidth " << outlineWidth
|
|
// <<" (textStyle.textOutlineWidth() " << textStyle.textOutlineWidth()
|
|
// << " m_scale.value() " << m_scale.value() << ")";
|
|
|
|
// if (textStyle.backgroundColor().isValid())
|
|
m_textSymbol->setBackgroundColor(textStyle.backgroundColor());
|
|
|
|
// m_textSymbol->setAntiAliased(textStyle.antiAliased());
|
|
|
|
m_textSymbol->setHorizontalAlignment(convert(textStyle.horizontalAlignment()));
|
|
m_textSymbol->setVerticalAlignment(convert(textStyle.verticalAlignment()));
|
|
|
|
assignTextSymbol = true;
|
|
// : TextStyle to TextSymbol@ESRI
|
|
}
|
|
|
|
// || m_visibility.changed()) -> szenario: create invisible object and make it visible
|
|
if (m_offset.changed() || m_visibility.changed())
|
|
{
|
|
m_textSymbol->setOffsetX(m_offset.value().x());
|
|
m_textSymbol->setOffsetY(m_offset.value().y());
|
|
assignTextSymbol = true;
|
|
}
|
|
|
|
if (assignTextSymbol)
|
|
m_graphic->setSymbol(m_textSymbol);
|
|
|
|
|
|
// check ChangedFlags:
|
|
// Object is created and text is invisble due to scale (meterPerPixel)
|
|
// map is zoomed in -> text should arise, but on m_visibility is changed:
|
|
if (m_visibility.changed() || m_positions.changed())
|
|
{
|
|
const Point3D &origin = this->origin();
|
|
m_graphic->setGeometry(Esri::ArcGISRuntime::Point(origin.x(),
|
|
origin.y(),
|
|
origin.z(),
|
|
spatialReference()));
|
|
success = addUpdateGraphic();
|
|
} // m_visibility.changed() || m_positions.changed()
|
|
|
|
}
|
|
else // if visible
|
|
{
|
|
BaseClass::updateViewImpl();
|
|
success = addUpdateGraphic();
|
|
}
|
|
|
|
if (m_logger.isTraceEnabled())
|
|
{
|
|
int drawOrder = -1;
|
|
if (m_graphic)
|
|
drawOrder = m_graphic->zIndex();
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
|
<< " text='" << m_text << "'"
|
|
<< " success=" << success
|
|
<< " drawOrder = " << drawOrder;
|
|
}
|
|
|
|
TRACE_LOG(m_logger) << LOGFUNCTION << " END, debugInfo='" << m_debugInfo << "'"
|
|
// << " fontFamily='" << m_textSymbol->fontFamily() << "'"
|
|
;
|
|
return success;
|
|
}
|
|
|
|
|
|
|
|
Esri::ArcGISRuntime::HorizontalAlignment GraphicalObjectText::convert(const HorizontalAlignment horizontalAlignment)
|
|
{
|
|
Esri::ArcGISRuntime::HorizontalAlignment esriAlignmenmt =
|
|
Esri::ArcGISRuntime::HorizontalAlignment::Left;
|
|
switch (horizontalAlignment)
|
|
{
|
|
case HorizontalAlignment::Left: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Left; break;
|
|
case HorizontalAlignment::Center: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Center; break;
|
|
case HorizontalAlignment::Right: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Right; break;
|
|
case HorizontalAlignment::Justify: esriAlignmenmt = Esri::ArcGISRuntime::HorizontalAlignment::Justify; break;
|
|
} // switch
|
|
|
|
return esriAlignmenmt;
|
|
}
|
|
|
|
Esri::ArcGISRuntime::VerticalAlignment GraphicalObjectText::convert(const VerticalAlignment verticalAlignment)
|
|
{
|
|
Esri::ArcGISRuntime::VerticalAlignment esriAlignmenmt =
|
|
Esri::ArcGISRuntime::VerticalAlignment::Bottom;
|
|
switch (verticalAlignment)
|
|
{
|
|
case VerticalAlignment::Bottom: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Bottom; break;
|
|
case VerticalAlignment::Middle: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Middle; break;
|
|
case VerticalAlignment::Top: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Top; break;
|
|
case VerticalAlignment::BaseLine: esriAlignmenmt = Esri::ArcGISRuntime::VerticalAlignment::Baseline; break;
|
|
} // switch
|
|
return esriAlignmenmt;
|
|
}
|
|
|
|
|
|
|
|
} // namespace SituationMap
|