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 #include "Geo/GeoClip.hpp"
31 clip_longitude(const GeoPoint origin
, const GeoPoint pt
, Angle at
)
33 Angle dx
= pt
.longitude
- origin
.longitude
;
34 Angle dy
= pt
.latitude
- origin
.latitude
;
36 Angle ex
= at
- origin
.longitude
;
37 Angle ey
= ex
* (dy
.Native() / dx
.Native());
39 return GeoPoint(at
, origin
.latitude
+ ey
);
44 clip_latitude(const GeoPoint origin
, const GeoPoint pt
, Angle at
)
46 Angle dx
= pt
.longitude
- origin
.longitude
;
47 Angle dy
= pt
.latitude
- origin
.latitude
;
49 Angle ey
= at
- origin
.latitude
;
50 Angle ex
= ey
* (dx
.Native() / dy
.Native());
52 return GeoPoint(origin
.longitude
+ ex
, at
);
56 GeoClip::ClipPoint(const GeoPoint
&origin
, GeoPoint
&pt
) const
58 const Angle zero
= Angle::Zero();
60 if (pt
.longitude
< zero
) {
61 if (origin
.longitude
<= zero
)
64 pt
= clip_longitude(origin
, pt
, zero
);
65 } else if (pt
.longitude
> width
) {
66 if (origin
.longitude
>= width
)
69 pt
= clip_longitude(origin
, pt
, width
);
72 if (pt
.latitude
< GetSouth()) {
73 if (origin
.latitude
<= GetSouth())
76 pt
= clip_latitude(origin
, pt
, GetSouth());
77 } else if (pt
.latitude
> GetNorth()) {
78 if (origin
.latitude
>= GetNorth())
81 pt
= clip_latitude(origin
, pt
, GetNorth());
88 GeoClip::ClipLine(GeoPoint
&a
, GeoPoint
&b
) const
90 GeoPoint a2
= ImportPoint(a
);
91 GeoPoint b2
= ImportPoint(b
);
93 if (!ClipPoint(a2
, b2
) || !ClipPoint(b2
, a2
))
102 ClipVertexLongitude(const Angle west
, const Angle east
,
103 const GeoPoint
&prev
, GeoPoint
&pt
, GeoPoint
&insert
,
104 const GeoPoint
&next
)
106 unsigned num_insert
= 0;
108 if (pt
.longitude
< west
) {
109 if (prev
.longitude
<= west
) {
110 if (next
.longitude
<= west
)
111 /* all three outside, middle one can be deleted */
114 pt
= clip_longitude(next
, pt
, west
);
116 if (next
.longitude
> west
) {
117 /* both neighbours are inside, clip both lines and insert a
119 insert
= clip_longitude(next
, pt
, west
);
123 pt
= clip_longitude(prev
, pt
, west
);
125 } else if (pt
.longitude
> east
) {
126 if (prev
.longitude
>= east
) {
127 if (next
.longitude
>= east
)
128 /* all three outside, middle one can be deleted */
131 pt
= clip_longitude(next
, pt
, east
);
133 if (next
.longitude
< east
) {
134 /* both neighbours are inside, clip both lines and insert a
136 insert
= clip_longitude(next
, pt
, east
);
140 pt
= clip_longitude(prev
, pt
, east
);
144 return 1 + num_insert
;
148 ClipVertex_latitude(const Angle south
, const Angle north
,
149 const GeoPoint
&prev
, GeoPoint
&pt
, GeoPoint
&insert
,
150 const GeoPoint
&next
)
152 unsigned num_insert
= 0;
154 if (pt
.latitude
< south
) {
155 if (prev
.latitude
<= south
) {
156 if (next
.latitude
<= south
)
157 /* all three outside, middle one can be deleted */
160 pt
= clip_latitude(next
, pt
, south
);
162 if (next
.latitude
> south
) {
163 /* both neighbours are inside, clip both lines and insert a
165 insert
= clip_latitude(next
, pt
, south
);
169 pt
= clip_latitude(prev
, pt
, south
);
171 } else if (pt
.latitude
> north
) {
172 if (prev
.latitude
>= north
) {
173 if (next
.latitude
>= north
)
174 /* all three outside, middle one can be deleted */
177 pt
= clip_latitude(next
, pt
, north
);
179 if (next
.latitude
< north
) {
180 /* both neighbours are inside, clip both lines and insert a
182 insert
= clip_latitude(next
, pt
, north
);
186 pt
= clip_latitude(prev
, pt
, north
);
190 return 1 + num_insert
;
194 ClipPolygonLongitude(const Angle west
, const Angle east
, GeoPoint
*dest
,
195 const GeoPoint
*src
, unsigned src_length
)
197 /* this array always holds the current vertex and its two neighbors;
198 it is filled in advance with the last two points, because that
199 avoids range checking inside the loop */
201 three
[0] = src
[src_length
- 2];
202 three
[1] = src
[src_length
- 1];
204 unsigned dest_length
= 0;
205 for (unsigned i
= 0; i
< src_length
; ++i
) {
206 if (i
< src_length
- 1)
209 /* the last vertex may have been removed in the first iteration,
210 so use the first element of the "dest" buffer instead */
212 if (dest_length
== 0)
219 unsigned n
= ClipVertexLongitude(west
, east
,
220 three
[0], three
[1], insert
, three
[2]);
224 /* thee points outside, the middle one can be deleted */
227 /* no change in vertex count, but the current vertex may have
229 dest
[dest_length
++] = three
[1];
233 /* one vertex has been inserted */
234 dest
[dest_length
++] = three
[1];
238 /* backtrack, inspect inserted vertex in the next iteration */
247 ClipPolygonLatitude(const Angle south
, const Angle north
, GeoPoint
*dest
,
248 const GeoPoint
*src
, unsigned src_length
)
250 /* this array always holds the current vertex and its two neighbors;
251 it is filled in advance with the last two points, because that
252 avoids range checking inside the loop */
254 three
[0] = src
[src_length
- 2];
255 three
[1] = src
[src_length
- 1];
257 unsigned dest_length
= 0;
258 for (unsigned i
= 0; i
< src_length
; ++i
) {
259 if (i
< src_length
- 1)
262 /* the last vertex may have been removed in the first iteration,
263 so use the first element of the "dest" buffer instead */
265 if (dest_length
== 0)
272 unsigned n
= ClipVertex_latitude(south
, north
,
273 three
[0], three
[1], insert
, three
[2]);
277 /* thee points outside, the middle one can be deleted */
280 /* no change in vertex count, but the current vertex may have
282 dest
[dest_length
++] = three
[1];
286 /* one vertex has been inserted */
287 dest
[dest_length
++] = three
[1];
291 /* backtrack, inspect inserted vertex in the next iteration */
300 GeoClip::ClipPolygon(GeoPoint
*dest
,
301 const GeoPoint
*src
, unsigned src_length
) const
306 GeoPoint
*imported
= dest
+ src_length
* 2;
307 for (unsigned i
= 0; i
< src_length
; ++i
)
308 imported
[i
] = ImportPoint(src
[i
]);
310 GeoPoint
*first_stage
= dest
+ src_length
;
311 unsigned n
= ClipPolygonLongitude(Angle::Zero(), width
,
312 first_stage
, imported
, src_length
);
316 n
= ClipPolygonLatitude(GetSouth(), GetNorth(), dest
, first_stage
, n
);
320 for (unsigned i
= 0; i
< n
; ++i
)
321 dest
[i
] = ExportPoint(dest
[i
]);