Random bezier blob? - actionscript-3

I have some ActionScript3 code I'm using to create liquid-like "droplets", and when they're first generated they look like a curved square (that's as close as I can get them to being a circle). I've tried and failed a lot here but my goal is to make these droplets look more organic and free-form, as if you were looking closely at rain drops on your windshield before they start dripping.
Here's what I have:
var size:int = (100 - asset.width) / 4,
droplet:Shape = new Shape();
droplet.graphics.beginFill(0xCC0000);
droplet.graphics.moveTo(size / 2, 0);
droplet.graphics.curveTo(size, 0, size, size / 2);
droplet.graphics.curveTo(size, size, size / 2, size);
droplet.graphics.curveTo(0, size, 0, size / 2);
droplet.graphics.curveTo(0, 0, size / 2, 0);
// Apply some bevel filters and such...
Which yields a droplet shaped like this:
When I try adding some randomness to the size or the integers or add more curves in the code above, I end up getting jagged points and some line overlap/inversion.
I'm really hoping someone who is good at math or bezier logic can see something obvious that I need to do to make my consistently rounded-corner square achieve shape randomness similar to this:

First off, you can get actual circle-looking cirles using beziers by using 0.55228 * size rather than half-size (in relation to bezier curves, this is sometimes called kappa). It only applies if you're using four segments, and that's where the other hint comes in: the more points you have, the more you can make your shape "creep", so you might actually want more segments, in which case it becomes easier to simply generate a number of points on a circle (fairly straight forward using good old sine and cosine functions and a regularly spaced angle), and then come up with the multi-segment Catmul-Rom curve through those points instead. Catmul-Rom curves and Bezier curves are actually different representations of the same curvatures, so you can pretty much trivially convert from one to the other, explained over at http://pomax.github.io/bezierinfo/#catmullconv (last item in the section gives the translation if you don't care about the maths). You can then introduce as much random travel as you want (make the upper points a little stickier and "jerk" them down when they get too far from the bottom points to get that sticky rain look)

Related

LibGDX guidance - sprite tracing 2D infinite random bezier curve

I've been able to apply a smooth animation to my sprite and control it using the accelerometer. My sprite is fixed to move left and right along the x-aixs.
From here, I need to figure out how to create a vertical infinite wavy line for the sprite to attempt to trace. the aim of my game is for the user to control the sprite's left/right movement with the accelerometer in an attempt to trace the never ending wavy line as best they can, whilst the sprite and camera both move in a vertical direction to simulate "moving along the line." It would be ideal if the line was randomly generated.
I've researched about splines, planes, bezier curves etc, but I can't find anything that seems to relate close enough to what I'm trying to achieve.
I'm just seeking some guidance as to what methods I could possibly use to achieve this. Any ideas?
You could use sum of 4 to 5 sine waves (each with different amplitude, wavelength and phase difference). All 3 of those parameters could be random.
The resulting curve would be very smooth (since it is primarily sinusoidal) yet it'll look random (it's time period would be LCM of all 4 to 5 random wavelengths which is a huge number).
So the curve won't repeat for a long time, yet it will not be hard on memory. Concerning computational complexity, you can always tune it by changing number of sine terms with FPS.
It should look like this.
It's really easy to implement too. (even I could generate above image.. haha)
Hope this helps. Maths rocks. :D
(The basic idea here is a finite Fourier series which I think should be ideal for your use case)
Edit:
You can create each term like this and assign random values to all terms.
public class SineTerm {
private float amplitude;
private float waveLength;
private float phaseDifference;
public SineTerm(float amplitude, float waveLength, float phaseDifference) {
this.amplitude = amplitude;
this.waveLength = waveLength;
this.phaseDifference = phaseDifference;
}
public float evaluate(float x) {
return amplitude * (float) Math.sin(2 * Math.PI * x / waveLength + phaseDifference);
}
}
Now create an array of SineTerms and add all values returned by evaluate(x) (use one coordinate of sprite as input). Use the output as other coordinate of sprite. You should be good to go.
The real trick would be in tuning those random numbers.
Good luck.

drawing a line: is there exists a limits of thickness in Graphics.lineStyle()?

I'm developing a simple a graphical editor for my flash-based app. In my editor there's a posibility of scaling, range of scaling is big (maximum scale is 16.0, minimum scale is 0.001 and default scale is 0.2). So it's quite possible that a user can draw a line with thickness 0.1 or 300.0, and it looks that line possible thickness (in Graphics.lineStyle()) has upper border. As I found out from livedocs maximum value is 255. So if thickness is greater then 255.0 there'is drawn a line of thickness 255.0. Whether mentioned upper border exists and how big is it. Here're my questions:
Right now I'm drawing lines with drawPath() or lineTo() methods. Natural walkarround if thickness is greater then 255.0 is to draw a rectange instead of segment and two circles on the ends of segment (instead of lineTo()). Or even to draw two thin segments and two half-circles and fill interior. Maybe there's more elegant/quick solution?
Another question is if the thickness of line is big but less then 255.0 (e.g. 100.0), what is faster drawing a line with lineTo() or drawing two thin segments and two half-circles and fill interior?
And finally, maybe someone knows a good article/book where I can read what's inside all methods of flash.display.Graphics class (or even not flash specific article/book on graphics)?
Any thoughts are appreciated. Thank you in advance!
I agree with f-a that putting the line in a container would probably be better and more efficient than drawing a rectangle and extra circles.
I don't think that the math would be too difficult to work out. For efficiency you should probably only do this if the line style is going to be over 255.
To setup the display object to hold your line I would start by halving the width of your line (the length can stay the same). Then create a new sprite and draw the line in the sprite at half size (e.g. if you wanted 300, just draw it at 150). It would be most simple to just start at (0,0) and draw the segment straight so that all of your transformations can be applied to the new sprite.
From here you can just double the scaleY of the sprite to get the desired line weight. It should keep the same length and the ends should also be rounded correctly.
Hope this helped out!
A cool resource for working with the graphics class is Flash and Math. This site has several cool effects and working examples and source code.
http://www.flashandmath.com/

AS3 Calculating evenly distributed points on a line of points

I have been tasked with trying to create a drawing tool that draws dotted lines as you drag the mouse across the stage. I can easily capture the points on MouseEvent.MOUSE_MOVE and store them in a vector and then draw the points as dots:
The problem is that I need to calculate evenly distributed points on an ever growing Vector of points so I can only draw the line between say every 5th point (say using modulus). I have been battling away with Bezier curve equations both Quadratic and Cubic but still can't quite figure out how to convert my Vector of points into an evenly distributed Vector of Points without sucking the life from the CPU.
Anyone help me? I see that George Profenza has come close to this one here on stack overflow...George?
hmm, I would try it like this: go over the points, calculate the distance between one and the next, keep track of the total distance, keep track of how many dots you placed already. Then, for each next point in the vector, see how many evenly distributed dots you would need to put between the new one and the last one and draw them on Bezier to make fancy, but straight should already be nice even.
example:
3 points in vector, total distance 22. distance per evenly distributed dot: 5. Hence, dots drawn on screen so far: 4. New point has distance 7 to last one, makes total distance 29. You need 5 points now (Math.floor(29/5)=5), you have 4, so you need to draw 1. Rest distance = 22 - 4*5 = 2. So then distance to do = 5-2 = 3. And 3 / distance between new and last point (9) = 0.333 -> so place this point on 1/3rd of the line between the new point in your vector and the last point. As in dot.x = seccondLastPoint.x + ((lastPoint.x - seccondLastPoint.x) * 0.333.
I'm pretty sure that will give you the desired result. Do you think you can build the code from this description?

Actionscript BlurFilter wrap around

I'm using the standard ActionScript blur filter to blur an image. The image will later be used as a texture map on a cylinder, i.e. it's left and right edges will meet in 3D. This looks bad because the blur filter has discontinuities at the image edges. I'd like to set it so it'll wrap around the image so that instead of truncating the filter kernel it'll do a modulo operation to get the pixel from the other end. Is that at all possible?
If not - what's the best way to write such functions yourself in ActionScript? I'd imagine using getPixel32 and setPixel32 would be prohibitively slow for larger images?
Option one: create an image extended by the radius of the blur. So you do something like buffer = new BitmapData(src.width + 2 * radius, src.height + 2 * radius, src.transparent, 0) then you draw the src onto the buffer with a translated matrix by radius. Like m = new Matrix() and then m.translate(radius, radius) and finally buffer.draw(src, m) now you just have to call buffer.applyFilter with new BlurFilter(radius, radius) and call copyPixels with new Rectangle(radius, radius, src.width, src.height) and you are done.
Option two: Use Adobe PixelBender if your blur radius does not change. You can write the modulo yourself and this should not be to hard.
Option three: Implement your own Gauss kernel -- this will never be as fast as option one but faster than option two since you can always buffer n-1 columns of the matrix for a blur and just calculate the n+1th colum. However you would use BitmapData.getVector to get a pixel buffer once instead of calling getPixel32 repeateadly.

Finding a free area in the stage

I'm drawing rectangles at random positions on the stage, and I don't want them to overlap.
So for each rectangle, I need to find a blank area to place it.
I've thought about trying a random position, verify if it is free with
private function containsRect(r:Rectangle):Boolean {
var free:Boolean = true;
for (var i:int = 0; i < numChildren; i++)
free &&= getChildAt(i).getBounds(this).containsRect(r);
return free;
}
and in case it returns false, to try with another random position.
The problem is that if there is no free space, I'll be stuck trying random positions forever.
There is an elegant solution to this?
Let S be the area of the stage. Let A be the area of the smallest rectangle we want to draw. Let N = S/A
One possible deterministic approach:
When you draw a rectangle on an empty stage, this divides the stage into at most 4 regions that can fit your next rectangle. When you draw your next rectangle, one or two regions are split into at most 4 sub-regions (each) that can fit a rectangle, etc. You will never create more than N regions, where S is the area of your stage, and A is the area of your smallest rectangle. Keep a list of regions (unsorted is fine), each represented by its four corner points, and each labeled with its area, and use weighted-by-area reservoir sampling with a reservoir size of 1 to select a region with probability proportional to its area in at most one pass through the list. Then place a rectangle at a random location in that region. (Select a random point from bottom left portion of the region that allows you to draw a rectangle with that point as its bottom left corner without hitting the top or right wall.)
If you are not starting from a blank stage then just build your list of available regions in O(N) (by re-drawing all the existing rectangles on a blank stage in any order, for example) before searching for your first point to draw a new rectangle.
Note: You can change your reservoir size to k to select the next k rectangles all in one step.
Note 2: You could alternatively store available regions in a tree with each edge weight equaling the sum of areas of the regions in the sub-tree over the area of the stage. Then to select a region in O(logN) we recursively select the root with probability area of root region / S, or each subtree with probability edge weight / S. Updating weights when re-balancing the tree will be annoying, though.
Runtime: O(N)
Space: O(N)
One possible randomized approach:
Select a point at random on the stage. If you can draw one or more rectangles that contain the point (not just one that has the point as its bottom left corner), then return a randomly positioned rectangle that contains the point. It is possible to position the rectangle without bias with some subtleties, but I will leave this to you.
At worst there is one space exactly big enough for our rectangle and the rest of the stage is filled. So this approach succeeds with probability > 1/N, or fails with probability < 1-1/N. Repeat N times. We now fail with probability < (1-1/N)^N < 1/e. By fail we mean that there is a space for our rectangle, but we did not find it. By succeed we mean we found a space if one existed. To achieve a reasonable probability of success we repeat either Nlog(N) times for 1/N probability of failure, or N² times for 1/e^N probability of failure.
Summary: Try random points until we find a space, stopping after NlogN (or N²) tries, in which case we can be confident that no space exists.
Runtime: O(NlogN) for high probability of success, O(N²) for very high probability of success
Space: O(1)
You can simplify things with a transformation. If you're looking for a valid place to put your LxH rectangle, you can instead grow all of the previous rectangles L units to the right, and H units down, and then search for a single point that doesn't intersect any of those. This point will be the lower-right corner of a valid place to put your new rectangle.
Next apply a scan-line sweep algorithm to find areas not covered by any rectangle. If you want a uniform distribution, you should choose a random y-coordinate (assuming you sweep down) weighted by free area distribution. Then choose a random x-coordinate uniformly from the open segments in the scan line you've selected.
I'm not sure how elegant this would be, but you could set up a maximum number of attempts. Maybe 100?
Sure you might still have some space available, but you could trigger the "finish" event anyway. It would be like when tween libraries snap an object to the destination point just because it's "close enough".
HTH
One possible check you could make to determine if there was enough space, would be to check how much area the current set of rectangels are taking up. If the amount of area left over is less than the area of the new rectangle then you can immediately give up and bail out. I don't know what information you have available to you, or whether the rectangles are being laid down in a regular pattern but if so you may be able to vary the check to see if there is obviously not enough space available.
This may not be the most appropriate method for you, but it was the first thing that popped into my head!
Assuming you define the dimensions of the rectangle before trying to draw it, I think something like this might work:
Establish a grid of possible centre points across the stage for the candidate rectangle. So for a 6x4 rectangle your first point would be at (3, 2), then (3 + 6 * x, 2 + 4 * y). If you can draw a rectangle between the four adjacent points then a possible space exists.
for (x = 0, x < stage.size / rect.width - 1, x++)
for (y = 0, y < stage.size / rect.height - 1, y++)
if can_draw_rectangle_at([x,y], [x+rect.width, y+rect.height])
return true;
This doesn't tell you where you can draw it (although it should be possible to build a list of the possible drawing areas), just that you can.
I think that the only efficient way to do this with what you have is to maintain a 2D boolean array of open locations. Have the array of sufficient size such that the drawing positions still appear random.
When you draw a new rectangle, zero out the corresponding rectangular piece of the array. Then checking for a free area is constant^H^H^H^H^H^H^H time. Oops, that means a lookup is O(nm) time, where n is the length, m is the width. There must be a range based solution, argh.
Edit2: Apparently the answer is here but in my opinion this might be a bit much to implement on Actionscript, especially if you are not keen on the geometry.
Here's the algorithm I'd use
Put down N number of random points, where N is the number of rectangles you want
iteratively increase the dimensions of rectangles created at each point N until they touch another rectangle.
You can constrain the way that the initial points are put down if you want to have a minimum allowable rectangle size.
If you want all the space covered with rectangles, you can then incrementally add random points to the remaining "free" space until there is no area left uncovered.