SymbolQuads getIconQuads(Anchor& anchor, const PositionedIcon& shapedIcon, const GeometryCoordinates& line, const SymbolLayoutProperties& layout, const bool alongLine) { auto image = *(shapedIcon.image); const float border = 1.0; auto left = shapedIcon.left - border; auto right = left + image.pos.w / image.relativePixelRatio; auto top = shapedIcon.top - border; auto bottom = top + image.pos.h / image.relativePixelRatio; vec2<float> tl{left, top}; vec2<float> tr{right, top}; vec2<float> br{right, bottom}; vec2<float> bl{left, bottom}; float angle = layout.icon.rotate * util::DEG2RAD; if (alongLine) { assert(static_cast<unsigned int>(anchor.segment) < line.size()); const GeometryCoordinate &prev= line[anchor.segment]; if (anchor.y == prev.y && anchor.x == prev.x && static_cast<unsigned int>(anchor.segment + 1) < line.size()) { const GeometryCoordinate &next= line[anchor.segment + 1]; angle += std::atan2(anchor.y - next.y, anchor.x - next.x) + M_PI; } else { angle += std::atan2(anchor.y - prev.y, anchor.x - prev.x); } } if (angle) { // Compute the transformation matrix. float angle_sin = std::sin(angle); float angle_cos = std::cos(angle); std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; tl = tl.matMul(matrix); tr = tr.matMul(matrix); bl = bl.matMul(matrix); br = br.matMul(matrix); } SymbolQuads quads; quads.emplace_back(tl, tr, bl, br, image.pos, 0, anchor, globalMinScale, std::numeric_limits<float>::infinity()); return quads; }
SymbolQuads getIconQuads(Anchor &anchor, const PositionedIcon &shapedIcon, const std::vector<Coordinate> &line, const StyleLayoutSymbol &layout, const bool alongLine) { const float border = 1.0; auto left = shapedIcon.left - border; auto right = left + shapedIcon.image.w; auto top = shapedIcon.top - border; auto bottom = top + shapedIcon.image.h; vec2<float> tl{left, top}; vec2<float> tr{right, top}; vec2<float> br{right, bottom}; vec2<float> bl{left, bottom}; float angle = layout.icon.rotate * M_PI / 180.0f; if (alongLine) { assert(static_cast<unsigned int>(anchor.segment) < line.size()); const Coordinate &prev= line[anchor.segment]; angle += std::atan2(anchor.y - prev.y, anchor.x - prev.x); } if (angle) { // Compute the transformation matrix. float angle_sin = std::sin(angle); float angle_cos = std::cos(angle); std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; tl = tl.matMul(matrix); tr = tr.matMul(matrix); bl = bl.matMul(matrix); br = br.matMul(matrix); } SymbolQuads quads; quads.emplace_back(tl, tr, bl, br, shapedIcon.image, 0, anchor, globalMinScale, std::numeric_limits<float>::infinity()); return quads; }
SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText, const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties& layout, const bool alongLine, const GlyphPositions& face) { const float textRotate = layout.text.rotate * util::DEG2RAD; const bool keepUpright = layout.text.keepUpright; SymbolQuads quads; for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) { auto face_it = face.find(positionedGlyph.glyph); if (face_it == face.end()) continue; const Glyph &glyph = face_it->second; const Rect<uint16_t> &rect = glyph.rect; if (!glyph) continue; if (!rect.hasArea()) continue; const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale; GlyphInstances glyphInstances; if (alongLine) { getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, true); if (keepUpright) getSegmentGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, false); } else { glyphInstances.emplace_back(GlyphInstance{anchor}); } // The rects have an addditional buffer that is not included in their size; const float glyphPadding = 1.0f; const float rectBuffer = 3.0f + glyphPadding; const float x1 = positionedGlyph.x + glyph.metrics.left - rectBuffer; const float y1 = positionedGlyph.y - glyph.metrics.top - rectBuffer; const float x2 = x1 + rect.w; const float y2 = y1 + rect.h; const vec2<float> otl{x1, y1}; const vec2<float> otr{x2, y1}; const vec2<float> obl{x1, y2}; const vec2<float> obr{x2, y2}; for (const GlyphInstance &instance : glyphInstances) { vec2<float> tl = otl; vec2<float> tr = otr; vec2<float> bl = obl; vec2<float> br = obr; const float angle = instance.angle + textRotate; if (angle) { // Compute the transformation matrix. float angle_sin = std::sin(angle); float angle_cos = std::cos(angle); std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; tl = tl.matMul(matrix); tr = tr.matMul(matrix); bl = bl.matMul(matrix); br = br.matMul(matrix); } // Prevent label from extending past the end of the line const float glyphMinScale = std::max(instance.minScale, anchor.scale); const float glyphAngle = std::fmod((anchor.angle + textRotate + instance.offset + 2 * M_PI), (2 * M_PI)); quads.emplace_back(tl, tr, bl, br, rect, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale); } } return quads; }
SymbolQuads getGlyphQuads(Anchor& anchor, const Shaping& shapedText, const float boxScale, const GeometryCoordinates& line, const SymbolLayoutProperties::Evaluated& layout, const style::SymbolPlacementType placement, const GlyphPositionMap& positions) { const float textRotate = layout.get<TextRotate>() * util::DEG2RAD; const bool keepUpright = layout.get<TextKeepUpright>(); SymbolQuads quads; for (const PositionedGlyph &positionedGlyph: shapedText.positionedGlyphs) { auto positionsIt = positions.find(positionedGlyph.glyph); if (positionsIt == positions.end()) continue; const GlyphPosition& glyph = positionsIt->second; const Rect<uint16_t>& rect = glyph.rect; const float centerX = (positionedGlyph.x + glyph.metrics.advance / 2.0f) * boxScale; GlyphInstances glyphInstances; if (placement == style::SymbolPlacementType::Line) { getLineGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, false); if (keepUpright) getLineGlyphs(std::back_inserter(glyphInstances), anchor, centerX, line, anchor.segment, true); } else { glyphInstances.emplace_back(GlyphInstance{anchor.point}); } // The rects have an addditional buffer that is not included in their size; const float glyphPadding = 1.0f; const float rectBuffer = 3.0f + glyphPadding; const float x1 = positionedGlyph.x + glyph.metrics.left - rectBuffer; const float y1 = positionedGlyph.y - glyph.metrics.top - rectBuffer; const float x2 = x1 + rect.w; const float y2 = y1 + rect.h; const Point<float> center{positionedGlyph.x, static_cast<float>(static_cast<float>(glyph.metrics.advance) / 2.0)}; Point<float> otl{x1, y1}; Point<float> otr{x2, y1}; Point<float> obl{x1, y2}; Point<float> obr{x2, y2}; if (positionedGlyph.angle != 0) { otl = util::rotate(otl - center, positionedGlyph.angle) + center; otr = util::rotate(otr - center, positionedGlyph.angle) + center; obl = util::rotate(obl - center, positionedGlyph.angle) + center; obr = util::rotate(obr - center, positionedGlyph.angle) + center; } for (const GlyphInstance &instance : glyphInstances) { Point<float> tl = otl; Point<float> tr = otr; Point<float> bl = obl; Point<float> br = obr; if (textRotate) { // Compute the transformation matrix. float angle_sin = std::sin(textRotate); float angle_cos = std::cos(textRotate); std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}}; tl = util::matrixMultiply(matrix, tl); tr = util::matrixMultiply(matrix, tr); bl = util::matrixMultiply(matrix, bl); br = util::matrixMultiply(matrix, br); } // Prevent label from extending past the end of the line const float glyphMinScale = std::max(instance.minScale, anchor.scale); // All the glyphs for a label are tagged with either the "right side up" or "upside down" anchor angle, // which is used at placement time to determine which set to show const float anchorAngle = std::fmod((anchor.angle + (instance.upsideDown ? M_PI : 0.0) + 2 * M_PI), (2 * M_PI)); const float glyphAngle = std::fmod((instance.angle + (instance.upsideDown ? M_PI : 0.0) + 2 * M_PI), (2 * M_PI)); quads.emplace_back(tl, tr, bl, br, rect, anchorAngle, glyphAngle, instance.anchorPoint, glyphMinScale, instance.maxScale, shapedText.writingMode); } } return quads; }