SectorZone: add attribute arc_boundary
[xcsoar.git] / src / Replay / CatmullRomInterpolator.hpp
blobdd596378fc238c18af8a7df74dbc6050ff96e717
1 /*
2 Copyright_License {
4 XCSoar Glide Computer - http://www.xcsoar.org/
5 Copyright (C) 2000-2013 The XCSoar Project
6 A detailed list of copyright holders can be found in the file "AUTHORS".
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #ifndef XCSOAR_CATMULL_ROM_INTERPOLATOR_HPP
25 #define XCSOAR_CATMULL_ROM_INTERPOLATOR_HPP
27 #include "Math/fixed.hpp"
28 #include "Geo/GeoPoint.hpp"
29 #include "Geo/GeoVector.hpp"
30 #include "Util/Clamp.hpp"
32 #include <algorithm>
33 #include <assert.h>
35 /**
36 * A Catmull-Rom splines interpolator
37 * @see http://www.cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
39 class CatmullRomInterpolator
41 public:
42 struct Record {
43 GeoPoint location;
44 fixed gps_altitude;
45 fixed baro_altitude;
46 fixed time;
49 private:
50 const fixed time;
52 unsigned num;
53 Record p[4];
55 public:
56 CatmullRomInterpolator(fixed _time):
57 time(_time)
59 Reset();
62 void
63 Reset()
65 num = 0;
68 void
69 Update(fixed t, GeoPoint location, fixed alt, fixed palt)
71 if (num && (t <= p[3].time))
72 return;
74 if (num < 4)
75 num++;
77 std::copy(p + 1, p + 4, p);
79 p[3].location = location;
80 p[3].gps_altitude = alt;
81 p[3].baro_altitude = palt;
82 p[3].time = t;
85 bool
86 Ready() const
88 return (num == 4);
91 GeoVector
92 GetVector(fixed _time) const
94 assert(Ready());
96 if (!positive(p[2].time-p[1].time))
97 return GeoVector(fixed(0), Angle::Zero());
99 const Record r0 = Interpolate(_time - fixed(0.05));
100 const Record r1 = Interpolate(_time + fixed(0.05));
102 fixed speed = p[1].location.Distance(p[2].location) / (p[2].time - p[1].time);
103 Angle bearing = r0.location.Bearing(r1.location);
105 return GeoVector(speed, bearing);
108 gcc_pure
109 Record
110 Interpolate(fixed _time) const
112 assert(Ready());
114 const fixed u = GetTimeFraction(_time, false);
117 ps = ( c0 c1 c2 c3)
118 [ 0 1 0 0] 1
119 [ -t 0 t 0] u
120 [ 2t t-3 3-2t -t] u^2
121 [ -t 2-t t-2 t] u^3
124 const fixed u2 = sqr(u);
125 const fixed u3 = u2 * u;
126 const fixed c[4]= {-time * u3 + 2 * time * u2 - time * u,
127 (fixed(2) - time) * u3 + (time - fixed(3)) * u2 + fixed(1),
128 (time - fixed(2)) * u3 + (fixed(3) - 2 * time) * u2 + time * u,
129 time * u3 - time * u2};
131 Record r;
132 r.location.latitude =
133 p[0].location.latitude * c[0] + p[1].location.latitude * c[1] +
134 p[2].location.latitude * c[2] + p[3].location.latitude * c[3];
136 r.location.longitude =
137 p[0].location.longitude * c[0] + p[1].location.longitude * c[1] +
138 p[2].location.longitude * c[2] + p[3].location.longitude * c[3];
140 r.gps_altitude =
141 p[0].gps_altitude * c[0] + p[1].gps_altitude * c[1] +
142 p[2].gps_altitude * c[2] + p[3].gps_altitude * c[3];
144 r.baro_altitude =
145 p[0].baro_altitude * c[0] + p[1].baro_altitude * c[1] +
146 p[2].baro_altitude * c[2] + p[3].baro_altitude * c[3];
148 r.time = _time;
150 return r;
153 fixed
154 GetMinTime() const
156 assert(Ready());
158 return p[0].time;
161 fixed
162 GetMaxTime() const
164 assert(Ready());
166 return std::max({fixed(0), p[0].time, p[1].time, p[2].time, p[3].time});
169 bool
170 NeedData(fixed t_simulation) const
172 return !Ready() || (p[2].time <= t_simulation + fixed(0.1));
175 private:
176 fixed
177 GetTimeFraction(const fixed time, bool limit_range = true) const
179 assert(Ready());
180 assert(p[2].time > p[1].time);
182 const fixed fraction = (time - p[1].time) / (p[2].time - p[1].time);
184 if (limit_range)
185 return Clamp(fraction, fixed(0), fixed(1));
186 else
187 return fraction;
191 #endif