Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ create random shaped "blob" objects

I need to define an object (or a region) that is kind of "blob" shaped on a discrete gridmap. It should look something like this: enter image description here

where the red region denotes the center point (these are just ideas, any blobby shape will work as long as it can be varied randomly). My idea so far was to iteratively increment the angle from starting point (=0 degrees) to 360 degrees and use trigonometry to calculate the outer points of a circle (which will result in the unit circle if the radius = 1 = const). I then used Bresenham's line algorithm (remember: we are moving on a discrete grid) to calculate the line that connects the center of the circle and the outer point I just came up with. My idea was that if I could vary the radius somewhat, I could create these blobby shapes. What I've come up with so far gives me nice shapes, they're just not really "blobby" though. Here's my code (note that x0 and y0 mark the center point of my gridmap, plotBresenham just puts all 1s in the regions so the gridmap can be visualized):

double radius = 10; 
for(int alpha=0; alpha<360; alpha++) {
   double x = cos(alpha*M_PI/180.0)*radius;
   double y = sin(alpha*M_PI/180.0)*radius;

   if(alpha<45) radius+=0.5;
   else if(alpha<90) radius-=0.5; 
   else if(alpha<135) radius+=0.5; 
   else if(alpha<180) radius-=0.5; 
   else if(alpha<225) radius+=0.5; 
   else if(alpha<270) radius-=0.5; 
   else if(alpha<315) radius+=0.5; 
   else radius-=0.5; 

   plotBresenhamLine(x0,y0,x,y)

}

The result looks like this:

enter image description here

Sorry for the crude drawing. Programming language is C++, but I think the approach doesn't really depend on the language used. Any tips / help / guidance on how I can create shapes that resemble the ones I need more? Or even a Framework that does stuff like this for you? For me, it's just important to have the coordinates of the points within, to put them into my gridmap.

like image 386
masterBroesel Avatar asked Dec 24 '22 00:12

masterBroesel


1 Answers

Varying the radius with the angle is the way to go. But instead of the random walk you can use a sum of several periodic functions with predetermined amplitudes and phases. This guarantees that

  1. the radius will come back to its original value after a turn of 360°,
  2. you can easily control the range of radii you encounter. (You need to avoid going less than zero).

Pick a sine or cosine function where you multiply the angle by an integer and add a random phase. Scale each by a random (pre-determined) amplitude. Add a constant larger than the sum of all the amplitudes. Profit.

I'm not going to write this in C++ because, as you said, it won't add anything important to the algorithm. It may go like this:

  1. Take N, the number of waves you'd like.
  2. Define float arrays amps[N] and phases[N].
  3. Pick a random number between 0 and 1/(2N) for each amps[i] and between 0 and 2π for each phases[i].
  4. For each angle alpha (in radians), calculate
radius = 1 + sum[i=0 to N-1] amps[i] * cos((i+1)*alpha + phases[i])
x = cos(alpha)*radius;
y = sin(alpha)*radius;
  1. Proceed as before.

Results (from Wolfram Mathematica):

To make it somewhat more interesting, limit the k-th amplitude by some negative power of k (or of k+1, since we're indexing from zero). Here's when instead of 2N the random number is divided by pow(i+1,1.5) in step 3, for N = 30:

like image 197
The Vee Avatar answered Dec 29 '22 12:12

The Vee