1 #ifndef OSMSCOUT_MAP_LABELLAYOUTER_H 2 #define OSMSCOUT_MAP_LABELLAYOUTER_H 35 #ifdef DEBUG_LABEL_LAYOUTER 128 template<
class NativeGlyph>
143 template<
class NativeGlyph,
class NativeLabel>
157 template<
typename... Args>
168 std::vector<Glyph<NativeGlyph>>
ToGlyphs()
const;
171 template<
class NativeGlyph,
class NativeLabel>
180 std::shared_ptr<Label<NativeGlyph, NativeLabel>>
185 size_t priority{std::numeric_limits<size_t>::max()};
190 template<
class NativeGlyph>
194 #ifdef DEBUG_LABEL_LAYOUTER 205 explicit Mask(
size_t rowSize) :
d(rowSize)
223 std::vector<uint64_t>
d;
231 template <
class NativeGlyph,
class NativeLabel>
243 template <
class NativeGlyph>
248 assert(!a.
glyphs.empty());
249 assert(!b.
glyphs.empty());
250 return a.
glyphs[0].trPosition.GetX() < b.
glyphs[0].trPosition.GetX();
276 template <
class NativeGlyph,
class NativeLabel,
class TextLayouter>
288 textLayouter(textLayouter)
299 layoutOverlap = overlap;
300 layoutViewport.
width = visibleViewport.
width + (overlap * 2);
301 layoutViewport.
height = visibleViewport.
height + (overlap * 2);
302 layoutViewport.
x = visibleViewport.
x - overlap;
303 layoutViewport.
y = visibleViewport.
y - overlap;
308 contourLabelInstances.clear();
309 labelInstances.clear();
314 int64_t viewportHeight)
const 316 bool collision=
false;
317 for (
int r=std::max(0,mask.
rowFrom); !collision && r<=std::min((
int)viewportHeight-1, mask.
rowTo); r++){
318 for (
int c=std::max(0,mask.
cellFrom); !collision && c<=std::min((
int)mask.
size()-1,mask.
cellTo); c++){
319 collision |= (mask.
d[c] & canvas[r*mask.
size() + c]) != 0;
327 int viewportHeight)
const 329 for (
int r=std::max(0,mask.
rowFrom); r<=std::min((
int)viewportHeight-1, mask.
rowTo); r++){
330 for (
int c=std::max(0,mask.
cellFrom); c<=std::min((
int)mask.
size()-1, mask.
cellTo); c++){
331 canvas[r*mask.
size() + c] = mask.
d[c] | canvas[r*mask.
size() + c];
339 return labelData.
alpha < 0.8;
343 const MapParameter& parameter)
345 std::vector<ContourLabelType> allSortedContourLabels;
346 std::vector<LabelInstanceType> allSortedLabels;
350 double shieldLabelPadding = projection.
ConvertWidthToPixel(parameter.GetPlateLabelPadding());
351 double contourLabelPadding = projection.
ConvertWidthToPixel(parameter.GetContourLabelPadding());
352 double overlayLabelPadding = projection.
ConvertWidthToPixel(parameter.GetOverlayLabelPadding());
354 std::swap(allSortedLabels, labelInstances);
355 std::swap(allSortedContourLabels, contourLabelInstances);
358 std::stable_sort(allSortedLabels.begin(),
359 allSortedLabels.end(),
360 LabelInstanceSorter<NativeGlyph, NativeLabel>);
361 std::stable_sort(allSortedContourLabels.begin(),
362 allSortedContourLabels.end(),
363 ContourLabelSorter<NativeGlyph>);
366 int64_t rowSize = (layoutViewport.
width / 64)+1;
367 std::vector<uint64_t> iconCanvas((
size_t)(rowSize*layoutViewport.
height));
368 std::vector<uint64_t> labelCanvas((
size_t)(rowSize*layoutViewport.
height));
369 std::vector<uint64_t> overlayCanvas((
size_t)(rowSize*layoutViewport.
height));
371 auto labelIter = allSortedLabels.begin();
372 auto contourLabelIter = allSortedContourLabels.begin();
373 while (labelIter != allSortedLabels.end()
374 || contourLabelIter != allSortedContourLabels.end()) {
376 auto currentLabel = labelIter;
377 auto currentContourLabel = contourLabelIter;
378 if (currentLabel != allSortedLabels.end()
379 && currentContourLabel != allSortedContourLabels.end()) {
380 if (currentLabel->priority != currentContourLabel->priority) {
381 if (currentLabel->priority < currentContourLabel->priority) {
382 currentContourLabel = allSortedContourLabels.end();
384 currentLabel = allSortedLabels.end();
389 if (currentLabel != allSortedLabels.end()){
391 std::vector<Mask> masks(currentLabel->elements.size(), m);
392 std::vector<std::vector<uint64_t> *> canvases(currentLabel->elements.size(),
nullptr);
394 std::vector<typename LabelInstance<NativeGlyph, NativeLabel>::Element> visibleElements;
396 for (
size_t eli=0; eli < currentLabel->elements.size(); eli++){
398 Mask& row=masks[eli];
402 padding = iconPadding;
404 padding = overlayLabelPadding;
405 }
else if (dynamic_cast<const ShieldStyle*>(element.
labelData.
style.get())!=
nullptr){
406 padding = shieldLabelPadding;
408 padding = labelPadding;
411 IntRectangle rectangle{ (int)std::floor(element.
x - layoutViewport.
x - padding),
412 (int)std::floor(element.
y - layoutViewport.
y - padding),
414 std::vector<uint64_t> *canvas = &labelCanvas;
418 rectangle.height = 0;
424 canvas = &iconCanvas;
425 #ifdef DEBUG_LABEL_LAYOUTER 428 " prio " << currentLabel->priority;
431 " prio " << currentLabel->priority;
435 #ifdef DEBUG_LABEL_LAYOUTER 437 "label prio " << currentLabel->priority <<
": " <<
441 rectangle.width = std::ceil(element.
label->width + 2*padding);
442 rectangle.height = std::ceil(element.
label->height + 2*padding);
445 canvas = &overlayCanvas;
451 visibleElements.push_back(element);
452 canvases[eli]=canvas;
454 #ifdef DEBUG_LABEL_LAYOUTER 455 std::cout <<
" -> " << (collision ?
"skipped" :
"added") << std::endl;
462 instanceCopy.
priority = currentLabel->priority;
463 instanceCopy.
elements = visibleElements;
464 if (!instanceCopy.
elements.empty()) {
465 labelInstances.push_back(instanceCopy);
468 for (
size_t eli=0; eli < currentLabel->elements.size(); eli++) {
469 if (canvases[eli] !=
nullptr) {
478 if (currentContourLabel != allSortedContourLabels.end()){
479 int glyphCnt=currentContourLabel->glyphs.size();
481 #ifdef DEBUG_LABEL_LAYOUTER 482 std::cout <<
"Test contour label prio " << currentContourLabel->priority <<
": " << currentContourLabel->text;
486 std::vector<Mask> masks(glyphCnt, m);
487 bool collision=
false;
488 for (
int gi=0; !collision && gi<glyphCnt; gi++) {
490 auto glyph=currentContourLabel->glyphs[gi];
492 (int)(glyph.trPosition.GetX() - layoutViewport.
x - contourLabelPadding),
493 (
int)(glyph.trPosition.GetY() - layoutViewport.
y - contourLabelPadding),
494 (
int)(glyph.trWidth + 2*contourLabelPadding),
495 (
int)(glyph.trHeight + 2*contourLabelPadding)
497 masks[gi].prepare(rect);
501 for (
int gi=0; gi<glyphCnt; gi++) {
504 contourLabelInstances.push_back(*currentContourLabel);
506 #ifdef DEBUG_LABEL_LAYOUTER 507 std::cout <<
" -> " << (collision ?
"skipped" :
"added") << std::endl;
543 template<
class Pa
inter>
545 const MapParameter& parameter,
549 std::vector<const typename LabelInstanceType::Element*> textElements;
550 std::vector<const typename LabelInstanceType::Element*> overlayElements;
561 if (!visibleViewport.
Intersects(elementRectangle)){
566 p->DrawSymbol(projection,
582 overlayElements.push_back(&el);
584 textElements.push_back(&el);
592 p->DrawLabel(projection, parameter,
594 el->labelData, el->label->label);
598 p->DrawLabel(projection, parameter,
600 el->labelData, el->label->label);
604 p->DrawGlyphs(projection, parameter,
605 label.style, label.glyphs);
610 const MapParameter& parameter,
611 const Vertex2D& point,
612 const std::vector<LabelData> &data,
613 double objectWidth = 10.0)
618 for (
const auto &d:data) {
621 if (d.type==LabelData::Type::Icon || d.type==LabelData::Type::Symbol){
623 element.
x = point.GetX() - d.iconWidth / 2;
625 element.
y = point.GetY() - d.iconHeight / 2;
626 offset = point.GetY() + d.iconHeight / 2;
629 offset += d.iconHeight;
635 element.
label = textLayouter->Layout(projection, parameter,
640 element.
x = point.GetX() - element.
label->width / 2;
642 element.
y = point.GetY() - element.
label->height / 2;
643 offset = point.GetY() + element.
label->height / 2;
646 offset += element.
label->height;
649 instance.
elements.push_back(element);
652 labelInstances.push_back(instance);
656 const MapParameter& parameter,
661 LabelPtr label = textLayouter->Layout(
672 double textBaselineOffset = label->height * 0.25;
674 std::vector<Glyph<NativeGlyph>> glyphs = label->ToGlyphs();
679 while (offset+label->width < pLength){
695 #if defined(DEBUG_LABEL_LAYOUTER) 696 cLabel.text = labelData.
text;
703 bool upwards=initialAngle>90 && initialAngle<270;
706 double glyphOffset = upwards ?
707 offset - glyph.position.GetX() + label->width:
708 offset + glyph.position.GetX();
709 osmscout::Vertex2D point=labelPath.
PointAtLength(glyphOffset);
711 DoubleRectangle textBoundingBox = textLayouter->GlyphBoundingBox(glyph.glyph);
712 double w = textBoundingBox.
width;
713 double h = textBoundingBox.
height;
714 osmscout::Vertex2D tl(textBoundingBox.
x, textBoundingBox.
y);
717 double angle=labelPath.
AngleAtLength(upwards ? glyphOffset - w/2 : glyphOffset + w/2)*-1;
721 double diagonal=w+h+std::abs(textBaselineOffset);
725 point.GetX()-diagonal,
726 point.GetY()-diagonal,
736 double sinA=std::sin(angle);
737 double cosA=std::cos(angle);
740 glyphCopy.
position=osmscout::Vertex2D(point.GetX() - textBaselineOffset * sinA,
741 point.GetY() + textBaselineOffset * cosA);
742 glyphCopy.
angle=angle;
745 std::array<double, 4> x{tl.GetX(), tl.GetX() + w, tl.GetX() + w, tl.GetX()};
746 std::array<double, 4> y{tl.GetY(), tl.GetY(), tl.GetY() + h, tl.GetY() + h};
749 for (
int i=0; i<4; i++){
752 x[i] = ox * cosA - oy * sinA;
753 y[i] = ox * sinA + oy * cosA;
761 for (
int i=1; i<4; i++){
762 minX = std::min(minX, x[i]);
763 maxX = std::max(maxX, x[i]);
764 minY = std::min(minY, y[i]);
765 maxY = std::max(maxY, y[i]);
769 glyphCopy.
trWidth = maxX - minX;
772 cLabel.
glyphs.push_back(glyphCopy);
774 if (!cLabel.
glyphs.empty()) {
775 contourLabelInstances.push_back(cLabel);
782 const std::vector<LabelInstanceType>&
Labels()
const 784 return labelInstances;
789 return contourLabelInstances;
793 TextLayouter *textLayouter;
794 std::vector<ContourLabelType> contourLabelInstances;
795 std::vector<LabelInstanceType> labelInstances;
798 uint32_t layoutOverlap=0;
void RegisterContourLabel(const Projection &projection, const MapParameter ¶meter, const PathLabelData &labelData, const LabelPath &labelPath)
Definition: LabelLayouter.h:655
double ConvertWidthToPixel(double width) const
Definition: Projection.h:280
Definition: LabelLayouter.h:144
Mask(size_t rowSize)
Definition: LabelLayouter.h:205
double iconWidth
Definition: LabelLayouter.h:119
T width
Definition: LabelLayouter.h:45
Type
Definition: LabelLayouter.h:101
std::string text
The label text.
Definition: LabelLayouter.h:153
double angle
clock-wise rotation in radians
Definition: LabelLayouter.h:133
LabelData labelData
Definition: LabelLayouter.h:177
T height
Definition: LabelLayouter.h:46
Definition: LabelLayouter.h:105
const std::vector< ContourLabelType > & ContourLabels() const
Definition: LabelLayouter.h:787
size_t position
Relative position of the label.
Definition: LabelLayouter.h:110
NativeLabel label
Definition: LabelLayouter.h:147
Definition: LabelLayouter.h:87
void MarkLabelPlace(std::vector< uint64_t > &canvas, const Mask &mask, int viewportHeight) const
Definition: LabelLayouter.h:325
void Reset()
Definition: LabelLayouter.h:306
size_t priority
Priority of the entry (minimum of priority label elements)
Definition: LabelLayouter.h:185
void RegisterLabel(const Projection &projection, const MapParameter ¶meter, const Vertex2D &point, const std::vector< LabelData > &data, double objectWidth=10.0)
Definition: LabelLayouter.h:609
double width
Definition: LabelLayouter.h:149
double contourLabelSpace
Definition: LabelLayouter.h:95
LabelStyleRef style
Style for drawing.
Definition: LabelLayouter.h:115
bool CheckLabelCollision(const std::vector< uint64_t > &canvas, const Mask &mask, int64_t viewportHeight) const
Definition: LabelLayouter.h:312
Rectangle(T x, T y, T width, T height)
Definition: LabelLayouter.h:51
void SetLayoutOverlap(uint32_t overlap)
Definition: LabelLayouter.h:297
std::vector< Element > elements
Definition: LabelLayouter.h:187
Definition: LabelLayouter.h:172
Definition: LabelLayouter.h:175
void DrawLabels(const Projection &projection, const MapParameter ¶meter, Painter *p)
Definition: LabelLayouter.h:544
OSMSCOUT_MAP_API void prepare(const IntRectangle &rect)
Type type
Definition: LabelLayouter.h:108
const std::vector< LabelInstanceType > & Labels() const
Definition: LabelLayouter.h:782
double iconHeight
Definition: LabelLayouter.h:120
std::shared_ptr< LabelType > LabelPtr
Definition: LabelLayouter.h:283
double trHeight
height after rotation
Definition: LabelLayouter.h:137
osmscout::Vertex2D trPosition
top-left position after rotation
Definition: LabelLayouter.h:135
T y
Definition: LabelLayouter.h:44
bool IsOverlay(const LabelData &labelData) const
Definition: LabelLayouter.h:337
double x
Coordinate of the left, top edge of the text / icon / symbol.
Definition: LabelLayouter.h:178
void SetViewport(const DoubleRectangle &v)
Definition: LabelLayouter.h:291
double alpha
Alpha value of the label; 0.0 = fully transparent, 1.0 = solid.
Definition: LabelLayouter.h:112
bool TestAngleVariance(double startOffset, double endOffset, double maximumAngle) const
Mask & operator=(const Mask &m)=delete
Definition: LabelLayouter.h:277
Definition: LabelLayouter.h:191
Definition: LabelLayouter.h:103
int64_t size() const
Definition: LabelLayouter.h:218
Definition: Projection.h:43
double y
Coordinate of the left, top edge of the text / icon / symbol.
Definition: LabelLayouter.h:179
std::shared_ptr< PathTextStyle > PathTextStyleRef
Definition: Styles.h:877
std::shared_ptr< Label< NativeGlyph, NativeLabel > > label
Definition: LabelLayouter.h:181
std::vector< Glyph< NativeGlyph > > glyphs
Definition: LabelLayouter.h:198
osmscout::Vertex2D position
glyph baseline position
Definition: LabelLayouter.h:132
int cellFrom
Definition: LabelLayouter.h:225
double AngleAtLengthDeg(double offset) const
double GetLength() const
Definition: LabelPath.h:56
void Layout(const Projection &projection, const MapParameter ¶meter)
Definition: LabelLayouter.h:342
IconStyleRef iconStyle
Icon or symbol style.
Definition: LabelLayouter.h:118
Definition: LabelLayouter.h:104
Definition: LabelLayouter.h:202
Label(Args &&... args)
Definition: LabelLayouter.h:158
Definition: LabelPath.h:42
Definition: LabelLayouter.h:98
#define OSMSCOUT_MAP_API
Definition: MapImportExport.h:45
int cellTo
Definition: LabelLayouter.h:226
double AngleAtLength(double offset) const
bool Intersects(const Rectangle< T > &other)
Definition: LabelLayouter.h:73
Definition: LabelLayouter.h:42
std::vector< uint64_t > d
Definition: LabelLayouter.h:221
PathTextStyleRef style
Definition: LabelLayouter.h:93
Definition: LabelLayouter.h:129
int rowTo
Definition: LabelLayouter.h:228
size_t priority
Definition: LabelLayouter.h:197
size_t priority
Priority of the entry.
Definition: LabelLayouter.h:90
double trWidth
width after rotation
Definition: LabelLayouter.h:136
NativeGlyph glyph
Definition: LabelLayouter.h:131
std::vector< Glyph< NativeGlyph > > ToGlyphs() const
Rectangle< double > DoubleRectangle
Definition: LabelLayouter.h:85
Vertex2D PointAtLength(double offset) const
std::shared_ptr< LabelStyle > LabelStyleRef
Definition: Styles.h:496
osmscout::PathTextStyleRef style
Style for drawing.
Definition: LabelLayouter.h:199
LabelLayouter(TextLayouter *textLayouter)
Definition: LabelLayouter.h:287
size_t priority
Priority of the entry.
Definition: LabelLayouter.h:109
double contourLabelOffset
Definition: LabelLayouter.h:94
static bool ContourLabelSorter(const ContourLabel< NativeGlyph > &a, const ContourLabel< NativeGlyph > &b)
Definition: LabelLayouter.h:244
double height
Definition: LabelLayouter.h:150
Rectangle< T > & Set(T nx, T ny, T nw, T nh)
Definition: LabelLayouter.h:56
int rowFrom
Definition: LabelLayouter.h:227
double fontSize
Font size to be used.
Definition: LabelLayouter.h:113
double fontSize
Font size to be used.
Definition: LabelLayouter.h:152
double height
Definition: LabelLayouter.h:92
std::string text
The label text (type==Text|PathText)
Definition: LabelLayouter.h:116
static bool LabelInstanceSorter(const LabelInstance< NativeGlyph, NativeLabel > &a, const LabelInstance< NativeGlyph, NativeLabel > &b)
Definition: LabelLayouter.h:232
std::string text
The label text (type==Text|PathText)
Definition: LabelLayouter.h:91
std::shared_ptr< IconStyle > IconStyleRef
Definition: Styles.h:975
T x
Definition: LabelLayouter.h:43