Develop and Download Open Source Software

Browse CVS Repository

Contents of /autocoast/src/lib/cell.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.10 - (show annotations) (download) (as text)
Fri Dec 3 15:02:11 2004 UTC (19 years, 4 months ago) by tmurakam
Branch: MAIN
CVS Tags: v0_3, HEAD
Changes since 1.9: +5 -1 lines
File MIME type: text/x-c++src
bug fix for west hemisphere.

1 //
2 // AutoCoast: Automatic Coastline scenery generator for Flight Simulator
3 //
4 // Copyright (c) 2004, Takuya Murakami. All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions
8 // are met:
9 //
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
21 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 // cellarea.cc : Cell/Area process
30
31 #include <math.h>
32 #include <list>
33
34 #include "vector.hpp"
35 #include "cell.hpp"
36 #include "bgl.hpp"
37 #include "opt.hpp"
38
39 ///////////////////////////////////////////////////////////////////////
40 // Cell
41
42 Cell::Cell(void)
43 {
44 cellData = NULL;
45 }
46
47 Cell::~Cell()
48 {
49 if (cellData) delete cellData;
50 }
51
52 // Convert coordinates
53 double Cell::x2lon(int u)
54 {
55 double lon = u * 360.0 / 768.0 - 180.0;
56 if (lon < 0) lon += 360.0; // 0 to 360
57
58 return lon;
59 }
60
61 int Cell::lon2x(double lon)
62 {
63 if (lon > 180) lon -= 360; // -180 to 180
64 return (int)((lon + 180.0) * 768.0 / 360.0);
65 }
66
67 double Cell::y2lat(int v)
68 {
69 return 90.0 - v * 180.0 / 512.0;
70 }
71
72 int Cell::lat2y(double lat)
73 {
74 return (int)((90.0 - lat) * 512.0 / 180.0);
75 }
76
77 void Cell::setid(int xx, int yy)
78 {
79 x = xx;
80 y = yy;
81
82 bbox.xmin = x2lon(x);
83 bbox.xmax = x2lon(x+1);
84 if (bbox.xmax == 0.0) bbox.xmax = 360.0;
85
86 bbox.ymax = y2lat(y);
87 bbox.ymin = y2lat(y+1);
88
89 for (int u = 0; u < 32; u++) {
90 for (int v = 0; v < 32; v++) {
91 area[u][v].setid(u, v, bbox);
92 }
93 }
94 }
95
96 bool Cell::Clipping(DataSet *source)
97 {
98 if (cellData) {
99 delete cellData;
100 }
101
102 cellData = source->Clipping(bbox);
103 if (source->isEmpty(bbox)) {
104 return false;
105 }
106
107 for (int u = 0; u < 32; u++) {
108 for (int v = 0; v < 32; v++) {
109 area[u][v].Clipping(cellData);
110 area[u][v].setType();
111 }
112 }
113
114 return true;
115 }
116
117 void Cell::checkFill(LwmDataChunk *chunk, int u, int v, int blocksz)
118 {
119 int uu, vv;
120 int type, firsttype;
121
122 if (area[u][v].mark) return; // already done...
123
124 firsttype = area[u][v].getType(); // initial...
125 if (isLand(firsttype)) {
126 // AreaFill does not work for land area!
127 // We must use land class or fill it with a polygon.
128 return;
129 }
130
131 for (uu = u; uu < u + blocksz; uu++) {
132 for (vv = v; vv < v + blocksz; vv++) {
133 type = area[uu][vv].getType();
134
135 if (isLand(type)) return; // mix!
136 }
137 }
138
139 // okay fill area...
140 chunk->DataAreaFill(blocksz, 0, u, v);
141
142 // set mark
143 for (uu = u; uu < u + blocksz; uu++) {
144 for (vv = v; vv < v + blocksz; vv++) {
145 area[uu][vv].mark = true;
146 }
147 }
148 }
149
150 //
151 // Generate LWM bgl data
152 void Cell::GenLwmBgl(LwmBgl *bgl)
153 {
154 int u, v, blocksz;
155 LwmDataChunk *chunk = (LwmDataChunk *)bgl->NewDataChunk(x, y, bbox);
156
157 for (u = 0; u < 32; u++) {
158 for (v = 0; v < 32; v++) {
159 area[u][v].mark = false;
160 }
161 }
162
163 // First, generate AreaFill for water.
164 for (blocksz = 16; blocksz >= 1; blocksz = blocksz / 2) {
165 for (u = 0; u < 32; u += blocksz) {
166 for (v = 0; v < 32; v += blocksz) {
167 checkFill(chunk, u, v, blocksz);
168 }
169 }
170 }
171
172 // Next, fill all land area.
173 for (u = 0; u < 32; u++) {
174 for (v = 0; v < 32; v++) {
175 if (area[u][v].getType() != T_LAND) continue;
176
177 // near the shoreline??
178 const int K = AcOpts.landWidth;
179 bool match = false;
180 for (int uu = u - K; uu <= u + K; uu++) {
181 for (int vv = v - K; vv <= v + K; vv++) {
182 if (uu < 0 || uu >= 32 ||
183 vv < 0 || vv >= 32) continue;
184
185 int t = area[uu][vv].getType();
186 if (t == T_MIX_WATER || t == T_MIX_LAND) {
187 match = true;
188 break;
189 }
190 }
191 }
192
193 if (match) {
194 // fill this area...
195 area[u][v].FillLand(chunk);
196 }
197 }
198 }
199
200 // Next, draw polygons.
201 for (u = 0; u < 32; u++) {
202 for (v = 0; v < 32; v++) {
203 area[u][v].DrawLwmPolygon(chunk);
204 }
205 }
206 }
207
208 //
209 // Generate VTP bgl data
210 //
211 void Cell::GenVtpBgl(VtpBgl *bgl)
212 {
213 VtpDataChunk *chunk = (VtpDataChunk *)bgl->NewDataChunk(x, y, bbox);
214
215 int level, i;
216 GpcPolygon shorelines;
217
218 // Extract shorelines from all polygons in the cell.
219 for (level = 1; level <= 4; level++) {
220 GpcPolygon *poly = cellData->get(level);
221
222 if (poly->isEmpty() ||
223 poly->isFull(bbox)) continue;
224
225 for (i = 0; i < poly->numVList(); i++) {
226 ExtractShoreline(&shorelines, poly->getVList(i), level);
227 }
228 }
229
230 int n = shorelines.numVList();
231 if (n == 0) {
232 // No shorelines.
233 return;
234 }
235
236 // Mask default VTP shoreline.
237 for (int u = 0; u < 32; u++) {
238 for (int v = 0; v < 32; v++) {
239 chunk->DataArea(u, v, 0, 0); // numTexture=0, autocalc=0
240 }
241 }
242
243
244 // Start drawing polygons
245 chunk->DataArea(x & 0x1f, y & 0x1f, 1, 1); // numTexture=1, autocalc=1
246 chunk->TextureStart(n);
247
248 for (i = 0; i < n; i++) {
249 // Interpolate vertices.
250 // We must need at least one vertex in each LOD13 cell...
251 GpcVertexList *vl = InterPolateVTPPoints(shorelines.getVList(i));
252
253 // Draw polygons
254 int np = vl->numVertices();
255 chunk->PolyStart(np);
256 for (int j = 0; j < np; j++) {
257 double x = (vl->vx(j) - bbox.xmin) / (bbox.xmax - bbox.xmin) *
258 (12240 - 4080) + 4080;
259 double y = (bbox.ymax - vl->vy(j)) / (bbox.ymax - bbox.ymin) *
260 (12240 - 4080) + 4080;
261
262 chunk->WidePoint((int)x, (int)y, (j == 0) ? 1 : 0);
263 if (j == 0) {
264 chunk->WidePointWidth(AcOpts.textureWidth);
265 }
266 }
267
268 delete vl;
269 }
270 }
271
272 //
273 // Extract shorelines
274 //
275 void Cell::ExtractShoreline(GpcPolygon *shorelines, GpcVertexList *vlist, int level)
276 {
277 bool needInvert = false;
278
279 // Fix draw starting point
280 vlist->modifyStartPointFromEdge(bbox);
281
282 // Check drawing order of the line.
283 // Left side of the line will be land, right side will be water.
284 // If not, we set needInvert flag to invert drawing order.
285 if (vlist->isLeftHand()) {
286 if (!isLand(level)) {
287 needInvert = true;
288 }
289 } else {
290 if (isLand(level)) {
291 needInvert = true;
292 }
293 }
294
295 // check drawing
296 int drawStartPoint = -1;
297 int n = vlist->numVertices();
298 int prev, flags = 0;
299 bool allInside = true;
300
301 for (int i = 0; i < n; i++) {
302 prev = flags;
303 flags = bbox.checkEdge(vlist->vx(i), vlist->vy(i));
304 if (flags) allInside = false;
305
306 if (i == 0) continue;
307
308 //fprintf(stderr, (flags) ? "_" : "*");
309
310 // check drawing start point
311 if (drawStartPoint < 0) {
312 // Check if we leaved from previous edge?
313 if ((prev & ~flags) != 0 &&
314 (prev & flags) == 0) {
315 // start drawing.
316 drawStartPoint = i - 1;
317 //fprintf(stderr, "S");
318 }
319 }
320
321 // check drawing end point
322 if (drawStartPoint >= 0 && flags != 0) {
323 // reached to edge.
324 PutShoreLine(shorelines, vlist,
325 drawStartPoint, i, needInvert);
326 drawStartPoint = -1;
327 //fprintf(stderr, "E");
328 }
329 }
330 //fprintf(stderr, "\n");
331
332 // No vertices are on any edge. Draw all lines...
333 if (allInside) {
334 PutShoreLine(shorelines, vlist, 0, n - 1, needInvert, true);
335 }
336
337 shorelines->BuildVertexListFromGpcPolygon();
338 }
339
340 //
341 // Put one shoreline
342 //
343 void Cell::PutShoreLine(GpcPolygon *shorelines, GpcVertexList *vlist,
344 int st, int ed, bool needInvert, bool isLoop)
345 {
346 ASSERT(ed > st);
347
348 int n = ed - st + 1;
349 if (isLoop) n++;
350
351 GpcVertexList *vl = new GpcVertexList(n, NULL);
352
353 gpc_vertex *s;
354 gpc_vertex *d = vl->vertex(0);
355
356 for (int i = 0; i < n ; i++) {
357 if (isLoop && i == n - 1) {
358 s = vlist->vertex(st); // loop
359 } else {
360 s = vlist->vertex(st + i);
361 }
362 *d++ = *s;
363 }
364
365 if (needInvert) {
366 vl->invert();
367 }
368
369 shorelines->AddVertexList(vl, false);
370 }
371
372 // LOD13 conversion
373 inline int x2ax(double x, BoundingBox &bbox)
374 {
375 int xx = (int)((x - bbox.xmin) / (bbox.xmax - bbox.xmin) * 32);
376 if (xx == 32) xx = 31;
377 return xx;
378 }
379
380 inline int y2ay(double y, BoundingBox &bbox)
381 {
382 int yy = (int)((y - bbox.ymin) / (bbox.ymax - bbox.ymin) * 32);
383 if (yy == 32) yy = 31;
384 return yy;
385 }
386
387 //
388 // Interpolate vertices
389 //
390 GpcVertexList *Cell::InterPolateVTPPoints(GpcVertexList *vl)
391 {
392 int i, n;
393 list<gpc_vertex>::iterator iter;
394
395 // Create linked list of vertices.
396 list<gpc_vertex> vlist;
397
398 n = vl->numVertices();
399 for (i = 0; i < n; i++) {
400 ASSERT(bbox.isInbox(vl->vx(i), vl->vy(i)));
401 vlist.push_back(*vl->vertex(i));
402 }
403
404 gpc_vertex v1, v2, vi;
405 int ax1, ay1;
406 int ax2, ay2;
407 int ax3, ay3;
408 int dx, dy;
409
410 // check all sides...
411 iter = vlist.begin();
412 for (;;) {
413 v1 = *iter;
414 iter++;
415 if (iter == vlist.end()) break;
416 v2 = *iter;
417
418 ax1 = x2ax(v1.x, bbox);
419 ay1 = y2ay(v1.y, bbox);
420
421 ax2 = x2ax(v2.x, bbox);
422 ay2 = y2ay(v2.y, bbox);
423
424 // Check if interpolation needed?
425 dx = abs(ax1 - ax2);
426 dy = abs(ay1 - ay2);
427 if ((dx == 0 && dy <= 1) ||
428 (dx <= 1 && dy == 0)) {
429 // no interpolation
430 continue;
431 }
432
433 // We need interpolation.
434 // Find interpolation point from v1 to v2.
435 Vector fv(v1.x, v1.y);
436 Vector dv(v2.x - v1.x, v2.y - v1.y);
437 Vector point;
438
439 double k = 0.5, kd = 0.25;
440 bool tryagain = false;
441 for (;;) {
442 point = fv + dv * k;
443 ax3 = x2ax(point.x, bbox);
444 ay3 = y2ay(point.y, bbox);
445
446 if (ax3 == ax1 && ay3 == ay1) {
447 k += kd;
448 }
449 else if (ax3 == ax2 && ay3 == ay2) {
450 k -= kd;
451 }
452 else {
453 // found!
454 break;
455 }
456
457 kd = kd / 2.0;
458
459 if (kd < 1.0e-10) {
460 // oops! no interpolation point!
461 // dirty hack... slightly move 2nd point...
462 (*iter).y += 2.0e-6;
463 tryagain = true;
464 break;
465 }
466 }
467 if (tryagain) {
468 iter--;
469 continue;
470 }
471
472 vi.x = point.x;
473 vi.y = point.y;
474
475 // Interpolate a point.
476 vlist.insert(iter, vi);
477
478 // Go back to a point before interpolated point.
479 iter--;
480 iter--;
481 }
482
483 // Create VertexList
484 n = vlist.size();
485 GpcVertexList *nvl = new GpcVertexList(n, NULL);
486
487 for (i = 0, iter = vlist.begin(); i < n; i++, iter++) {
488 *(nvl->vertex(i)) = *iter;
489 }
490 ASSERT(iter == vlist.end());
491
492 return nvl;
493 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26