1

I want to create a genrator of "not perfect circles", circles that are a bit twisted and more random, but still look a bit like circle or maybe a cloud.

This is what I mean by not perfect circles: enter image description here

I want to create a function that gets the maximum and minimum scale of the "not perfect circle" and gets all of its points. I know the formula of a circle: X^2+Y^2=R^2 but I cant think of a way to make it a bit more random. Anyone has any ideas?

Edit: trying to draw a perfect circle with points but it wont work:

    for (int step = 0; step < 300; ++step) {
         double t = step / 300 * 2 * Math.PI;
         c.drawPoint(300+(float)(33 * Math.cos(t)), 300+(float)(33 * Math.sin(t)), p);
    }

Edit 2:

    for (int step = 0; step < 20; ++step) {
          double t = step / 20.0 * 2 * Math.PI; 
          double imperfectR = 50.0+randInt(10, 50);
          //I do it here?
          points[step]=new PointF();
          points[step].set((300+(float)(imperfectR  * Math.cos(t))), 300+(float)(imperfectR  * Math.sin(t)));
          if(step==0){
                pp.moveTo(points[step].x, points[step].y);
          }
          else
                pp.quadTo(points[step-1].x, points[step-1].y,points[step].x, points[step].y);

    } 

Edit 3:

double t=0;
for (int i = 0; i < points.length/4; i++) {
        if(t==1){
            t=0;
        }
        t+=0.10;
        double imperfectR=0.5*((2*points[i+1].y)+(-points[i].y+points[i+2].y)*t+(2*points[i].y-5*points[i+1].y+4*points[i+2].y-points[i+3].y)*(t*t)+((-points[i].y+3*points[i+1].y-3*points[i+2].y+points[i+3].y)*(t*t*t)));
        newPoints[i].set((300+(float)(imperfectR  * Math.cos(t))), 300+(float)(imperfectR  * Math.sin(t)));
        t+=0.10;
        imperfectR=0.5*((2*points[i+1].y)+(-points[i].y+points[i+2].y)*t+(2*points[i].y-5*points[i+1].y+4*points[i+2].y-points[i+3].y)*(t*t)+((-points[i].y+3*points[i+1].y-3*points[i+2].y+points[i+3].y)*(t*t*t)));
        newPoints[i+1].set((300+(float)(imperfectR  * Math.cos(t))), 300+(float)(imperfectR  * Math.sin(t)));
        t+=0.10;
        imperfectR=0.5*((2*points[i+1].y)+(-points[i].y+points[i+2].y)*t+(2*points[i].y-5*points[i+1].y+4*points[i+2].y-points[i+3].y)*(t*t)+((-points[i].y+3*points[i+1].y-3*points[i+2].y+points[i+3].y)*(t*t*t)));
        newPoints[i+2].set((300+(float)(imperfectR  * Math.cos(t))), 300+(float)(imperfectR  * Math.sin(t)));
        t+=0.10;
        imperfectR=0.5*((2*points[i+1].y)+(-points[i].y+points[i+2].y)*t+(2*points[i].y-5*points[i+1].y+4*points[i+2].y-points[i+3].y)*(t*t)+((-points[i].y+3*points[i+1].y-3*points[i+2].y+points[i+3].y)*(t*t*t)));
        newPoints[i+3].set((300+(float)(imperfectR  * Math.cos(t))), 300+(float)(imperfectR  * Math.sin(t)));
        if(i==0){
            pp.moveTo(newPoints[i].x, newPoints[i].y);
        }
        pp.lineTo(newPoints[i].x, newPoints[i].y);
        pp.lineTo(newPoints[i+1].x, newPoints[i+1].y);
        pp.lineTo(newPoints[i+2].x, newPoints[i+2].y);
        pp.lineTo(newPoints[i+3].x, newPoints[i+3].y);

}
pp.close();
Slava Vedenin
  • 58,326
  • 13
  • 40
  • 59
SpoocyCrep
  • 604
  • 7
  • 23
  • 1
    simple approach: calculate N points, which satisfy circle equation -> randomly increase/decrease each coordinate in a range [0, sigma] -> draw the path using these modified points. – nikis Mar 25 '15 at 11:24
  • 2
    Maybe look into circular harmonics, i.e. adding to the radius using a weighted sum of randomly-chosen sine waves whose frequency is such that an exact number of cycles fit into the circumference? – Andy Turner Mar 25 '15 at 11:25
  • @nikis but if I want to make it a bit more smoother, like if I will random each point the circle might turn to look like a spike ball, not a circle. – SpoocyCrep Mar 25 '15 at 11:27
  • @AndyTurner that sounds really complicated.. how do I do that? – SpoocyCrep Mar 25 '15 at 11:28
  • 1
    @SpoocyCrep it depends on N and sigma. – nikis Mar 25 '15 at 11:34
  • @nikis Yes it depends on N, but if I randomly increase and decrease it wont look smooth, and what is sigma? – SpoocyCrep Mar 25 '15 at 12:10
  • @SpoocyCrep sigma is maximum allowed deviance. But I agree, this approach is not perfectly fits you needs. – nikis Mar 25 '15 at 12:13
  • @SpoocyCrep you can express the circle via the parametric equations $\theta(t) = t$ and $r(t) = R$, where $t$ is your parameter in the range $[0..2\pi)$. You can adjust the radius for a given $t$, e.g. $r'(t) = R + \sum_i A_i\cos(it + w_i)$. Just choose your $A_i$ and $w_i$ values randomly. – Andy Turner Mar 25 '15 at 12:38
  • @AndyTurner Uh, that really looks like chinese for me, I apologize but I didn't understand a thing, I'm still an high school student so I might've not reached these kinds of stuff, but what is '$' or theta or t? – SpoocyCrep Mar 25 '15 at 12:58
  • Unfortunately SO doesn't render LaTeX like I expected :( Basically, anything between the dollars is math. `\cos` is the cosine function. – Andy Turner Mar 25 '15 at 13:08
  • @AndyTurner Please post an answer with an easier to read formation and also how to use it to get each point of the not perfect circle, ill be very grateful! – SpoocyCrep Mar 25 '15 at 13:19
  • the easiest is to use DiscretePathEffect but the result may be not as smooth as you want, otherwise use bezier curves but it requires some math skills... – pskink Mar 25 '15 at 13:42
  • @pskink but the patheffect wont actually change the points of the circle, only it look, or am I mistaking? – SpoocyCrep Mar 25 '15 at 13:53
  • yes, isn't it what you want? – pskink Mar 25 '15 at 13:56
  • @pskink No, I dont want to draw the circle with this shape, I want to just get the points of this shape so I could achieve this effect: http://stackoverflow.com/q/29240327/4024143 – SpoocyCrep Mar 25 '15 at 13:59
  • so google for "random curve" like this http://stackoverflow.com/questions/6661653/how-to-generate-this-kind-of-random-curves – pskink Mar 25 '15 at 14:04
  • @pskink as I said on the other question I dont want it to fly in random curve, because the bird is only one example, I need this effect for many other things like text wiggling smoothly, or mobs that float, and more stuff like that. – SpoocyCrep Mar 25 '15 at 14:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73778/discussion-between-spoocycrep-and-pskink). – SpoocyCrep Mar 25 '15 at 14:46
  • @pskink Lets discuss it at least here, I will try the code you have given, and I have no idea how to implement the catmull in android, im not that good with math and all of these stuff look really complicated to me.. – SpoocyCrep Mar 26 '15 at 12:50
  • @SpoocyCrep use your google, Luke, there is a lot of pages with the complete formula – pskink Mar 26 '15 at 12:59
  • @pskink I know how to use google, but I have hard time reading formulas like these, it looks like chinese for me.. – SpoocyCrep Mar 26 '15 at 13:03
  • @SpoocyCrep feed google with "catmull rom algorithm" : the first two are wikipedia articles with theory, the second two are practical sites with working code (e.g. "Splines, Catmull-Rom algorithm for smooth movement") – pskink Mar 26 '15 at 13:11
  • @pskink but those are not written in java and doesnt fit android, its hard to understand some parts of the code and translate them to android.. – SpoocyCrep Mar 26 '15 at 13:17
  • @pskink also what is SpringSystem? it doesnt exist in android I believe – SpoocyCrep Mar 26 '15 at 13:37
  • @SpoocyCrep It comes with rebound library, thats why catmull rom splines are better since they only take 30 lines of code and are much more smooth and realistic – pskink Mar 26 '15 at 13:40
  • @pskink well I dont understand how to do it. I understand that for you its easy and it would take you only 30 lines of code, but I don't understand how to do it in android. If you dont want to help me I dont see the point of teasing me by telling me its easy and simple.. – SpoocyCrep Mar 26 '15 at 13:59
  • @SpoocyCrep did you read the fourth link from google search: http://www.dxstudio.com/guide_content.aspx?id=70a2b2cf-193e-4019-859c-28210b1da81f , whats unclear in `Output_point = P0 ...` this is the exact formula! – pskink Mar 26 '15 at 14:04
  • @pskink its written in javascript so its really confusing.. ill try again I guess.. – SpoocyCrep Mar 26 '15 at 14:07
  • @pskink what is vector? – SpoocyCrep Mar 26 '15 at 14:13
  • @SpoocyCrep a line with a starting and ending point – pskink Mar 26 '15 at 14:14
  • @pskink how do I do that in android? – SpoocyCrep Mar 26 '15 at 14:15
  • @SpoocyCrep you dont need to translate that sample javascript code to java, just use the formula that is at the beginning of that page: `Output_point = P0 ... etc` – pskink Mar 26 '15 at 14:21
  • that formulla is also in a third link in modified form: http://www.mvps.org/directx/articles/catmull/ (see Equation 2) `q(t) = 0.5 *...` – pskink Mar 26 '15 at 14:30
  • @pskink I still dont understand. Ok so I get this output_point\desired point, what do I do with it now? what is it exactly? – SpoocyCrep Mar 26 '15 at 14:33
  • it is a formula for getting the y value of the curve input parameter is in range <0..1> – pskink Mar 26 '15 at 14:36
  • @pskink but I still need the other points, what do I do with this one? how do I draw the curve? – SpoocyCrep Mar 26 '15 at 14:37
  • this formula gives you imperfectR (see answer below) – pskink Mar 26 '15 at 14:43
  • @pskink Ohhh, but why in range 0 to 1? – SpoocyCrep Mar 26 '15 at 14:48
  • @SpoocyCrep because Catmull-Rom splines work that way – pskink Mar 26 '15 at 14:49
  • @pskink Wait, I just got completely confused. what do I exactly put in the formula, I mean its in a for, each point until the current point or what? – SpoocyCrep Mar 26 '15 at 17:43
  • For values of t between 0 and 1 the curve passes through P1 at t=0 and it passes through P2 at t=1, To do more than two points just step through the array of points using the previous point, the current point and the next two points as the four points for the spline. For each of these segments draw a curve for 0 < t < 1. This curve will be between the current point and the next point along the whole path – pskink Mar 26 '15 at 17:48
  • @pskink but how will I have array of points before having imperfectR, I need imperfectR to draw points, and then use Catmull rom as imperfectR?? – SpoocyCrep Mar 26 '15 at 17:53
  • imagine a perfect circle: it has constant radius R all the time, inperfect circle has to have smootlhly changing radius: R +/- "some small value" what you need is to provide such a smooth function and catmull rom helps here – pskink Mar 26 '15 at 18:12
  • @pskink I understand that, and I managed to create imperfect circle with not constant radius. But you tell me that to create imperfect circle i need to use the catmull rom as the R, but also you tell me to get the catmull rom I need all the points (but how the points can exist if there is no R beforehand). you don't see the problem? sigh i'm lost. – SpoocyCrep Mar 26 '15 at 18:17
  • you need to randomly generate sharp function (red one) and then smooth it using catmull rom (green one) http://ctrlv.in/525142 and use a green one as a radius, or see this: http://www.dxstudio.com/wikifiles/14cab67f-70f8-4c3e-873a-b028bf64ef4d.png, you generate randomly red points and then use catmull-rom to make smooth radius – pskink Mar 26 '15 at 18:38
  • @pskink Okay, going step by step I generated random sharp shape: http://puu.sh/gQDuX/3078cbdf59.png now, I go each 4 points and use them to draw a curve with catmull-rom? how? – SpoocyCrep Mar 26 '15 at 19:03
  • so you have N radiuses, so apply catmull-rom for each of them, btw your N is way too high: i used 20 as N and it looks like this: http://ctrlv.in/524966 or http://ctrlv.in/524967 – pskink Mar 26 '15 at 19:14
  • @pskink wait I need manually write the t for each one of them? – SpoocyCrep Mar 26 '15 at 19:27
  • yes for each of them call q(t) where t is 0..1 – pskink Mar 26 '15 at 19:30
  • @pskink so i set random t? – SpoocyCrep Mar 26 '15 at 19:37
  • no, use 0.1, 0.2 etc – pskink Mar 26 '15 at 19:41
  • but if I have 20 steps, and you tell me to go +0.10 each time, what do I do when I reach 1? reset it? – SpoocyCrep Mar 26 '15 at 19:42
  • yes you have to call t = 0, 0.1, 0.2 ... 20 times – pskink Mar 26 '15 at 19:55
  • @pskink Okay, do I do it inside the for I created for creating the shape or I do another for? ill edit in the code I wrote to draw the shape, do I do it there? – SpoocyCrep Mar 26 '15 at 19:56
  • use another for loop – pskink Mar 26 '15 at 20:12
  • @pskink Okay, I tried it, it drew nothing, I did how I understood you, ill post it in the queston in edit 3 – SpoocyCrep Mar 26 '15 at 20:40
  • @pskink actually my bad, I didnt set the points correctly, I did now and it drew: http://puu.sh/gQMfh/f1becbe8dc.png also edited edit 3 to the code im using now – SpoocyCrep Mar 26 '15 at 20:45
  • 1
    ok it seems you will not do that: then see this http://pastebin.com/FuCUMZvq – pskink Mar 26 '15 at 20:51
  • @pskink THANK YOU, please post this as answer so I could mark it as done. – SpoocyCrep Mar 26 '15 at 21:11

1 Answers1

3

An alternative equation for a circle which is a bit easier to draw is one of its parametric forms:

x = R * cos(t);
y = R * sin(t);

where R is the nominal radius and t is a parameter between 0 and 2 * pi. So, you can draw points on the circumference a 'perfect' circle like this:

for (int step = 0; step < NSTEPS; ++step) {
  double t = step / (double) NSTEPS * 2 * pi;
  drawPoint(R * cos(t), R * sin(t));
}

You can make the circle 'imperfect' by adding on a random amount to the circle's radius, as suggested by @nikis:

for (int step = 0; step < NSTEPS; ++step) {
  double t = step / (double) NSTEPS * 2 * pi;
  double imperfectR = R + randn();  // Normally distributed random
  drawPoint(imperfectR * cos(t), imperfectR * sin(t));
}

However, this is probably going to give you very spiky shape, since there is nothing to make the radius at step and step + 1 similar. Without losing generality, you can rewrite the code above as:

for (int step = 0; step < NSTEPS; ++step) {
  double t = step / (double) NSTEPS * 2 * pi;
  double imperfectR = f(t);
  drawPoint(imperfectR * cos(t), imperfectR * sin(t));
}

Where f(t) is some function generating the radius for parameter t. Now, you can choose absolutely any function for t, but you probably want to choose something which is continuous over the circle, i.e. there is no point where f(t) changes value suddenly.

There are lots of choices here. The example that I suggested above was to suggest using a sum of cosine functions:

double f(double t) {
  double f = 0;
  for (int i = 0; i < N; ++i) {
    f += A[i] * cos(i * t + w[i]);
  }
  return f;
}

where A and w are randomly-selected values; A[0] should be set to R. The point here is that the cosine function has a period of 2 * pi, so f(alpha) = f(alpha + 2 * pi), satisfying the requirement of being continuous.

However, this is far from the only choice. You could maybe choose something like a sum of Gaussian kernels, which places 'bumps' centered at w[i] with a spread of sigma[i] on the circumference of the circle:

double f(double t) {
  double f = 0;
  for (int i = 0; i < N; ++i) {
    f += A[i] * exp(-Math.pow(t-w[i], 2) / sigma[i]);
  }
  return f;
}

(this doesn't quite work, it doesn't handle the wrap-around of t)

You will need to play around and see what function and what sorts of randomly-selected values give you the shape you are looking for.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Thank you for your rich answer, Im trying the code now but I fail to draw the perfect circle as shown in the second code, can you join http://chat.stackoverflow.com/rooms/73778/discussion-between-spoocycrep-and-pskink please? – SpoocyCrep Mar 25 '15 at 14:49
  • Ill also edit in the code I wrote that fails to draw a circle – SpoocyCrep Mar 25 '15 at 15:05
  • The sum of cosines example for `f` is the way to go (you'd also want to add sines). By Fourier series, any shape would be possible if you use infinitely many `A` values. In that sense, cosines and sines are the only choice. – Teepeemm Mar 25 '15 at 16:02
  • @Teepeemm but why do I fail to draw a normal circle in the code I edited in the question – SpoocyCrep Mar 25 '15 at 16:34
  • 1
    @Teepeemm - you don't need separate sines because of the offset `w[i]` in `cos(i * t + w[i])`. Of course, you can express as `cos(A + B) = a cos A + b sin B`. – Andy Turner Mar 25 '15 at 16:37
  • @SpoocyCrep - I suspect that `step / 300 * 2` is always evaluating to zero because all terms are integers and `step < 300`. Try `300.0` to force coercion to a double. (And apologies for writing it in my code...) – Andy Turner Mar 25 '15 at 17:04
  • 1
    @SpoocyCrep if you really want smooth random curves read this: http://www.antigrain.com/research/bezier_interpolation/ – pskink Mar 25 '15 at 17:18
  • @AndyTurner Okay, I managed to draw a circle and imperfect circle that is spiky, I'm now trying to understand the f function, what is N? and do I need to manually set random values in A[] and M[]? I didn't really understand that part – SpoocyCrep Mar 25 '15 at 19:11
  • @pskink Thanks, Ill save that solution, for now ill try andy's solution, if that wont work ill try yours – SpoocyCrep Mar 25 '15 at 19:26
  • @SpoocyCrep this is a 10 minute work, not perfect, but perfectly random and perfectly smooth: http://ctrlv.in/524483 – pskink Mar 25 '15 at 19:54
  • @pskink nice! well if so ill be happy to see how you did it – SpoocyCrep Mar 25 '15 at 19:58
  • @SpoocyCrep just implemented the idea frm the link i sent – pskink Mar 25 '15 at 20:06
  • @pskink it looks complicated and some parts of the code doesnt exist in android.. It also doesnt exactly show how to create a circle type shape, but smooth any kind of shape.. meaning I need to create random curved shape which is also something that sounds hard. if you already made the app I dont see why cant you share the solution in android o.0. – SpoocyCrep Mar 25 '15 at 20:08
  • @SpoocyCrep its nothing but a simple math, from Android i only used Math.hypot and Path.moveTo/cubicTo – pskink Mar 25 '15 at 20:13
  • I'm pleased that you are making progress, but could you take it to chat? – Andy Turner Mar 25 '15 at 20:15
  • @AndyTurner apologize, can you please answer my question "Okay, I managed to draw a circle and imperfect circle that is spiky, I'm now trying to understand the f function, what is N? and do I need to manually set random values in A[] and M[]? I didn't really understand that part" – SpoocyCrep Mar 25 '15 at 20:24
  • 1
    @pskink please post your own answer so I could ask you questions or join http://chat.stackoverflow.com/rooms/73778/discussion-between-spoocycrep-and-pskink – SpoocyCrep Mar 25 '15 at 20:31
  • @SpoocyCrep `A` and `w` are values that you need to choose... somehow. There is some math which you can use to calculate their values for an example shape (and I think it is quite beautiful); you should read up about Fourier Series and orthogonality of sinusoids. If you're not going to dig deeper into the math, I recommend that you pick random values which get smaller for larger `i`. `N` is a term which you need to pick - the higher it is, the "rougher" the shape can be, but then the more coefficients `A` and `w` you need to calculate. Good luck! – Andy Turner Mar 25 '15 at 21:39
  • @SpoocyCrep here http://pastebin.com/D3u8CmDY you have the solution not using bezier curves, your job is to join start & end points of the curve – pskink Mar 26 '15 at 07:59
  • @SpoocyCrep found out that Catmull-Rom slines are *WAY* better in smooth interpolation of random points, google "catmull rom spline" for more info, the result is much more **realistic** – pskink Mar 26 '15 at 11:58