port bboxifyLabel from -js
This commit is contained in:
@@ -17,10 +17,6 @@ struct Anchor {
|
||||
explicit Anchor(float x_, float y_, float angle_, float scale_, int segment_)
|
||||
: x(x_), y(y_), angle(angle_), scale(scale_), segment(segment_) {}
|
||||
|
||||
template <typename M>
|
||||
inline Anchor matMul(const M &m) const {
|
||||
return Anchor{m[0] * x + m[1] * y, m[2] * x + m[3] * y, angle, scale, segment};
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::vector<Anchor> Anchors;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mbgl/text/collision_feature.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -24,10 +25,65 @@ CollisionFeature::CollisionFeature(const std::vector<Coordinate> &line, const An
|
||||
}
|
||||
|
||||
void CollisionFeature::bboxifyLabel(const std::vector<Coordinate> &line,
|
||||
const Anchor &anchor, const float length, const float height) {
|
||||
const Anchor &anchor, const float labelLength, const float boxSize) {
|
||||
|
||||
if (length && height && line.size() && anchor.x) {
|
||||
fprintf(stderr, "");
|
||||
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;
|
||||
|
||||
Coordinate anchorPoint = Coordinate{ (int16_t)anchor.x, (int16_t)anchor.y };
|
||||
|
||||
Coordinate &p = anchorPoint;
|
||||
int index = anchor.segment + 1;
|
||||
float anchorDistance = firstBoxOffset;
|
||||
|
||||
// move backwards along the line to the first segment the label appears on
|
||||
while (anchorDistance > -labelLength / 2) {
|
||||
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<float>(line[index], p);
|
||||
p = line[index];
|
||||
}
|
||||
|
||||
float segmentLength = util::dist<float>(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<float>(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<float> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
namespace mbgl {
|
||||
class CollisionBox {
|
||||
public:
|
||||
explicit CollisionBox(const Anchor &_anchor, float _x1, float _y1, float _x2, float _y2, float _maxScale) :
|
||||
explicit CollisionBox(const vec2<float> &_anchor, float _x1, float _y1, float _x2, float _y2, float _maxScale) :
|
||||
anchor(_anchor), x1(_x1), y1(_y1), x2(_x2), y2(_y2), maxScale(_maxScale) {}
|
||||
|
||||
// the box is centered around the anchor point
|
||||
const Anchor anchor;
|
||||
const vec2<float> anchor;
|
||||
|
||||
// distances to the edges from the anchor
|
||||
const float x1;
|
||||
|
||||
@@ -25,14 +25,14 @@ float CollisionTile::placeFeature(const CollisionFeature &feature) {
|
||||
float minPlacementScale = minScale;
|
||||
|
||||
for (auto& box : feature.boxes) {
|
||||
const Anchor anchor = box.anchor.matMul(rotationMatrix);
|
||||
const auto anchor = box.anchor.matMul(rotationMatrix);
|
||||
|
||||
std::vector<CollisionTreeBox> blockingBoxes;
|
||||
tree.query(bgi::intersects(getTreeBox(anchor, box)), std::back_inserter(blockingBoxes));
|
||||
|
||||
for (auto& blockingTreeBox : blockingBoxes) {
|
||||
const auto& blocking = std::get<1>(blockingTreeBox);
|
||||
Anchor blockingAnchor = blocking.anchor.matMul(rotationMatrix);
|
||||
auto blockingAnchor = blocking.anchor.matMul(rotationMatrix);
|
||||
|
||||
// Find the lowest scale at which the two boxes can fit side by side without overlapping.
|
||||
// Original algorithm:
|
||||
@@ -89,7 +89,7 @@ void CollisionTile::insertFeature(CollisionFeature &feature, const float minPlac
|
||||
|
||||
}
|
||||
|
||||
Box CollisionTile::getTreeBox(const Anchor &anchor, const CollisionBox &box) {
|
||||
Box CollisionTile::getTreeBox(const vec2<float> &anchor, const CollisionBox &box) {
|
||||
return Box{
|
||||
Point{
|
||||
anchor.x + box.x1,
|
||||
|
||||
@@ -50,7 +50,7 @@ class CollisionTile {
|
||||
|
||||
private:
|
||||
|
||||
Box getTreeBox(const Anchor &anchor, const CollisionBox &box);
|
||||
Box getTreeBox(const vec2<float> &anchor, const CollisionBox &box);
|
||||
|
||||
Tree tree;
|
||||
std::array<float, 4> rotationMatrix;
|
||||
|
||||
Reference in New Issue
Block a user