File size: 4,260 Bytes
e05eed1
98a67a0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
// SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <vector>
#include <random>
#include <algorithm>

#include "../geometry.h"

namespace graph_detection {



struct Edge {
    int32_t A;
    int32_t B;

    Edge() = default;
    Edge(int32_t a, int32_t b) : A(a), B(b) {}

    bool Touches(int32_t idx) const { return A == idx || B == idx; }
    bool Touches(const Edge &other) const;
};

inline
bool edge_touches(const Edge &edge, int32_t vertex) {
    return edge.A == vertex || edge.B == vertex;
}

inline
bool Edge::Touches(const Edge &other) const {
    return edge_touches(other, A) || edge_touches(other, B);
}

typedef Point_<float> Pointf;
typedef AABB_<float> AABBf;
typedef Polygon_<float> Polyf;
typedef std::vector<Pointf> Polyline;

std::vector<Edge> find_bottom(const Polygon_<float> &poly, bool useVertexOrder);

void find_long_edges(const Polygon_<float> &poly, Edge *bottoms, std::vector<Edge> &outLongEdge1, std::vector<Edge> &outLongEdge2);

void split_edge_sequence_by_step(const Polygon_<float> &poly, const std::vector<Edge> &longEdge1, const std::vector<Edge> &longEdge2,
                                 float step, std::vector<Pointf> &outInnerPoints1, std::vector<Pointf> &outInnerPoints2);

std::string print_poly(const Polyf &poly);

template<typename T>
inline
std::vector<T> vec_cumsum(const std::vector<T> &v)
{
    std::vector<T> ret;
    ret.reserve(v.size() + 1);
    ret.push_back(0);
    for (T val : v) {
        ret.push_back(ret.back() + val);
    }
    return ret;
}

template<typename RandEng, typename Fn>
inline
void n_choose_k(size_t n, size_t k, RandEng &randEng, Fn fn)
{
    if (k == 0) return;

    // TODO(mranzinger): This algorithm can be replaced with sampling from a geometric
    // distribution, which drastically reduces the runtime complexity
    for (size_t i = 0; i < n; ++i) {
        size_t leftover = n - i;
        if (leftover <= k) {
            fn(i);
            --k;
        } else {
            float p = std::uniform_real_distribution<float>(0.0f, 1.0f)(randEng);
            float probSample = float{k} / float{leftover};
            if (p < probSample) {
                fn(i);
                --k;
            }
        }
    }
}

template<typename T>
inline T clamp(T val, T minVal, T maxVal) {
    return std::max(std::min(val, maxVal), minVal);
}

inline
Pointf avg_point(const std::vector<Pointf> &points)
{
    return std::accumulate(std::begin(points), std::end(points), Pointf(0,0)) / float(points.size());
}

inline
float vector_sin(const Pointf &pt)
{
    // sin = y / len(pt)
    return pt.Y / (length(pt) + 1e-8);
}

inline
float vector_cos(const Pointf &pt)
{
    // cos = x / len(pt)
    return pt.X / (length(pt) + 1e-8);
}

inline
void vector_cos_sin(const Pointf & pt, float &outCos, float &outSin)
{
    float len = length(pt) + 1e-8;
    outCos = pt.X / len;
    outSin = pt.Y / len;
}

inline
float point_dist_to_line(const Pointf &l1, const Pointf &l2, const Pointf &pt)
{
    auto d = l2 - l1;

    auto lineLen = length(d);

    if (lineLen > 0) {
        float distance = abs(
              d.Y * pt.X
            - d.X * pt.Y
            + l2.X * l1.Y
            - l2.Y * l1.X
        ) / lineLen;
        return distance;
    } else {
        return length(pt - l1);
    }
}

template<typename T>
T find_mode(std::vector<T> &inputs) {
    using std::sort;
    using std::begin;
    using std::end;

    if (inputs.empty()) {
        throw std::runtime_error("Cannot find mode of empty distribution!");
    }

    sort(begin(inputs), end(inputs));

    T currVal = inputs[0];
    size_t currCount = 1;

    T modeVal = inputs[0];
    size_t modeCount = 1;

    auto commitCurr = [&] () {
        if (currCount > modeCount) {
            modeCount = currCount;
            modeVal = currVal;
        }
    };

    for (size_t i = 1; i < inputs.size(); ++i) {
        if (inputs[i] == currVal) {
            ++currCount;
        } else {
            // Start of a new value
            commitCurr();

            currCount = 1;
            currVal = inputs[i];
        }
    }

    commitCurr();

    return modeVal;
}

} // namespace graph_detection