CollisionFeature::CollisionFeature(const std::vector<Coordinate> &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);

        Coordinate 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<double> vector = util::unit(vec2<double>(line[anchor.segment + 1] - line[anchor.segment])) * length;
            const std::vector<Coordinate> 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<float>::infinity());
    }
}
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 style::SymbolPlacementType placement,
                                   IndexedSubfeature indexedFeature_,
                                   const float overscaling)
        : indexedFeature(std::move(indexedFeature_))
        , alongLine(placement == style::SymbolPlacementType::Line) {
    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 double length = x2 - x1;

        if (height <= 0.0f) return;

        height = std::max(10.0f * boxScale, height);

        GeometryCoordinate anchorPoint = convertPoint<int16_t>(anchor.point);
        bboxifyLabel(line, anchorPoint, anchor.segment, length, height, overscaling);
    } else {
        boxes.emplace_back(anchor.point, Point<float>{ 0, 0 }, x1, y1, x2, y2);
    }
}
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 style::SymbolPlacementType placement, IndexedSubfeature indexedFeature_,
        const bool straight)
        : indexedFeature(std::move(indexedFeature_)) {

    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 (placement == style::SymbolPlacementType::Line) {
        float height = y2 - y1;
        const double length = x2 - x1;

        if (height <= 0.0f) return;

        height = std::max(10.0f * boxScale, height);

        GeometryCoordinate anchorPoint = convertPoint<int16_t>(anchor.point);

        if (straight) {
            // used for icon labels that are aligned with the line, but don't curve along it
            const GeometryCoordinate vector = convertPoint<int16_t>(util::unit(convertPoint<double>(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.point, x1, y1, x2, y2, std::numeric_limits<float>::infinity());
    }
}