forked from mapsme/omim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfeature_algo.cpp
129 lines (104 loc) · 2.91 KB
/
feature_algo.cpp
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
#include "indexer/feature_algo.hpp"
#include "indexer/feature.hpp"
#include "base/logging.hpp"
namespace feature
{
class CalculateLineCenter
{
typedef m2::PointD P;
struct Value
{
Value(P const & p, double l) : m_p(p), m_len(l) {}
bool operator< (Value const & r) const { return (m_len < r.m_len); }
P m_p;
double m_len;
};
vector<Value> m_poly;
double m_length;
public:
CalculateLineCenter() : m_length(0.0) {}
void operator() (m2::PointD const & pt)
{
m_length += (m_poly.empty() ? 0.0 : m_poly.back().m_p.Length(pt));
m_poly.emplace_back(pt, m_length);
}
P GetCenter() const
{
typedef vector<Value>::const_iterator IterT;
double const l = m_length / 2.0;
IterT e = lower_bound(m_poly.begin(), m_poly.end(), Value(m2::PointD(0, 0), l));
if (e == m_poly.begin())
{
/// @todo It's very strange, but we have linear objects with zero length.
LOG(LWARNING, ("Zero length linear object"));
return e->m_p;
}
IterT b = e-1;
double const f = (l - b->m_len) / (e->m_len - b->m_len);
// For safety reasons (floating point calculations) do comparison instead of ASSERT.
if (0.0 <= f && f <= 1.0)
return (b->m_p * (1-f) + e->m_p * f);
else
return ((b->m_p + e->m_p) / 2.0);
}
};
class CalculatePointOnSurface
{
typedef m2::PointD P;
P m_center;
P m_rectCenter;
double m_squareDistanceToApproximate;
public:
CalculatePointOnSurface(m2::RectD const & rect)
{
m_rectCenter = rect.Center();
m_center = m_rectCenter;
m_squareDistanceToApproximate = numeric_limits<double>::max();
}
void operator() (P const & p1, P const & p2, P const & p3)
{
if (m_squareDistanceToApproximate == 0.0)
return;
if (m2::IsPointInsideTriangle(m_rectCenter, p1, p2, p3))
{
m_center = m_rectCenter;
m_squareDistanceToApproximate = 0.0;
return;
}
P triangleCenter(p1);
triangleCenter += p2;
triangleCenter += p3;
triangleCenter = triangleCenter / 3.0;
double triangleDistance = m_rectCenter.SquareLength(triangleCenter);
if (triangleDistance <= m_squareDistanceToApproximate)
{
m_center = triangleCenter;
m_squareDistanceToApproximate = triangleDistance;
}
}
P GetCenter() const { return m_center; }
};
m2::PointD GetCenter(FeatureType const & f, int scale)
{
feature::EGeomType const type = f.GetFeatureType();
switch (type)
{
case feature::GEOM_POINT:
return f.GetCenter();
case feature::GEOM_LINE:
{
CalculateLineCenter doCalc;
f.ForEachPointRef(doCalc, scale);
return doCalc.GetCenter();
}
default:
{
ASSERT_EQUAL ( type, feature::GEOM_AREA, () );
CalculatePointOnSurface doCalc(f.GetLimitRect(scale));
f.ForEachTriangleRef(doCalc, scale);
return doCalc.GetCenter();
}
}
}
m2::PointD GetCenter(FeatureType const & f) { return GetCenter(f, FeatureType::BEST_GEOMETRY); }
}