Reputation: 299
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:
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:
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.
Upvotes: 7
Views: 2733
Reputation: 11
This is a followup for The Vee's great answer.
For anyone stumbling upon this question and is looking for an implementation. Python code, it can be written like so.
from random import random
from math import cos, sin, pi, radians
N = 10
amps = [random() * (1 / (2*N)) for _ in range(N)]
phases = [random() * 2 * pi for _ in range(N)]
x = []
y = []
for deg in range(360):
alpha = radians(deg)
radius = 1 + sum([amps[i] * cos((i+1)*alpha + phases[i]) for i in range(N)])
x.append(cos(alpha) * radius)
y.append(sin(alpha) * radius)
Upvotes: 1
Reputation: 1629
Here is a C version of the solution from "The Vee" that gets close to what I'm looking for, but I'm trying to find a way to invert the curve for some of the parts, which would make these "nodes" that stretch out look like they're starting to pinch off.
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main() {
time_t t;
uint16_t alpha, i;
uint16_t N = 12;
float amps[N];
float phases[N];
float radius, x, y;
srand((unsigned) time(&t));
srand((unsigned) rand());
for (i=0; i<N; i++) {
float s = (rand() / (float) RAND_MAX);
amps[i] = 1.0/(2.0*N) * s * 4;
phases[i] = s * 2.0 * M_PI;
}
for (alpha=0; alpha<360; alpha++) {
float radian = alpha * ( M_PI / 180.0 );
radius = 1;
for (i=0; i<N-1; i++) {
radius = radius + (amps[i] * cos((i+1)*radian + phases[i]));
}
x = cos(radian)*radius;
y = sin(radian)*radius;
printf("%2.16f, %2.16f\n", x, y);
}
}
Upvotes: 1
Reputation: 11580
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
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:
amps[N]
and phases[N]
.amps[i]
and between 0 and 2π for each phases[i]
.alpha
(in radians), calculateradius = 1 + sum[i=0 to N-1] amps[i] * cos((i+1)*alpha + phases[i])
x = cos(alpha)*radius;
y = sin(alpha)*radius;
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:
Upvotes: 12