AS3 Calculating evenly distributed points on a line of points - actionscript-3

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?

Related

Force bezier loop to say inside boundary

I'm writing a code to simulate a lap time on motorcycle, using GNU Octave.
The racetrack is represented by the mid line (as x-y point values) and width "B".
The points of the racetrack midline are not at the same distance, for example a straight section have just two points, a bend could have 5-10 points.
The racing line is a closed loop cubic bezier.
I would like to calculate the distance of that bezier from the midline, to check if the vehicle goes off road (if distance > B/2 I'm out of track). I'm not interested in where this happens, only if happens.
Right now to check if the code works, I've made this by calculating the distance of every point of the racing line to the midline as the height of a triangle, where the two base vertex are two points of the mid line and the top vertex is the point of the racing line.
It works but I'm looking for an alternative method because this one is very slow.
As alternative I tought to "straighten" the mid line by calculating angle of each section, and then straighten the racing line with the same "transformation" and check min and max Y value, that must be less than B/2. The problem with this approach is that racing line and mid line are not the same length, in some part of racetrack racing line could be shorter, in other could be longer, so the transformation will not be linear.
Another option could be to transform the racetrack into a matrix filled with "0" inside track, "1" outside track, and the racing line will be a matrix with the same MxN filled with "0" everywhere and "1" where there is he racing line. By sum these two matrices, if there is some "2" I'm out of track. Right now I don't find a method to made this.
I've found the answer of my problem, using the function "inpolygon".
So, I set the outside boundary of racetrack as polygon, and all points of racing line as points to check. The function tell me if some point is outside the polygon.
Then, I repeat the same, setting inside boundary as polygon. Now all racing line points must be outside the polygon.

Random bezier blob?

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)

Distance between points on surface of cube

Let (x1, y1, z1) and (x2, y2, z2) be two points in Euclidian 3-space on the surface of an axis-aligned side-length-2 cube centered at the origin.
How do I efficiently compute the distance (or squared distance) between the points over the surface of the cube?
Internally, I represent points as (offset1, offset2, faceNumber) but an (x,y,z) format (as referenced above) is readily available.
I prefer C or Python code but I'll happily accept pseudocode or anything, really.
EDIT:
Some facts:
Shortest paths are always monotone in x, y, and z.
If the points are on the same face then it's trivially just Euclidian distance.
If the points are not on the same face, the shortest path could involve either 2 or 3 faces.
EDIT: What I would do, is turn the 3d cube into a 2d plane. The caveat is that, if the point is on the opposite side of the cube, you need to place the final surface on all ends of the cross.
If a cube had sides like this that you could fold around so that 4 touched side 1.
5
1 2 3 4
6
You would have a 2d plane that ultimately looked like this
3
4/5 5 5/2
3 4 1 2 3
4/6 6 2/6
3
So, I modified this. Now each of the corner panels represents the connections that can take place between both panels. When you initially lay out this array, each point on panels 2, 4, 5, and 6, will map to three points. The solution is then the shortest line to any of the given points, that represent point 2, in the event you need to map it to multiple points.
Mapping points from the 3d cube, to their initial 1 - 6 pains on the 2d graph is really quite simple. The only difficulty left is figuring out how to map points from the 2 plane, onto the "2/6" plane and so forth. This is just a matter of thinking through each situation. Ex: 2 -> 2/6 is different from 5 -> 5/2. My intuition is that it's either going to be 90 degree or -90 degree rotation, before shifting the width of the cube in the appropriate direction.
For example, to properly handle the situation you laid out we would have a value at the bottom left corner of plane one, and the bottom right corner of plane 2. After the following: '
points in plane 2/6 = rot90(points in plane 2) - width of the cube.
We will have a point in the bottom left corner of plane 2/6. This will then appropriately be the shortest path, and appropriately this path crosses the face of plane 6.

Rotate a circle around another circle

Short question: Given a point P and a line segment L, how do I find the point (or points) on L that are exactly X distance from P, if it guaranteed that there is such a point?
The longer way to ask this question is with an image. Given two circles, one static and one dynamic, if you move the dynamic one towards the static one in a straight line, it's pretty easy to determine the point of contact (see 1, the green dot).
Now, if you move the dynamic circle towards the static circle at an angle, determining the point of contact is much more difficult, (see 2, the purple dot). That part I already have done. What I want to do is, after determining the point of contact, decrease the angle and determine the new point of contact (see 3, 4, the red dot).
In #4, you can see the angle is decreased by less than half, and the new point of contact is half-way between the straight-line point and the original point. In #7, you can see the angle is bisected, but the new point of contact moves much farther than half way back towards the straight-line point.
In my case, I always want to decrease the angle to 5/6ths its original value, but the original angle and distance between the circles are variable. The circles are all the same radius. The actual data I need after decreasing the angle is the vector between the new center of the dynamic circle and the static circle, that is, the blue line in 3, 4, 6, and 7, if that makes the calculation any easier.
So far, I know I have to move the dynamic circle along the line that the purple circle is a center of, towards the center of the static circle. Then the circle has to move directly back towards the original position of the dynamic circle. The hard part is knowing exactly how far back it has to move so that it's just touching the other circle.
To answer your short question, if you are on the Cartesian plane, then find the equation of the line L is sitting on (given the two endpoints of L, this is simple). Find the equation of the perpendicular to said line, which passes through P (this is done by taking the negative inverse of the slope, plugging in P's x and y values, and solving for the intercept). Then find the point where the two perpendicular lines intersect by using their equations as a single system of equations (with x's and y's equal). Then find the distance between the point of intersection and the point P, which is one leg of a triangle. Finally, with that distance and the distance X you are given, use Pythagorean theorem to find the distance of the other leg of the triangle. Now the point you are looking for is a point on L, and also on the line on which L sits. So using the distance you just obtained, the intersection point you had found before, and the equation of L's line, you can find the desired point's coordinates. There can only be a maximum of 2 such points, so all you have to test for is whether the coordinates of the points found are actually on L, or beyond L but still on its line. Sorry for the long answer and if you wanted a geometric explanation rather than an algebraic one.
Draw a circle with the same centre as the stationary circle and the radius of the sum of both radii. There are two intersections with the translation line of the moving circle's centre. The place of the moving circle's center at the time of contact is the closer of those two intersections.
Let the ends of your segment be A and B, and the center of your stationary circle be C. Let the radius of both circles be r. Let the center of the moving circle at the moment of collision be D. We have a triangle ACD, of which we know: the distance AC, because it is constant, the angle DAC, because that's what you are changing, and the distance CD, which is exactly 2r. Theoretically, two sides and angle should let you get all the rest of a triangle...

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.