#include #include namespace mbgl { CollisionFeature::CollisionFeature(const GeometryCoordinates &line, const Anchor &anchor, const float top, const float bottom, const float left, const float right, const float boxScale, const float padding, const bool alongLine, const bool straight) { if (top == 0 && bottom == 0 && left == 0 && right == 0) return; const float y1 = top * boxScale - padding; const float y2 = bottom * boxScale + padding; const float x1 = left * boxScale - padding; const float x2 = right * boxScale + padding; if (alongLine) { float height = y2 - y1; const float length = x2 - x1; if (height <= 0.0f) return; height = std::max(10.0f * boxScale, height); GeometryCoordinate anchorPoint(int16_t(anchor.x), int16_t(anchor.y)); if (straight) { // used for icon labels that are aligned with the line, but don't curve along it const vec2 vector = util::unit(vec2(line[anchor.segment + 1] - line[anchor.segment])) * length; const GeometryCoordinates newLine({ anchorPoint - vector, anchorPoint + vector }); bboxifyLabel(newLine, anchorPoint, 0, length, height); } else { // used for text labels that curve along a line bboxifyLabel(line, anchorPoint, anchor.segment, length, height); } } else { boxes.emplace_back(anchor, x1, y1, x2, y2, std::numeric_limits::infinity()); } } void CollisionFeature::bboxifyLabel(const GeometryCoordinates &line, GeometryCoordinate &anchorPoint, const int segment, const float labelLength, const float boxSize) { const float step = boxSize / 2; const unsigned int nBoxes = std::floor(labelLength / step); // offset the center of the first box by half a box so that the edge of the // box is at the edge of the label. const float firstBoxOffset = -boxSize / 2; GeometryCoordinate &p = anchorPoint; int index = segment + 1; float anchorDistance = firstBoxOffset; // move backwards along the line to the first segment the label appears on do { index--; // there isn't enough room for the label after the beginning of the line // checkMaxAngle should have already caught this if (index < 0) return; anchorDistance -= util::dist(line[index], p); p = line[index]; } while (anchorDistance > -labelLength / 2); float segmentLength = util::dist(line[index], line[index + 1]); for (unsigned int i = 0; i < nBoxes; i++) { // the distance the box will be from the anchor const float boxDistanceToAnchor = -labelLength / 2 + i * step; // the box is not on the current segment. Move to the next segment. while (anchorDistance + segmentLength < boxDistanceToAnchor) { anchorDistance += segmentLength; index++; // There isn't enough room before the end of the line. if (index + 1 >= (int)line.size()) return; segmentLength = util::dist(line[index], line[index + 1]); } // the distance the box will be from the beginning of the segment const float segmentBoxDistance = boxDistanceToAnchor - anchorDistance; const auto& p0 = line[index]; const auto& p1 = line[index + 1]; vec2 boxAnchor = { p0.x + segmentBoxDistance / segmentLength * (p1.x - p0.x), p0.y + segmentBoxDistance / segmentLength * (p1.y - p0.y) }; const float distanceToInnerEdge = std::max(std::fabs(boxDistanceToAnchor - firstBoxOffset) - step / 2, 0.0f); const float maxScale = labelLength / 2 / distanceToInnerEdge; boxes.emplace_back(boxAnchor, -boxSize / 2, -boxSize / 2, boxSize / 2, boxSize / 2, maxScale); } } } // namespace mbgl