1 /* erode.c - erosion and cresting functions
2 *
3 * Copyright (C) 2001-2005 Patrice St-Gelais
4 * patrstg@users.sourceforge.net
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #include "hf.h"
22 #include "hf_calc.h"
23 #include "erode.h"
24
25 #ifndef MAX_CACHE
26 #define MAX_CACHE 32768
27 #endif
28
29 static gdouble **cache;
30 static gboolean if_cache_init=FALSE;
31
rain_erosion_struct_new(gint drops,gint threshold,gint strength,gint hardness,gboolean progressive_refresh,gint interval,gboolean old_algorithm)32 rain_erosion_struct *rain_erosion_struct_new (gint drops, gint threshold, gint strength, gint hardness, gboolean progressive_refresh, gint interval, gboolean old_algorithm) {
33 rain_erosion_struct *res;
34 res = (rain_erosion_struct *) x_malloc(sizeof(rain_erosion_struct), "rain_erosion_struct");
35 res->drops = drops;
36 res->threshold = threshold;
37 res->strength = MIN(100,MAX(strength,0));
38 res->hardness = MIN(100,MAX(hardness,25));
39 res->refresh = progressive_refresh;
40 res->interval = interval;
41 res->old_algorithm = old_algorithm;
42 res->gener_frames = FALSE;
43
44 return res;
45 }
46
rain_erosion_struct_free(rain_erosion_struct * res)47 void rain_erosion_struct_free (rain_erosion_struct *res) {
48 if (res)
49 x_free(res);
50 }
51
gravity_struct_new(gint steps,gint slope_threshold)52 gravity_struct *gravity_struct_new (gint steps, gint slope_threshold) {
53 gravity_struct *ges;
54 ges = (gravity_struct *) x_malloc(sizeof(gravity_struct), "gravity_struct");
55 ges->steps = steps;
56 ges->threshold = slope_threshold;
57 return ges;
58 }
59
gravity_struct_free(gravity_struct * ges)60 void gravity_struct_free (gravity_struct *ges){
61 if (ges)
62 x_free(ges);
63 }
64
oriented_gravity_struct_new(gint steps,gint threshold,gint direction)65 oriented_gravity_struct *oriented_gravity_struct_new (gint steps, gint threshold, gint direction) {
66 oriented_gravity_struct *ogs;
67 ogs = (oriented_gravity_struct *) x_malloc(sizeof(oriented_gravity_struct), "oriented_gravity_struct");
68 ogs->steps = steps;
69 ogs->threshold = threshold;
70 ogs->direction = direction;
71 return ogs;
72 }
73
oriented_gravity_struct_free(oriented_gravity_struct * ogs)74 void oriented_gravity_struct_free (oriented_gravity_struct *ogs) {
75 if (ogs)
76 x_free(ogs);
77 }
78
whimsical_erosion_struct_new(gint radius,gint smooth_ribs,gboolean auto_contrast)79 whimsical_erosion_struct *whimsical_erosion_struct_new (gint radius, gint smooth_ribs, gboolean auto_contrast) {
80 whimsical_erosion_struct *wes;
81 wes = (whimsical_erosion_struct *) x_malloc(sizeof(whimsical_erosion_struct), "whimsical_erosion_struct");
82 wes->radius = radius;
83 wes->smooth_ribs = smooth_ribs;
84 wes->auto_contrast = auto_contrast;
85 return wes;
86 }
87
whimsical_erosion_struct_free(whimsical_erosion_struct * wes)88 void whimsical_erosion_struct_free (whimsical_erosion_struct *wes){
89 if (wes)
90 x_free(wes);
91 }
92
craters_erosion_struct_new(gint qty,gint display_interval,gint peak_threshold,gint slope_threshold)93 craters_erosion_struct *craters_erosion_struct_new (gint qty, gint display_interval, gint peak_threshold, gint slope_threshold) {
94 craters_erosion_struct *ces;
95 ces = (craters_erosion_struct *) x_malloc(sizeof(craters_erosion_struct), "craters_erosion_struct");
96 ces->qty = qty;
97 ces->display_interval = display_interval;
98 ces->peak_threshold = peak_threshold;
99 ces->slope_threshold = slope_threshold;
100 ces->crater_str = crater_struct_new();
101 return ces;
102 }
103
craters_erosion_struct_free(craters_erosion_struct * ces)104 void craters_erosion_struct_free (craters_erosion_struct *ces) {
105 if (!ces)
106 return;
107 if (ces->crater_str)
108 crater_struct_free(ces->crater_str);
109 x_free(ces);
110 }
111
hf_eroded_ribs(hf_type * hf_in,hf_type * hf_out,gint max)112 void hf_eroded_ribs (hf_type *hf_in, hf_type *hf_out, gint max) {
113 // Build a "ribbed" (eroded) template by taking the minimum
114 // absolute value of the difference between each pixel and its neighborus
115 // Neighbours are numbered from 1 to 8, clockwise, 1 being (1,0)
116 // The default for this version of the program is to wrap
117 static gint z1, z2, z3, z4, z5, z6, z7, z8;
118 hf_type value;
119 static gint x,y, i;
120 for (y=0; y<max; y++)
121 for (x=0; x<max; x++) {
122 i = VECTORIZE(x,y,max);
123 value = *(hf_in + i);
124 z1 = *(hf_in+VECTORIZE(WRAP2(x+1,max),y,max)) ;
125 z2 = *(hf_in+VECTORIZE(WRAP2(x+1,max),
126 WRAP2(y+1,max),max)) ;
127 z3 = *(hf_in+VECTORIZE(x,WRAP2(y+1,max),max));
128 z4 = *(hf_in+VECTORIZE(WRAP2(x-1,max),WRAP2(y+1,max),max));
129 z5 = *(hf_in+VECTORIZE(WRAP2(x-1,max),y,max)) ;
130 z6 = *(hf_in+VECTORIZE(WRAP2(x-1,max),
131 WRAP2(y-1,max),max)) ;
132 z7 = *(hf_in+VECTORIZE(x,WRAP2(y-1,max),max)) ;
133 z8 = *(hf_in+VECTORIZE(WRAP2(x+1,max),
134 WRAP2(y-1,max),max)) ;
135
136 // Absolute minimum (negative of)
137 z1 = ABS(z1-value);
138 z2 = ABS(z2-value);
139 z3 = ABS(z3-value);
140 z4 = ABS(z4-value);
141 z5 = ABS(z5-value);
142 z6 = ABS(z6-value);
143 z7 = ABS(z7-value);
144 z8 = ABS(z8-value);
145
146 *(hf_out + i) = ~ (hf_type) MIN(z1,MIN(z2,MIN(z3,MIN(z4,MIN(z5,MIN(z6,MIN(z7,z8))))))) ;
147
148 // if (!(i%512)) {
149 // printf("*(hf_out+i): %d; z1: %d, z2: %d, z3: %d, z4: %d, z5: %d, z6: %d, z7: %d, z8: %d\n",*(hf_out+i), z1, z2, z3, z4, z5, z6, z7, z8);
150 // }
151 }
152 }
153
hf_oriented_relax(hf_struct_type * hf,gint steps,gint max_slope,gint direction)154 void hf_oriented_relax (hf_struct_type *hf, gint steps, gint max_slope, gint direction) {
155 // Oriented gravity relaxation (for wind functions)
156
157 gint v1, v2, i, slope, x, y, iprec, step;
158
159 // Direction is one of NORTH (ymax to 0), SOUTH (0 to ymax), WEST (xmax to 0), EAST (0 to xmax)
160 // Note: spreading the values with a 3x3 kernel gives no significant visible difference
161 slope = iget_absolute_slope(max_slope,hf->max_x);
162 for (step=0; step<steps; step++) {
163 for (y=0; y<hf->max_y; y++) {
164 for (x=0; x<hf->max_x; x++) {
165 switch (direction) {
166 case NORTH: // For N and S, swap x & y
167 i = VECTORIZE(x,hf->max_x-y-1,hf->max_x);
168 iprec = VECTORIZE (x, WRAP2(hf->max_x-y,hf->max_x), hf->max_x);
169 break;
170 case SOUTH:
171 i = VECTORIZE(x,y,hf->max_x);
172 iprec = VECTORIZE ( x, WRAP2(y-1,hf->max_x), hf->max_x);
173 break;
174 case WEST:
175 i = VECTORIZE(hf->max_x-x-1,y,hf->max_x);
176 iprec = VECTORIZE ( WRAP2(hf->max_x-x,hf->max_x), y, hf->max_x);
177 break;
178 default: // East
179 i = VECTORIZE(x,y,hf->max_x);
180 iprec = VECTORIZE ( WRAP2(x-1,hf->max_x), y, hf->max_x);
181 }
182
183 v1 = *(hf->hf_buf+iprec);
184 v2 = ((gint) *(hf->hf_buf+i)) + slope;
185 if ( v1 > v2 ) {
186
187 *(hf->hf_buf+iprec) -= (v1-v2) /2;
188 *(hf->hf_buf+i) += (v1-v2) / 2 ;
189
190 }
191 }
192 }
193 }
194 }
195
relax_hex(hf_type * hf,gint max_x,gint max_y,gint slope_threshold,gint wrap)196 gboolean relax_hex (hf_type *hf, gint max_x, gint max_y, gint slope_threshold, gint wrap) {
197
198 // Gravity relaxation, on an hexagonally sampled buffer
199 // Variation over cresting, more natural-like (I hope!)
200 // Written 2005-02 for sand / wind processes
201 // hf: buffer to transform
202 // x,y: pixel to relax
203 // max_x, max_y: size of the buffer (so it could work with non-square buffers!)
204 // slope_threshold: maximum allowed slope, in absolute HF units (not degrees!)
205 // max_steps: don't do more than this number of steps
206 // The function can stop before if all slopes are lowver than max_slope
207 // even, shift_right: hexagonal sampling parameters (see comments in other functions)
208 // Returns: TRUE is relaxation done, FALSE if no relaxation to do
209 //
210 // 2006-11-08 Modified for randomizing the hexagonal approximation
211 //
212
213 static gint v0[6] = {0,0,0,0,0,0};
214 static gint x,y,v[6],z1, z2, z3, z4, z5, z6, i, ii, ninf, shift, sumdif, axis, even, xx, yy;
215 long int value;
216 gboolean test, found=FALSE;
217
218 // The beginning is the same as find_all_neighbours
219 // Then we take all the neighbour pixels inferior to the threshold
220 // We average the difference between these pixels and the threshold
221 // Then the current pixel is decreased and the "soil" is evenly
222 // spread on the selected pixels
223
224 even = TRUE;
225 axis = H_AXIS;
226 for (x=0; x<max_x; x++) {
227 for (y=0; y<max_y; y++) {
228 ninf = 0;
229 sumdif = 0;
230 // 2006-11-08: better results with even and axis fixed
231 even = rand()%2;
232 if (rand()%2)
233 axis = V_AXIS;
234 else
235 axis = H_AXIS;
236
237 memcpy(v,v0,6*sizeof(gint));
238 value = *(hf+VECTORIZE(x,y,max_x)) - slope_threshold ;
239 // test = y & (gint) 1; // test = TRUE if value is odd
240 if (axis==H_AXIS)
241 test = y & (gint) 1; // test = TRUE if value is odd
242 else
243 test = x & (gint) 1; // test = TRUE if value is odd
244
245 if ( (test && even) || ((!test) && (!even)) ) // XOR
246 shift = 1;
247 else
248 shift = 0;
249
250 if (axis==H_AXIS) {
251 xx = x+1;
252 yy = y;
253 }
254 else {
255 xx = x;
256 yy = y+1;
257 }
258 if (wrap)
259 ii=VECTORIZE(WRAP2(xx,max_x),WRAP2(yy,max_y), max_x);
260 else
261 ii=VECTORIZE(MIN(xx,max_x-1),MIN(yy,max_y-1), max_x);
262
263 z1 = *(hf+ii);
264 if (z1<value) {
265 if (wrap || ( (x+1)<max_x ) ) {
266 v[ninf] = ii;
267 ninf++;
268 sumdif += value-z1;
269 }
270 }
271
272 if (axis==H_AXIS) {
273 xx = x+shift;
274 yy = y+1;
275 }
276 else {
277 xx = x+1;
278 yy = y+shift;
279 }
280
281 if (wrap)
282 ii=VECTORIZE(WRAP2(xx,max_x), WRAP2(yy,max_y),max_x) ;
283 else
284 ii=VECTORIZE(MIN(xx,max_x-1), MIN(yy,max_y-1),max_x) ;
285
286 z2 = *(hf+ii);
287 if (z2<value) {
288 if (wrap || (((x+shift)<max_x) && ((y+1)<max_y)) ) {
289 v[ninf] = ii;
290 ninf++;
291 sumdif += value-z2;
292 }
293 }
294
295 if (axis==H_AXIS) {
296 xx = x-1+shift;
297 yy = y+1;
298 }
299 else {
300 xx = x+1;
301 yy = y-1+shift;
302 }
303
304 if (wrap)
305 ii =VECTORIZE( WRAP2(xx,max_x), WRAP2(yy,max_y), max_x) ;
306 else
307 ii = VECTORIZE(MAX(0,xx),MIN(MAX(0,yy),max_y-1),max_x) ;
308
309 z3 = *(hf+ii) ;
310 if (z3<value) {
311 if (wrap || (((x+shift)>0) && ((y+1)<max_y)) ) {
312 v[ninf] = ii;
313 ninf++;
314 sumdif += value-z3;
315 }
316 }
317
318 if (axis==H_AXIS) {
319 xx = x-1;
320 yy = y;
321 }
322 else {
323 xx = x;
324 yy = y-1;
325 }
326
327 if (wrap)
328 ii=VECTORIZE(WRAP2(xx,max_x), WRAP2(yy,max_x) , max_x) ;
329 else
330 ii=VECTORIZE(MAX(xx,0), MAX(yy,0), max_x) ;
331
332 z4 = *(hf+ii);
333 if (z4<value) {
334 if (wrap || (x>0)) {
335 v[ninf] = ii;
336 ninf++;
337 sumdif += value-z4;
338 }
339 }
340
341
342 if (axis==H_AXIS) {
343 xx = x-1+shift;
344 yy = y-1;
345 }
346 else {
347 xx = x-1;
348 yy = y-1+shift;
349 }
350 if (wrap)
351 ii=VECTORIZE(WRAP2(xx,max_x),
352 WRAP2(yy,max_x),max_x) ;
353 else
354 ii=VECTORIZE(MAX(xx,0), MAX(yy,0),max_x) ;
355
356 z5 = *(hf+ii) ;
357 if (z5<value) {
358 if (wrap || ((y>0) && ((x+shift)>0)) ) {
359 v[ninf] = ii;
360 ninf++;
361 sumdif += value-z5;
362 }
363 }
364
365 if (axis==H_AXIS) {
366 xx = x+shift;
367 yy = y-1;
368 }
369 else {
370 xx = x-1;
371 yy = y+shift;
372 }
373 if (wrap)
374 ii=VECTORIZE(WRAP2(xx,max_x),WRAP2(yy,max_y),max_x) ;
375 else
376 ii=VECTORIZE(MIN(MAX(0,xx),max_x-1),MAX(yy,0),max_x) ;
377
378 z6 = *(hf+ii);
379 if (z6<value) {
380 if (wrap || ((y>0) && ((x+shift)<max_x)) ) {
381 v[ninf] = ii;
382 ninf++;
383 sumdif += value-z6;
384 }
385 }
386
387 if (ninf)
388 found = TRUE;
389 else
390 continue;
391
392 // if (y==255)
393 // printf("(X,Y): (%d,%d); ninf: %d; sl_max: %d; value: %d; sumdif: %d; sd/ninf+1: %d; sd/ninf*ninf+1: %d\n",x,y,ninf,slope_threshold, value, sumdif, sumdif/(ninf+1), sumdif / (ninf*(ninf+1)) );
394
395 *(hf+VECTORIZE(x,y,max_x)) -= sumdif / (ninf+1);
396
397 sumdif = sumdif / (ninf*(ninf+1));
398
399 for (i=0; i<ninf; i++) {
400 *(hf+v[i]) += sumdif;
401 }
402
403
404 } // Y loop
405
406 } // X loop
407
408 return found;
409 }
410
hf_relax_hex(hf_struct_type * hf,gint max_steps,gint max_slope)411 void hf_relax_hex (hf_struct_type *hf, gint max_steps, gint max_slope) {
412
413 // Wrapper for relax_hex - gravity erosion
414
415 gint steps=0, slope;
416
417 slope = iget_absolute_slope(max_slope,hf->max_x);
418
419 for (steps=0; steps<max_steps; steps++) {
420 // printf("******************** STEP %d **********************\n",steps);
421 if (!relax_hex (hf->hf_buf, hf->max_x, hf->max_y, slope, (hf->if_tiles==NULL) ? TRUE : *hf->if_tiles))
422 break;
423 }
424
425 // printf("Steps: %d / %d\n",steps, max_steps);
426
427 }
428
find_all_neighbours_hex(gint x,gint y,gint * newx,gint * newy,gint max,hf_type * hf,gint threshold)429 gboolean find_all_neighbours_hex( gint x, gint y, gint *newx, gint *newy,
430 gint max, hf_type *hf, gint threshold) {
431 // Find all the inferior neighbours of (x,y) in hf
432 // Randomly select one of the neighbours,
433 // given its height difference with the minimum is < to threshold
434 // Returns the result in newx and newy
435 // If (x,y) is a minimum, returns FALSE
436 // This version emulates an hexagonal symmetry (six neighbours)
437 // We need to know if even or odd rows have been shifted (even=TRUE)
438 // and if they have been shifted right or left
439 // Neighbours are counted clockwise from 1 to 6, 1 being (1,0)
440 // 2, 3, 5 and 6 are being shifted on x, depending on "even"
441 //
442 // 5 | 6
443 // 4 | 0 | 1
444 // 3 | 2
445 //
446 // 2006.11.07: when axis is V_AXIS, assume that Y is shifted instead of X
447 // Axis and even/ood shift are randomized, for some kind of antialiasing
448 // This is a better replacement of the preceding simili-hexagonal sampling
449 //
450 static gint v[6],z1, z2, z3, z4, z5, z6, i, ii, nx, ny, ninf, ok, shift;
451 long int value;
452 long int lower= (long int) 0xFFFF;
453 gint even, axis;
454 gboolean test;
455 ninf = 0;
456 ok = 0;
457 value = *(hf+VECTORIZE(x,y,max)) ;
458 if (rand()%2)
459 axis = V_AXIS;
460 else
461 axis = H_AXIS;
462 even = rand()%2; // TRUE or FALSE
463 if (axis==H_AXIS)
464 test = y & (gint) 1; // test = TRUE if value is odd
465 else
466 test = x & (gint) 1; // test = TRUE if value is odd
467 if ( (test && even) || ((!test) && (!even)) ) // XOR
468 shift = 1;
469 else
470 shift = 0;
471
472 if (axis==H_AXIS)
473 ii=VECTORIZE(WRAP2(x+1,max),y,max);
474 else
475 ii=VECTORIZE(x,WRAP2(y+1,max),max);
476 z1 = *(hf+ii);
477 if (z1<value) {
478 v[ninf] = ii;
479 ninf++;
480 }
481 lower = z1;
482
483 if (axis==H_AXIS) {
484 nx = WRAP2(x+shift,max);
485 ny = WRAP2(y+1,max);
486 }
487 else {
488 nx = WRAP2(x+1,max);
489 ny = WRAP2(y+shift,max);
490 }
491 ii=VECTORIZE(nx, ny,max) ;
492 z2 = *(hf+ii);
493 if (z2<value) {
494 v[ninf] = ii;
495 ninf++;
496 }
497 if (z2<z1)
498 lower = z2;
499
500 if (axis==H_AXIS) {
501 nx = WRAP2(x-1+shift,max);
502 ny = WRAP2(y+1,max) ;
503 }
504 else {
505 nx = WRAP2(x+1,max);
506 ny = WRAP2(y-1+shift,max) ;
507 }
508 ii =VECTORIZE(nx,ny,max) ;
509 z3 = *(hf+ii) ;
510 if (z3<value) {
511 v[ninf] = ii;
512 ninf++;
513 }
514 if (z3<lower)
515 lower = z3;
516
517
518 if (axis==H_AXIS) {
519 nx = WRAP2(x-1,max);
520 ii = VECTORIZE(nx,y,max) ;
521 }
522 else {
523 ny = WRAP2(y-1,max);
524 ii = VECTORIZE(x,ny,max) ;
525 }
526 z4 = *(hf+ii);
527 if (z4<value) {
528 v[ninf] = ii;
529 ninf++;
530 }
531 if (z4<lower)
532 lower = z4;
533
534 if (axis==H_AXIS) {
535 nx = WRAP2(x-1+shift,max) ;
536 ny = WRAP2(y-1,max) ;
537 }
538 else {
539 nx = WRAP2(x-1,max) ;
540 ny = WRAP2(y-1+shift,max) ;
541 }
542 ii =VECTORIZE(nx,ny,max) ;
543 z5 = *(hf+ii) ;
544 if (z5<value) {
545 v[ninf] = ii;
546 ninf++;
547 }
548 if (z5<lower)
549 lower = z5;
550
551 if (axis==H_AXIS) {
552 nx = WRAP2(x+shift,max);
553 ny = WRAP2(y-1,max);
554 }
555 else {
556 nx = WRAP2(x-1,max);
557 ny = WRAP2(y+shift,max);
558 }
559 ii = VECTORIZE(nx, ny,max) ;
560 z6 = *(hf+ii);
561 if (z6<value) {
562 v[ninf] = ii;
563 ninf++;
564 }
565 if (z6<lower)
566 lower = z6;
567
568 // printf("(X,Y): (%d,%d); ninf: %d; lower: %u; threshold: %d; value: %d; ",x,y,ninf, lower, threshold, value);
569 if ( (lower+threshold) < value) {
570 // Find all the pixels not farther away than "threshold" than the lower one
571 for (i=0; i<ninf; i++) {
572 if ((*(hf+v[i])-threshold)<=lower) {
573 v[ok] = v[i];
574 ok ++;
575 }
576 }
577 // printf("ok: %d; ",ok);
578 ii = v[rand()%ok];
579 // printf("ii: %d; ",ii);
580 *newx = ii%max;
581 *newy = (gint) (ii / max);
582 // printf("(NEWX,NEWY) = (%d,%d) = (%d,%d)\n", ii%max,(gint) ii/max,*newx,*newy);
583 return TRUE;
584 }
585 else {
586 // printf("Returning FALSE\n");
587 return FALSE;
588 }
589 }
590
gflow_add_part(hf_type remainder,hf_type from_value,gint tox,gint toy,hf_type * hf,gint max,gboolean wrap)591 void gflow_add_part(hf_type remainder, hf_type from_value, gint tox, gint toy, hf_type *hf, gint max, gboolean wrap) {
592 // Flow some part of the H difference between (x,y) and (tox,toy)
593 // from (x,y) to (tox,toy)
594 // Float (double) version
595 // Define a 3x3 matrix - proportion of the flowing chunk to displace
596 static gdouble matrix[3][3]={{1.0,2.0,1.0},{2.0,4.0,2.0},{1.0,2.0,1.0}};
597 static gdouble msum = 16.0;
598 // static gdouble matrix[3][3]={0.0,1.0,0.0,1.0,2.0,1.0,0.0,1.0,0.0};
599 // static gdouble msum = 6.0;
600 // static gdouble matrix[3][3]={1.0,1.0,1.0,1.0,4.0,1.0,1.0,1.0,1.0};
601 // static gdouble msum = 12.0;
602
603 gint i, m, n, xi, yi, qtytot=0;
604 gdouble qty, ratio;
605 hf_type to_value;
606
607 if (!remainder)
608 return;
609
610 ratio = remainder / msum;
611
612 // if (x==64)
613 // printf("FROM_VALUE: %d; TO_VALUE: %d; qtytot: %d\n",from_value, *(hf+VECTORIZE(tox,toy,max)),qtytot);
614 for (m=0; m<3; m++)
615 for (n=0; n<3; n++) {
616 if (wrap)
617 i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
618 else {
619 xi = tox-1+n;
620 yi = toy-1+m;
621 if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
622 continue;
623 else
624 i = VECTORIZE(xi,yi,max);
625 }
626 qty = ((gdouble) remainder) * matrix[m][n] * ratio;
627 // Flow up to the point where the target value is equal to
628 // the source value
629 // Keep the remainder for the target center
630 to_value = *(hf+i);
631 if (from_value>to_value) {
632 *(hf+i) = (hf_type) MIN(from_value,MAX(0,(gint) to_value + (gint) qty));
633 qtytot -= (*(hf+i) - to_value);
634 }
635 else
636 qtytot -= (gint) qty;
637 }
638
639 if (qtytot>0) {
640 // printf("SOLDE QTYTOT (%d, %d): %d; NCHUNK: %d\n",x,y,qtytot, nchunk);
641 *(hf+VECTORIZE(tox,toy,max)) -= qtytot;
642 }
643
644 }
645
flow(gint x,gint y,gint tox,gint toy,hf_type * hf,gint max,gint hardness,gint strength,gboolean wrap)646 void flow(gint x, gint y, gint tox, gint toy, hf_type *hf, gint max, gint hardness, gint strength, gboolean wrap) {
647 // Flow some part of the H difference between (x,y) and (tox,toy)
648 // from (x,y) to (tox,toy)
649 // Define a 3x3 matrix - proportion of the flowing chunk to displace
650 // static gint matrix[3][3]={1,1,1,1,4,1,1,1,1};
651 // static gint matrix[3][3]={0,1,0,1,2,1,0,1,0};
652 static gint matrix[3][3]={{1,2,1},{1,4,1},{1,2,1}};
653 gint i, m, n, qty, xi, yi, qtytot=0;
654 hf_type nchunk, to_value, from_value, value;
655 gdouble ratio;
656
657 // nchunk == soil (delta) to move
658 nchunk = *(hf+VECTORIZE(x,y,max)) - *(hf+VECTORIZE(tox,toy,max));
659 // nchunk = nchunk / 12;
660 nchunk = ((hf_type) ((((gfloat) nchunk) * ((gfloat) strength)) / 100.0)) >> 4;
661 // if (x==64)
662 // printf("NCHUNK (%d,%d): %d\n",x,y,nchunk);
663 ratio = ((gdouble) hardness) / 100.0;
664 // Remove soil at (x,y)
665 for (m=0; m<3; m++)
666 for (n=0; n<3; n++) {
667 if (wrap)
668 i = VECTORIZE(WRAP2(x-1+n,max),WRAP2(y-1+m,max),max);
669 else {
670 xi = x-1+n;
671 yi = y-1+m;
672 if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
673 continue;
674 else
675 i = VECTORIZE(xi,yi,max);
676 }
677 qty = nchunk * matrix[m][n];
678 qtytot += qty;
679 *(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) - qty));
680 }
681 // Add soil at (tox,toy)
682 from_value = *(hf+VECTORIZE(x,y,max));
683 // if (x==64)
684 // printf("FROM_VALUE: %d; TO_VALUE: %d; qtytot: %d\n",from_value, *(hf+VECTORIZE(tox,toy,max)),qtytot);
685 for (m=0; m<3; m++)
686 for (n=0; n<3; n++) {
687 if (wrap)
688 i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
689 else {
690 xi = tox-1+n;
691 yi = toy-1+m;
692 if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
693 continue;
694 else
695 i = VECTORIZE(xi,yi,max);
696 }
697 qty = nchunk * matrix[m][n];
698 // Flow up to the point where the target value is equal to
699 // the source value
700 // Keep the remainder for the target center
701 to_value = *(hf+i);
702 if (from_value>to_value) {
703 *(hf+i) = (hf_type) MIN(from_value,MAX(0,(gint) to_value + qty));
704 qtytot -= (*(hf+i) - to_value);
705 }
706 else
707 qtytot -= qty;
708 }
709
710 if (qtytot>0) {
711 // printf("SOLDE QTYTOT (%d, %d): %d; NCHUNK: %d\n",x,y,qtytot, nchunk);
712 value = (hf_type) (((gdouble) qtytot) * ratio);
713 *(hf+VECTORIZE(tox,toy,max)) -= value;
714 gflow_add_part((hf_type) qtytot - value, from_value, tox, toy, hf, max, wrap);
715 }
716
717 }
718
hf_rain_erosion_hex(hf_struct_type * hf,rain_erosion_struct * res,gpointer (* display_function)(gpointer),gpointer display_data)719 void hf_rain_erosion_hex (hf_struct_type *hf, rain_erosion_struct *res, gpointer (*display_function) (gpointer), gpointer display_data) {
720 // Simple iterative erosion
721 // using hexagonal sampling for a more natural looking result
722 // We generate random drops and follow their path
723 // We don't flow a drop when the slope is more than 2 power threshold
724 // Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
725 // Not extensively tested when the HF doesn't wrap
726
727 static gint x,y, ii, s, threshold, nextx, nexty, steps;
728 gboolean tiling;
729
730 // threshold is the future chunk... it must be at least 16, because the center
731 // of the 3x3 averaging matrix == 4 and we divide the chunk by 16 before applying it
732 // threshold = 15 + (gint) pow(2.0,(double) thresh);
733 threshold = MAX(16,iget_absolute_slope(res->threshold,hf->max_x));
734 // printf("RAIN: Threshold (slope): %d = %d\n",slope_threshold,threshold);
735 // In the 1st version, drops were given as an exponent
736 // We could fallback to this in the future...
737 // drops = (long int) pow(2.0,(gdouble) dr_log);
738 if (hf->if_tiles)
739 tiling = *hf->if_tiles;
740 else
741 tiling = TRUE;
742
743 if (!hf->tmp_buf)
744 hf_backup(hf);
745 // printf("RAIN EROSION, DROPS: %d; THRESHOLD: %d\n", drops, threshold);
746 for (s=0; s<res->drops; s++) {
747
748 x = rand()%hf->max_x;
749 y = rand()%hf->max_y;
750 // Make the (x,y) drop flow until it encounters a minimum
751 steps = 0;
752 // printf("********** DROP: %u; (x,y): (%d,%d)\n",s,x,y);
753 while (find_all_neighbours_hex(x,y,&nextx,&nexty,
754 hf->max_x,hf->hf_buf,threshold)) {
755 if (!tiling)
756 if ( (x==0) || (y==0) ||
757 (x==(hf->max_x-1)) ||
758 (y==(hf->max_y-1)) )
759 break;
760 flow(x,y,nextx,nexty,hf->hf_buf,hf->max_x, res->hardness, res->strength, tiling);
761 ii = VECTORIZE(nextx,nexty,hf->max_x);
762 y = nexty;
763 x = nextx;
764 steps++;
765 if (steps>hf->max_x)
766 break;
767 }
768 if (res->refresh && res->interval)
769 if ((!(s%res->interval)) && display_function && display_data)
770 (*display_function) (display_data);
771 }
772
773 }
774
find_all_neighbours_hex_old(gint x,gint y,gint * newx,gint * newy,gint max,hf_type * hf,gint threshold,gboolean even,gboolean shift_right)775 gboolean find_all_neighbours_hex_old( gint x, gint y, gint *newx, gint *newy,
776 gint max, hf_type *hf, gint threshold,
777 gboolean even, gboolean shift_right) {
778 // Find all the inferior neighbours of (x,y) in hf
779 // Randomly select one of the neighbours,
780 // given its height difference with the minimum is < to threshold
781 // Returns the result in newx and newy
782 // If (x,y) is a minimum, returns FALSE
783 // This version works on an hexagonally samplec HF (six neighbours)
784 // We need to know if even or odd rows have been shifted (even=TRUE)
785 // and if they have been shifted right or left
786 // Neighbours are counted clockwise from 1 to 6, 1 being (1,0)
787 // 2, 3, 5 and 6 are being shifted on x, depending on "even" and "shift_right"
788 //
789 // 5 | 6
790 // 4 | 0 | 1
791 // 3 | 2
792 //
793 static gint v[6],z1, z2, z3, z4, z5, z6, i, ii, nx, ny, ninf, ok, shift;
794 long int value;
795 long int lower= (long int) 0xFFFF;
796 gboolean test;
797 ninf = 0;
798 ok = 0;
799 value = *(hf+VECTORIZE(x,y,max)) ;
800
801 test = y & (gint) 1; // test = TRUE if value is odd
802 if ( (test && even) || ((!test) && (!even)) ) // XOR
803 shift = 1;
804 else
805 shift = 0;
806
807 ii=VECTORIZE(WRAP2(x+1,max),y,max);
808 z1 = *(hf+ii);
809 if (z1<value) {
810 v[ninf] = ii;
811 ninf++;
812 }
813 lower = z1;
814
815 nx = WRAP2(x+shift,max);
816 ny = WRAP2(y+1,max);
817 ii=VECTORIZE(nx, ny,max) ;
818 z2 = *(hf+ii);
819 if (z2<value) {
820 v[ninf] = ii;
821 ninf++;
822 }
823 if (z2<z1)
824 lower = z2;
825
826 nx = WRAP2(x-1+shift,max);
827 ny = WRAP2(y+1,max) ;
828 ii =VECTORIZE(nx,ny,max) ;
829 z3 = *(hf+ii) ;
830 if (z3<value) {
831 v[ninf] = ii;
832 ninf++;
833 }
834 if (z3<lower)
835 lower = z3;
836
837 nx = WRAP2(x-1,max);
838 ii = VECTORIZE(nx,y,max) ;
839 z4 = *(hf+ii);
840 if (z4<value) {
841 v[ninf] = ii;
842 ninf++;
843 }
844 if (z4<lower)
845 lower = z4;
846
847 nx = WRAP2(x-1+shift,max) ;
848 ny = WRAP2(y-1,max) ;
849 ii =VECTORIZE(nx,ny,max) ;
850 z5 = *(hf+ii) ;
851 if (z5<value) {
852 v[ninf] = ii;
853 ninf++;
854 }
855 if (z5<lower)
856 lower = z5;
857
858 nx = WRAP2(x+shift,max);
859 ny = WRAP2(y-1,max);
860 ii = VECTORIZE(nx, ny,max) ;
861 z6 = *(hf+ii);
862 if (z6<value) {
863 v[ninf] = ii;
864 ninf++;
865 }
866 if (z6<lower)
867 lower = z6;
868
869 if ( (lower+threshold) < value) {
870 // Find all the pixels not farther away than "threshold" than the lower one
871 for (i=0; i<ninf; i++) {
872 if ((*(hf+v[i])-threshold)<=lower) {
873 v[ok] = v[i];
874 ok ++;
875 }
876 }
877 ii = v[rand()%ok];
878 *newx = ii%max;
879 *newy = (gint) (ii / max);
880 return TRUE;
881 }
882 else {
883 return FALSE;
884 }
885 }
886
flow_old(gint x,gint y,gint tox,gint toy,hf_type * hf,gint max,gboolean wrap)887 void flow_old(gint x, gint y, gint tox, gint toy, hf_type *hf, gint max, gboolean wrap) {
888 // Flow a quarter of the H difference between (x,y) and (tox,toy)
889 // from (x,y) to (tox,toy)
890 // Define a 3x3 matrix - proportion of the flowing chunk to displace
891 static gint matrix[3][3]={ {1,2,1}, {2,4,2}, {1,2,1} };
892 gint i, m, n, qty, xi, yi;
893 hf_type nchunk;
894
895 nchunk = *(hf+VECTORIZE(x,y,max)) - *(hf+VECTORIZE(tox,toy,max));
896 nchunk = nchunk >> 2;
897 // nchunk = nchunk >> 4;
898 // Remove soil at (x,y)
899 for (m=0; m<3; m++)
900 for (n=0; n<3; n++) {
901 if (wrap)
902 i = VECTORIZE(WRAP2(x-1+n,max),WRAP2(y-1+m,max),max);
903 else {
904 xi = x-1+n;
905 yi = y-1+m;
906 if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
907 continue;
908 else
909 i = VECTORIZE(xi,yi,max);
910 }
911 qty = nchunk * matrix[m][n];
912 *(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) - qty));
913 }
914 // Add soil at (tox,toy)
915 for (m=0; m<3; m++)
916 for (n=0; n<3; n++) {
917 if (wrap)
918 i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
919 else {
920 xi = tox-1+n;
921 yi = toy-1+m;
922 if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
923 continue;
924 else
925 i = VECTORIZE(xi,yi,max);
926 }
927 qty = nchunk * matrix[m][n];
928 *(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) + qty));
929 }
930
931 }
932
hf_rain_erosion_hex_old(hf_struct_type * hf,rain_erosion_struct * res,gpointer (* display_function)(gpointer),gpointer display_data)933 void hf_rain_erosion_hex_old (hf_struct_type *hf, rain_erosion_struct *res, gpointer (*display_function) (gpointer), gpointer display_data) {
934 // Simple iterative erosion
935 // using hexagonal sampling for a more natural looking result
936 // We generate random drops and follow their path
937 // We don't flow a drop when the slope is more than 2 power thresh
938 // Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
939 // Not extensively tested when the HF doesn't wrap
940
941 static gint x,y, ii, s, threshold, nextx, nexty;
942 unsigned long int steps;
943 hf_type *tmp;
944 gboolean even=TRUE, tiling;
945
946 // threshold is the future chunk... it must be at least 16, because the center
947 // of the 3x3 averaging matrix == 4 and we divide the chunk by 16 before applying it
948 // threshold = 15 + (gint) pow(2.0,(double) thresh);
949 threshold = MAX(16,iget_absolute_slope(res->threshold,hf->max_x));
950 // printf("RAIN: Threshold (slope): %d = %d\n",slope_threshold,threshold);
951 // In the 1st version, drops were given as an exponent
952 // We could fallback to this in the future...
953 // drops = (long int) pow(2.0,(gdouble) dr_log);
954
955 if (hf->if_tiles)
956 tiling = *hf->if_tiles;
957 else
958 tiling = TRUE;
959
960 if (!hf->tmp_buf)
961 hf_backup(hf);
962
963 tmp = hf->hf_buf;
964 hf->hf_buf = hexagonal_row_sampling (hf->hf_buf, hf->max_x, tiling, even, TRUE);
965 x_free(tmp);
966
967 for (s=0; s<res->drops; s++) {
968 x = rand()%hf->max_x;
969 y = rand()%hf->max_y;
970 // Make the (x,y) drop flow until it encounters a minimum
971 steps = 0;
972 while (find_all_neighbours_hex_old(x,y,&nextx,&nexty,
973 hf->max_x,hf->hf_buf,res->threshold, TRUE, TRUE)) {
974 if (!tiling)
975 if ( (x==0) || (y==0) ||
976 (x==(hf->max_x-1)) ||
977 (y==(hf->max_y-1)) )
978 break;
979 flow_old(x,y,nextx,nexty,hf->hf_buf,hf->max_x, tiling);
980 ii = VECTORIZE(nextx,nexty,hf->max_x);
981 y = nexty;
982 x = nextx;
983 steps++;
984 if (steps>hf->max_x)
985 break;
986 }
987 if (res->refresh && res->interval)
988 if ((!(s%res->interval)) && display_function && display_data)
989 (*display_function) (display_data);
990 }
991 // Restore the rectangular sampled hf
992 tmp = hf->hf_buf;
993 hf->hf_buf = hexagonal_row_sampling (hf->hf_buf, hf->max_x, tiling, even, FALSE);
994 x_free(tmp);
995 }
996
hf_crests_erosion_hex(hf_struct_type * hf,gint steps,gint slope_threshold)997 void hf_crests_erosion_hex (hf_struct_type *hf, gint steps, gint slope_threshold) {
998 // Simple iterative erosion, giving crested mountains
999 // Hexagonally sampled version (see hf_rain_erosion_hex) 2005-02
1000 // 2006-02 Replaced by randomized axis / even / odd flow
1001 // We find the minimum neighbour
1002 // If its value is superior to the current pixel one,
1003 // we add half the difference to the current pixel
1004 // If the minimum neighbour is inferior, we subtract half the current pixel
1005 // This is like if half the difference was "flowing" from or to the current pixel
1006 // Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
1007 // 2004-03-11 Corrected to deal with wrapping
1008
1009 static gint z1, z2, z3, z4, z5, z6, x, y, xx, yy;
1010 static gint i, s, val, ii, minii, lower, threshold, shift, axis;
1011 hf_type value;
1012 gboolean test, even, tiling;
1013 gfloat ratio; // Factor for dividing the weight of the minimum pixel, when it is on the diagonals
1014
1015 // Slope_threshold is in degrees
1016 threshold = iget_absolute_slope(slope_threshold,hf->max_x);
1017 // printf("Threshold (slope): %d = %d\n",slope_threshold,threshold);
1018 if (!hf->tmp_buf)
1019 hf_backup(hf);
1020
1021 if (hf->if_tiles)
1022 tiling = *hf->if_tiles;
1023 else
1024 tiling = TRUE;
1025
1026 test = y & (gint) 1; // test = TRUE if value is odd
1027 if ( (test && even) || ((!test) && (!even)) ) // XOR
1028 shift = 1;
1029 else
1030 shift = 0;
1031
1032 // We need a second temporary buffer for storing
1033 // the result of each step
1034 if (!hf->result_buf) {
1035 hf->result_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hf->result_buf in hf_crests_erosion_hex)");
1036 }
1037 // printf("CRESTS EROSION, STEPS: %d; THRESHOLD: %d\n", steps, threshold);
1038 memcpy(hf->result_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type));
1039 for (s=0; s<steps; s++) {
1040 for (y=0; y<hf->max_y; y++) {
1041 for (x=0; x<hf->max_x; x++) {
1042 even = rand()%2;
1043
1044 if (rand()%2)
1045 axis = V_AXIS;
1046 else
1047 axis = H_AXIS;
1048
1049 i = VECTORIZE(x,y,hf->max_x);
1050 value = *(hf->hf_buf + i);
1051 if (axis==H_AXIS) {
1052 xx = x+1;
1053 yy = y;
1054 }
1055 else {
1056 xx = x;
1057 yy = y+1;
1058 }
1059 if (tiling)
1060 ii=VECTORIZE(WRAP2(xx,hf->max_x),WRAP2(yy,hf->max_y), hf->max_x);
1061 else
1062 ii=VECTORIZE(MIN(xx,hf->max_x-1),MIN(yy,hf->max_y-1), hf->max_x);
1063 z1 = *(hf->hf_buf+ii);
1064 minii = ii;
1065 lower = z1;
1066 ratio = 1.0;
1067
1068 if (axis==H_AXIS) {
1069 xx = x+shift;
1070 yy = y+1;
1071 }
1072 else {
1073 xx = x+1;
1074 yy = y+shift;
1075 }
1076
1077 if (tiling)
1078 ii=VECTORIZE(WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_y),hf->max_x) ;
1079 else
1080 ii=VECTORIZE(MIN(xx,hf->max_x-1), MIN(yy,hf->max_y-1),hf->max_x) ;
1081 z2 = *(hf->hf_buf+ii);
1082 if (z2<z1) {
1083 minii = ii;
1084 lower = z2;
1085 ratio = 1.155;
1086 }
1087
1088 if (axis==H_AXIS) {
1089 xx = x-1+shift;
1090 yy = y+1;
1091 }
1092 else {
1093 xx = x+1;
1094 yy = y-1+shift;
1095 }
1096
1097 if (tiling)
1098 ii =VECTORIZE( WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_y),hf->max_x) ;
1099 else
1100 ii = VECTORIZE(MIN(MAX(xx,0),hf->max_x-1),MAX(0,yy),hf->max_x) ;
1101 z3 = *(hf->hf_buf+ii) ;
1102 if (z3<lower) {
1103 minii = ii;
1104 lower = z3;
1105 ratio = 1.155;
1106 }
1107
1108 if (axis==H_AXIS) {
1109 xx = x-1;
1110 yy = y;
1111 }
1112 else {
1113 xx = x;
1114 yy = y-1;
1115 }
1116
1117 if (tiling)
1118 ii=VECTORIZE(WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_x) , hf->max_x) ;
1119 else
1120 ii=VECTORIZE(MAX(xx,0), MAX(yy,0), hf->max_x) ;
1121 z4 = *(hf->hf_buf+ii);
1122 if (z4<lower) {
1123 minii = ii;
1124 lower = z4;
1125 ratio = 1.0;
1126 }
1127
1128 if (axis==H_AXIS) {
1129 xx = x-1+shift;
1130 yy = y-1;
1131 }
1132 else {
1133 xx = x-1;
1134 yy = y-1+shift;
1135 }
1136 if (tiling)
1137 ii=VECTORIZE(WRAP2(xx,hf->max_x),
1138 WRAP2(yy,hf->max_x),hf->max_x) ;
1139 else
1140 ii=VECTORIZE(MAX(xx,0), MAX(yy,0) ,hf->max_x) ;
1141 z5 = *(hf->hf_buf+ii) ;
1142 if (z5<lower) {
1143 minii = ii;
1144 lower = z5;
1145 ratio = 1.155;
1146 }
1147
1148 if (axis==H_AXIS) {
1149 xx = x+shift;
1150 yy = y-1;
1151 }
1152 else {
1153 xx = x-1;
1154 yy = y+shift;
1155 }
1156 if (tiling)
1157 ii=VECTORIZE(WRAP2(xx,hf->max_x),WRAP2(yy,hf->max_y),hf->max_x) ;
1158 else
1159 ii=VECTORIZE(MIN(MAX(0,xx),hf->max_x-1),MAX(yy,0),hf->max_x) ;
1160 z6 = *(hf->hf_buf+ii);
1161 if (z6<lower) {
1162 minii = ii;
1163 lower = z6;
1164 ratio = 1.155;
1165 }
1166
1167 val = ( ( ((gint) *(hf->hf_buf+minii)) - (gint) value ) / 2);
1168 if (threshold < ABS(val)) {
1169 *(hf->result_buf+i) = value + (gint) ( ((gfloat) val) / ratio);
1170 // *(hf->hf_buf+minii) -= (gint) ( ((gfloat) val) / ratio);
1171 }
1172 else
1173 *(hf->result_buf+i) = value;
1174 }
1175 }
1176 memcpy(hf->hf_buf, hf->result_buf, hf->max_x*hf->max_y*sizeof(hf_type));
1177 }
1178
1179 // printf("MAX: %d; MIN: %d; DELTA: %d\n",hf->max, hf->min, hf->max-hf->min);
1180
1181 }
1182
1183
dfind_all_neighbours(gint x,gint y,gint * newx,gint * newy,gint max,gdouble * hf,gdouble threshold)1184 gboolean dfind_all_neighbours( gint x, gint y, gint *newx, gint *newy,
1185 gint max, gdouble *hf, gdouble threshold) {
1186 // Find all the inferior neighbours of (x,y) in hf
1187 // Randomly select one of the neighbours,
1188 // given its height difference with the minimum is < to threshold
1189 // Returns the result in newx and newy
1190 // If (x,y) is a minimum, returns FALSE
1191 static gint v[8], i, ii, nx, ny, ninf, ok;
1192 gdouble value,z1, z2, z3, z4, z5, z6, z7, z8;
1193 gdouble lower= (gdouble) MAX_HF_VALUE;
1194 ninf = 0;
1195 ok = 0;
1196 value = *(hf+VECTORIZE(x,y,max)) ;
1197 ii=VECTORIZE(WRAP2(x+1,max),y,max);
1198 z1 = *(hf+ii);
1199 if (z1<value) {
1200 v[ninf] = ii;
1201 ninf++;
1202 }
1203 lower = z1;
1204 nx = WRAP2(x+1,max);
1205 ny = WRAP2(y+1,max);
1206 ii=VECTORIZE(nx, ny,max) ;
1207 z2 = *(hf+ii);
1208 if (z2<value) {
1209 v[ninf] = ii;
1210 ninf++;
1211 }
1212 if (z2<z1)
1213 lower = z2;
1214 ny=WRAP2(y+1,max) ;
1215 ii =VECTORIZE(x,ny,max) ;
1216 z3 = *(hf+ii) ;
1217 if (z3<value) {
1218 v[ninf] = ii;
1219 ninf++;
1220 }
1221 if (z3<lower)
1222 lower = z3;
1223 nx = WRAP2(x-1,max);
1224 ny = WRAP2(y+1,max);
1225 ii=VECTORIZE(nx,ny,max) ;
1226 z4 = *(hf+ii);
1227 if (z4<value) {
1228 v[ninf] = ii;
1229 ninf++;
1230 }
1231 if (z4<lower)
1232 lower = z4;
1233 nx = WRAP2(x-1,max) ;
1234 ii =VECTORIZE(nx,y,max) ;
1235 z5 = *(hf+ii) ;
1236 if (z5<value) {
1237 v[ninf] = ii;
1238 ninf++;
1239 }
1240 if (z5<lower)
1241 lower = z5;
1242 nx = WRAP2(x-1,max);
1243 ny = WRAP2(y-1,max);
1244 ii=VECTORIZE(nx, ny,max) ;
1245 z6 = *(hf+ii);
1246 if (z6<value) {
1247 v[ninf] = ii;
1248 ninf++;
1249 }
1250 if (z6<lower)
1251 lower = z6;
1252 ny = WRAP2(y-1,max) ;
1253 ii =VECTORIZE(x,ny,max) ;
1254 z7 = *(hf+ii);
1255 if (z7<value) {
1256 v[ninf] = ii;
1257 ninf++;
1258 }
1259 if (z7<lower)
1260 lower = z7;
1261 nx = WRAP2(x+1,max);
1262 ny = WRAP2(y-1,max) ;
1263 ii=VECTORIZE(nx,ny,max) ;
1264 z8 = *(hf+ii);
1265 if (z8<value) {
1266 v[ninf] = ii;
1267 ninf++;
1268 }
1269 if (z8<lower)
1270 lower = z8;
1271
1272 // printf("(%d, %d) => LOWER: %5.2f; THRESHOLD: %5.2f; VALUE: %5.2f\n", x, y, lower, threshold, value);
1273 if ( (lower+threshold) < value) {
1274 // Find all the pixels not farther away than "threshold" than the lower one
1275 for (i=0; i<ninf; i++) {
1276 if ((*(hf+v[i])-threshold)<=lower) {
1277 v[ok] = v[i];
1278 ok ++;
1279 }
1280 }
1281 // printf("ok: %d; ",ok);
1282 ii = v[rand()%ok];
1283 // printf("ii: %d; ",ii);
1284 *newx = ii%max;
1285 *newy = (gint) (ii / max);
1286 // printf("(NEWX,NEWY) = (%d,%d) = (%d,%d)\n", ii%max,(gint) ii/max,*newx,*newy);
1287 return TRUE;
1288 }
1289 else {
1290 // printf("Returning FALSE\n");
1291 return FALSE;
1292 }
1293 }
dadd_rain(gdouble * water,gint max_x,gint max_y,gdouble * v,gint vlength)1294 void dadd_rain (gdouble *water, gint max_x, gint max_y, gdouble *v, gint vlength) {
1295 gint x,y;
1296 for (y=0; y<max_y; y++) {
1297 for (x=0; x<max_x; x++) {
1298 // Generate water
1299 *(water+VECTORIZE(x,y,max_x)) += v[rand()%vlength];
1300 }
1301 }
1302 }
1303 /*
1304 static gdouble *build_map (gint soil_qty, gint radius) {
1305
1306 gdouble *map, sum, dval, ratio;
1307 gint i,j,map_size;
1308
1309 map_size = (2*radius) + 1;
1310 map = (gdouble *) x_malloc(map_size*map_size*sizeof(gdouble), "gdouble (map in build_map in erode.c");
1311 sum = 0.0;
1312 if (!radius)
1313 sum = (gdouble) soil_qty;
1314 else {
1315 for (i=-radius; i<radius+1; i++) {
1316 for (j=-radius; j<radius+1; j++) {
1317 dval = BELLD(CONST_E,2.0,i,radius) *
1318 BELLD(CONST_E,2.0,j,radius);
1319 sum += dval;
1320 }
1321 }
1322 }
1323
1324 ratio = ((gdouble) soil_qty) / sum;
1325 */
1326 /*
1327 printf("SUM: %6.3f; RADIUS: %5d; ",sum, radius);
1328 printf("SOIL_QTY: %5d ",soil_qty);
1329 printf("RATIO: %6.3f\n", ratio);
1330 */
1331 // printf("MAP %d x %d:\n", (2*radius) + 1, (2*radius) + 1);
1332 /*
1333 for (i=-radius; i<radius+1; i++) {
1334 for (j=-radius; j<radius+1; j++) {
1335 *(map+VECTORIZE(i+radius,j+radius,map_size)) = ratio * BELLD(CONST_E,2.0,i,radius) * BELLD(CONST_E,2.0,j,radius);
1336 // if (radius<4) printf("(%d, %d) == %5.2f; ",i,j,*(map+VECTORIZE(i,j,map_size)) );
1337 }
1338 // if (radius<4) printf("\n");
1339 }
1340 return map;
1341 }
1342 */
1343
dflow_map(gint x,gint y,gint tox,gint toy,gdouble * hf,gdouble * water,gint max,gboolean wrap)1344 void dflow_map(gint x, gint y, gint tox, gint toy, gdouble *hf, gdouble *water, gint max, gboolean wrap) {
1345 // Flow a quarter of the water (part considered as soil in suspension)
1346 // between (x,y) and (tox,toy) from (x,y) to (tox,toy)
1347
1348 gint fromi, toi, isoil, radius, map_size;
1349
1350 gdouble soil;
1351 // gdouble *map;
1352
1353 // 1. Check if required map is already cached
1354 // 2. Build it if not, add to the cache
1355
1356 fromi = VECTORIZE(x,y,max);
1357 toi = VECTORIZE(tox,toy,max);
1358
1359 soil = *(water + fromi);
1360
1361 // printf("FROM (%d, %d) TO (%d, %d); SOIL: %5.2f; \n", x, y, tox, toy, soil);
1362 isoil = MIN(MAX_CACHE-1,(gint) soil);
1363
1364 if (!isoil)
1365 return;
1366
1367 radius = (gint) log((gdouble) isoil);
1368 map_size = 2*radius +1;
1369 /*
1370 map = *(cache+isoil);
1371
1372 if (! map ) {
1373 map = build_map (isoil, radius);
1374 *(cache+isoil) = map;
1375 }
1376 */
1377 // if (map_size==1)
1378 *(water+VECTORIZE(tox,toy,max)) += soil;
1379 // else
1380 // generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) water, GDOUBLE_ID, max, max, tox, toy, ADD, wrap, FALSE);
1381 /*
1382
1383 if (map_size==1) {
1384 *(hf+VECTORIZE(x,y,max)) -= soil;
1385 *(hf+VECTORIZE(tox,toy,max)) += soil;
1386 }
1387 else {
1388 generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) hf, GDOUBLE_ID, max, max, x, y, SUBTRACT, wrap, FALSE);
1389
1390 generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) hf, GDOUBLE_ID, max, max, tox, toy, ADD, wrap, FALSE);
1391 }
1392
1393
1394 // We flow all the water mass
1395 *(water+toi) += *(water+fromi);
1396 *(water+fromi) = 0.0;
1397 */
1398 }
1399
check_water(gdouble * water,gint max)1400 void check_water (gdouble *water, gint max) {
1401
1402 gint i, count=0;
1403 gdouble sum=0.0;
1404
1405 for (i=0; i<max*max; i++) {
1406 if (*(water+i)>0.0) {
1407 count ++;
1408 sum += *(water+i);
1409 }
1410 }
1411 printf("WATER PIX > 0: %d; SUM: %5.2f; AVRG: %5.2f\n",count, sum, sum / (gdouble) count);
1412
1413 }
1414
check_hf(gdouble * hf,gint max)1415 void check_hf (gdouble *hf, gint max) {
1416
1417 gint i, countneg=0, countoverflow=0;
1418 gdouble sumo=0.0, sumn=0.0;
1419
1420 for (i=0; i<max*max; i++) {
1421 if (*(hf+i)<1.0) {
1422 countneg ++;
1423 sumn += *(hf+i);
1424 }
1425 else
1426 if (*(hf+i)>(gdouble)MAX_HF_VALUE) {
1427 countoverflow ++;
1428 sumo += *(hf+i) - (gdouble) MAX_HF_VALUE;
1429 }
1430
1431
1432 }
1433 printf("HF < 1: %d; AVRG: %7.2f HF > MAX: %d; AVRG: %7.2f\n",countneg, sumn / (gdouble) countneg, countoverflow, sumo / (gdouble) countoverflow);
1434
1435 }
1436
hf_water_erosion(hf_struct_type * hf,gint steps,gint slope_threshold)1437 void hf_water_erosion (hf_struct_type *hf, gint steps, gint slope_threshold) {
1438 // Water / fluvial erosion
1439 // Simple model without speed and direction matrix
1440 // Derivated from the rain erosion
1441 // Basically, we add drops in a water matrix
1442 // We never spread water explicitly
1443 // Howvever, we spread soil with a gaussian matrix which size depends
1444 // on the water weight
1445 // Buffers:
1446 // input, output: height field converted to gdouble, 0 - 0xFFFF -> 0 - 1.0
1447 // water = water mass;
1448 gdouble threshold;
1449 gdouble *water,*input;
1450 gint i,s,x,y, nextx, nexty;
1451 gboolean tiling;
1452 gdouble vpow2[15] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 4.0, 4.0 ,8.0};
1453
1454 // for (i=0; i<15; i++)
1455 // vpow2[i] /= (gdouble) MAX_HF_VALUE;
1456
1457 if (hf->if_tiles)
1458 tiling = *hf->if_tiles;
1459 else
1460 tiling = TRUE;
1461
1462 if (!if_cache_init) {
1463 // printf("@@@@@@@@@@@@@@@@ Initializing CACHE @@@@@@@@@@@@@@@@\n");
1464 cache = (gdouble **) x_malloc(MAX_CACHE*sizeof(gdouble *), "gdouble * (cache in hf_water_erosion)");
1465 for (i=0; i<MAX_CACHE; i++) {
1466 *(cache+i) = NULL;
1467 }
1468 if_cache_init = TRUE;
1469 }
1470
1471 threshold = dget_absolute_slope(slope_threshold,hf->max_x);
1472
1473 input = xalloc_double_hf(hf->max_x, "gdouble (input in hf_water_erosion");
1474 water = xcalloc_double_hf(hf->max_x, "gdouble (water in hf_water_erosion");
1475
1476 hf_type_to_double (hf->hf_buf, hf->max_x, hf->max_y, input);
1477
1478 // For each step, for each pixel:
1479 // 1. Add rain drops to the current water mass
1480 // Choice at random
1481 // water mass = power of 2, from 0 to 3), small chunks more frequent
1482 // 2. Flow the water mass with a simple rule, like we do with rain
1483 // Modify the water matrix
1484 // Add / subtract the soil from input to output
1485
1486 for (s=0; s<steps; s++) {
1487 printf("STEP : %d / %d\n",s, steps);
1488 dadd_rain (water, hf->max_x, hf->max_y, vpow2, 15);
1489
1490 for (y=0; y<hf->max_y; y++) {
1491 for (x=0; x<hf->max_x; x++) {
1492 i = VECTORIZE(x,y,hf->max_x);
1493
1494 if (dfind_all_neighbours(x,y,&nextx,&nexty,
1495 hf->max_x,input,threshold)) {
1496 if (!tiling)
1497 if ( (x==0) || (y==0) ||
1498 (x==(hf->max_x-1)) ||
1499 (y==(hf->max_y-1)) )
1500 break;
1501 // printf("Flowing from (%d, %d) to (%d, %d)\n",x,y,nextx,nexty);
1502 dflow_map(x,y,nextx,nexty,input,water,hf->max_x, tiling);
1503 }
1504 }
1505 }
1506 for (i=0; i<hf->max_x*hf->max_y; i++)
1507 *(input+i) = *(water+i) + *(input+i);
1508 // check_water (water, hf->max_x);
1509 // check_hf (input, hf->max_x);
1510 }
1511
1512 double_clamp (hf->hf_buf, hf->max_x, hf->max_y, 0, MAX_HF_VALUE, water);
1513 // double_clamp (hf->hf_buf, hf->max_x, hf->max_y, 0, MAX_HF_VALUE, input);
1514
1515 x_free(input);
1516 x_free(water);
1517 }
1518