Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/flatgeobuf/packedrtree.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  FlatGeobuf
4
 * Purpose:  Packed RTree management
5
 * Author:   Björn Harrtell <bjorn at wololo dot org>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2018-2020, Björn Harrtell <bjorn at wololo dot org>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
// NOTE: The upstream of this file is in
14
// https://github.com/bjornharrtell/flatgeobuf/tree/master/src/cpp
15
16
#ifndef FLATGEOBUF_PACKEDRTREE_H_
17
#define FLATGEOBUF_PACKEDRTREE_H_
18
19
#include <cmath>
20
#include <deque>
21
#include <numeric>
22
23
#if defined(__clang__)
24
#pragma clang diagnostic push
25
#pragma clang diagnostic ignored "-Wweak-vtables"
26
#endif
27
#include "flatbuffers/flatbuffers.h"
28
#if defined(__clang__)
29
#pragma clang diagnostic pop
30
#endif
31
32
namespace FlatGeobuf
33
{
34
35
struct NodeItem
36
{
37
    double minX;
38
    double minY;
39
    double maxX;
40
    double maxY;
41
    uint64_t offset;
42
43
    double width() const
44
39
    {
45
39
        return maxX - minX;
46
39
    }
47
48
    double height() const
49
39
    {
50
39
        return maxY - minY;
51
39
    }
52
53
    static NodeItem sum(NodeItem a, const NodeItem &b)
54
0
    {
55
0
        a.expand(b);
56
0
        return a;
57
0
    }
58
59
    static NodeItem create(uint64_t offset = 0);
60
    const NodeItem &expand(const NodeItem &r);
61
    bool intersects(const NodeItem &r) const;
62
    std::vector<double> toVector();
63
};
64
65
struct Item
66
{
67
    NodeItem nodeItem;
68
};
69
70
struct SearchResultItem
71
{
72
    uint64_t offset;
73
    uint64_t index;
74
};
75
76
std::ostream &operator<<(std::ostream &os, NodeItem const &value);
77
78
uint32_t hilbert(uint32_t x, uint32_t y);
79
uint32_t hilbert(const NodeItem &n, uint32_t hilbertMax, const double minX,
80
                 const double minY, const double width, const double height);
81
void hilbertSort(std::vector<std::shared_ptr<Item>> &items);
82
83
constexpr uint32_t HILBERT_MAX = (1 << 16) - 1;
84
85
template <class ITEM_TYPE>
86
NodeItem calcExtent(const std::deque<ITEM_TYPE> &items)
87
78
{
88
78
    return std::accumulate(items.begin(), items.end(), NodeItem::create(0),
89
78
                           [](NodeItem a, const ITEM_TYPE &b) -> NodeItem
90
426
                           { return a.expand(b.nodeItem); });
91
78
}
92
93
template <class ITEM_TYPE> void hilbertSort(std::deque<ITEM_TYPE> &items)
94
39
{
95
39
    NodeItem extent = calcExtent(items);
96
39
    const double minX = extent.minX;
97
39
    const double minY = extent.minY;
98
39
    const double width = extent.width();
99
39
    const double height = extent.height();
100
39
    std::sort(
101
39
        items.begin(), items.end(),
102
39
        [minX, minY, width, height](const ITEM_TYPE &a, const ITEM_TYPE &b)
103
284
        {
104
284
            uint32_t ha =
105
284
                hilbert(a.nodeItem, HILBERT_MAX, minX, minY, width, height);
106
284
            uint32_t hb =
107
284
                hilbert(b.nodeItem, HILBERT_MAX, minX, minY, width, height);
108
284
            return ha > hb;
109
284
        });
110
39
}
111
112
void hilbertSort(std::vector<NodeItem> &items);
113
NodeItem calcExtent(const std::vector<std::shared_ptr<Item>> &items);
114
NodeItem calcExtent(const std::vector<NodeItem> &rects);
115
116
/**
117
 * Packed R-Tree
118
 * Based on https://github.com/mourner/flatbush
119
 */
120
class PackedRTree
121
{
122
    NodeItem _extent;
123
    NodeItem *_nodeItems = nullptr;
124
    uint64_t _numItems;
125
    uint64_t _numNodes;
126
    uint16_t _nodeSize;
127
    std::vector<std::pair<uint64_t, uint64_t>> _levelBounds;
128
    void init(const uint16_t nodeSize);
129
    void generateNodes();
130
    void fromData(const void *data);
131
132
  public:
133
    ~PackedRTree()
134
39
    {
135
39
        if (_nodeItems != nullptr)
136
39
            delete[] _nodeItems;
137
39
    }
138
139
    PackedRTree(const std::vector<std::shared_ptr<Item>> &items,
140
                const NodeItem &extent, const uint16_t nodeSize = 16);
141
    PackedRTree(const std::vector<NodeItem> &nodes, const NodeItem &extent,
142
                const uint16_t nodeSize = 16);
143
    PackedRTree(const void *data, const uint64_t numItems,
144
                const uint16_t nodeSize = 16);
145
    PackedRTree(std::function<void(NodeItem *)> fillNodeItems,
146
                const uint64_t numItems, const NodeItem &extent,
147
                const uint16_t nodeSize = 16);
148
    std::vector<SearchResultItem> search(double minX, double minY, double maxX,
149
                                         double maxY) const;
150
    static std::vector<SearchResultItem> streamSearch(
151
        const uint64_t numItems, const uint16_t nodeSize, const NodeItem &item,
152
        const std::function<void(uint8_t *, size_t, size_t)> &readNode);
153
    static std::vector<std::pair<uint64_t, uint64_t>>
154
    generateLevelBounds(const uint64_t numItems, const uint16_t nodeSize);
155
    uint64_t size() const;
156
    static uint64_t size(const uint64_t numItems, const uint16_t nodeSize = 16);
157
    NodeItem getExtent() const;
158
    void streamWrite(const std::function<void(uint8_t *, size_t)> &writeData);
159
};
160
161
}  // namespace FlatGeobuf
162
163
#endif