# random.c: distort a bitmap. # # Copyright (C) 1992, 2011 Free Software Foundation, Inc. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # #include "config.h" #include "rand.h" #include "random.h" /* Distort the bitmap (see below). (-randomize) */ real random_max = 0.0; real random_threshold = 0.2; static bitmap_type enlarge_bitmap (bitmap_type, int, int); static real random_number (void); /* Randomize the bitmap B by moving each black pixel a randomly chosen distance between -random_max and random_max (both horizontally and vertically). Return the enlargement of B on all four side in ADJUST. */ void randomize_bitmap (bitmap_type *b, bounding_box_type *adjust) { unsigned this_row, this_col; MIN_ROW (*adjust) = MAX_ROW (*adjust) = MIN_COL (*adjust) = MAX_COL (*adjust) = 0; for (this_row = 0; this_row < BITMAP_HEIGHT (*b); this_row++) for (this_col = 0; this_col < BITMAP_WIDTH (*b); this_col++) { if (BITMAP_PIXEL (*b, this_row, this_col) != WHITE) { int row_enlarge, col_enlarge; /* Generate two random numbers between -random_max and random_max to give rise to the new x and y. */ real random1 = random_number (); int row_delta = random1 + .5 * SIGN (random1); int new_row = this_row + row_delta; real random2 = random_number (); int col_delta = random2 + .5 * SIGN (random2); int new_col = this_col + col_delta; /* Clear the old location before we (possibly) mess with the bitmap dimensions. */ BITMAP_PIXEL (*b, this_row, this_col) = WHITE; /* Check if the new location is outside the current bitmap. */ if (new_row < 0) { row_enlarge = new_row; /* Negative rows are off the top of the bitmap -- it's in C coordinates, not Cartesian. */ MAX_ROW (*adjust) -= row_enlarge; } else if (new_row >= BITMAP_HEIGHT (*b)) { row_enlarge = new_row - BITMAP_HEIGHT (*b) + 1; MIN_ROW (*adjust) += row_enlarge; } else row_enlarge = 0; if (new_col < 0) { col_enlarge = new_col; MIN_COL (*adjust) -= col_enlarge; } else if (new_col >= BITMAP_WIDTH (*b)) { col_enlarge = new_col - BITMAP_WIDTH (*b) + 1; MAX_COL (*adjust) += col_enlarge; } else col_enlarge = 0; if (row_delta != 0 || col_delta != 0) { /* Enlarge the bitmap to make the new location valid. */ bitmap_type new_b = enlarge_bitmap (*b, row_enlarge, col_enlarge); free_bitmap (b); *b = new_b; /* We've made the new row/column at the edge. */ if (new_row < 0) new_row = 0; if (new_col < 0) new_col = 0; } BITMAP_PIXEL (*b, new_row, new_col) = BLACK; } } } /* Return the enlargement of the bitmap B by ROW_DELTA and COL_DELTA. Negative deltas enlarge to the bottom/left, positive to the top/right. */ static bitmap_type enlarge_bitmap (bitmap_type b, int row_delta, int col_delta) { bitmap_type new; dimensions_type new_size; unsigned row; int row_addend = row_delta < 0 ? abs (row_delta) : 0; int col_addend = col_delta < 0 ? abs (col_delta) : 0; DIMENSIONS_HEIGHT (new_size) = BITMAP_HEIGHT (b) + abs (row_delta); DIMENSIONS_WIDTH (new_size) = BITMAP_WIDTH (b) + abs (col_delta); new = new_bitmap (new_size); /* `new_bitmap' initializes all the pixels to white, so we don't have to do anything to the new rows and columns. */ for (row = 0; row < BITMAP_HEIGHT (b); row++) { one_byte *source = BITMAP_ROW (b, row); one_byte *target = BITMAP_ROW (new, row + row_addend) + col_addend; memcpy (target, source, BITMAP_WIDTH (b)); } return new; } /* Return a random number between -random_max and random_max. */ static real random_number () { static boolean initialized = false; real r; if (!initialized) { seed_rand (getpid ()); initialized = true; } /* If the random number is less than `random_threshold', return zero. Otherwise, return a random number in the interval [-random_max,random_max]. */ r = (real) k_rand () / RAND_MAX; r = r > random_threshold ? (real) k_rand () / RAND_MAX * random_max - random_max : 0; return r; }