Drawing shaped based on points making sure lines don't cross - algorithm

say, I have 100 points and want to draw a closedcurve (I'm using C# and graphics), like this:
Graphics g = this.CreateGraphics();
Pen pen = new Pen(Color.Black, 2);
Point[] points = new Point[DrawingPoints];
for (int x = 0; x < DrawingPoints; x++)
{
int px = r.Next(0, MaxXSize);
int py = r.Next(0, MaxYSize);
Point p = new Point(px, py);
points[x] = p;
}
g.DrawClosedCurve(pen, points);
It is connecting points as they get into points[] and lines cross - you will not get a solid figure with this.
Is there an algorithm that will help me toss the points to get a solid figure? Here's a picture below (tried as hard as I could hehe) to help visualize what I'm asking for.

Well, in O(n log n) time, you could compute the centroid of the points and sort them in order of angle about that centroid, leaving a star-shaped polygon. That's efficient but probably messes up the order of your points too much.
I think you'd be happier with the results of a 2-OPT method for TSP (description here). 2-OPT is worst-case exponential but polynomial-time in practice.

Related

Creating cubic and/or quadratic Bezier curves to fit a path

I am working on a 2D game in Lua.
I have a path which is made up of a number of points, for example, points A to L:
I want to move an object smoothly along this path. To accomplish this, I wanted to create quadratic or cubic Bezier curves based on the points, and interpolate these curves. However, how do I fit the curves properly, such that the path isn't broken if eg. a curve stops and another starts in point F?
Curve fitting is explained in this question: How can I fit a Bézier curve to a set of data?
However, there is a must easier method to interpolate the points. It goes this way:
Refine: Place a point in the middle of each edge.
Dual: Place a point in the middle of each edge and remove the old points.
Repeat the Dual step several times.
Repeat from step one until the curve is smooth enough.
You can easily see that it works on paper. The resulting curve begins to approximate a series of bezier splines.
It is described more formally in this PDF file (Section 3): http://www.cc.gatech.edu/~jarek/courses/handouts/curves.pdf
Here is some Javascript code to do it:
function bspline_smooth(points, order) {
// insert a point in the middle of each edge.
function _refine(points) {
var i, index, len, point, refined;
points = [points[0]].concat(points).concat(points[points.length-1]);
refined = [];
index = 0;
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
refined[index * 2] = point;
if (points[index + 1]) {
refined[index * 2 + 1] = _mid(point, points[index + 1]);
}
index += 1;
}
return refined;
}
// insert point in the middle of each edge and remove the old points.
function _dual(points) {
var dualed, i, index, len, point;
dualed = [];
index = 0;
for (i = 0, len = points.length; i < len; i++) {
point = points[i];
if (points[index + 1]) {
dualed[index] = _mid(point, points[index + 1]);
}
index += 1;
}
return dualed;
}
function _mid(a, b) {
return new Point(
a.x + ((b.x - a.x) / 2),
a.y + ((b.y - a.y) / 2) );
}
if (!order) {
return points;
}
return bspline_smooth(_dual(_dual(_refine(points))), order - 1);
}
You don't need to know math to do this.
Connect each point with the next point with a separate Bezier curve.
Bezier curves have "handles" attached to their end points. These handles are tangent to the curve (at the end points). To make a "smooth" path all you need to do is make the handles of every two adjacent Bezier curves "sit" on one line.
To understand this, experiment with a drawing program like GIMP (but probably almost any other software will do). Such programs even have a special key to make the "handles" of adjacent curves sit on a straight line (and be of the same length).
The only "hard" mathematical decision you'll have to make is to determine the lengths of these handles. Experiment. You might want to make it dependent on how far each 3 consecutive points deviate from being on a straight line, or on the distance between the points.
Lastly, as for moving a point (your "object") along the curve at a seemingly constant speed: You can use an adaptation of a method like this one.

Need to make an efficient vector handling algorithm for gravity simulation

So I'm currently working on a Java Processing program where I want to simulate high numbers of particles interacting with collision and gravity. This obviously causes some performance issue when particle count gets high, so I try my best to optimize and avoid expensive operations such as square-root, otherwise used in finding distance between two points.
However, now I'm wondering how I could do the algoritm that figures out the direction a particle should move, given it only knows the distance squared and the difference between particles' x and y (dx, dy).
Here's a snip of the code (yes, I know I should use vectors instead of seperate x/y-couples. Yes, I know I should eventually handle particles by grids and clusters for further optimization) Anyways:
void applyParticleGravity(){
int limit = 2*particleRadius+1; //Gravity no longer applied if particles are within collision reach of eachother.
float ax, ay, bx, by, dx, dy;
float distanceSquared, f;
float gpp = GPP; //Constant is used, since simulation currently assumes all particles have equal mass: GPP = Gravity constant * Particle Mass * Particle Mass
Vector direction = new Vector();
Particle a, b;
int nParticles = particles.size()-1; //"particles" is an arraylist with particles objects, each storing an x/y coordinate and velocity.
for (int i=0; i<nParticles; i++){
a = particles.get(i);
ax = a.x;
ay = a.y;
for (int j=i+1; j<nParticles; j++){
b = particles.get(j);
bx = b.x;
by = b.y;
dx = ax-bx;
dy = ay-by;
if (Math.abs(dx) > limit && Math.abs(dy) > limit){ //Not too close to eachother
distanceSquared = dx*dx + dy*dy; //Avoiding square roots
f = gpp/distanceSquared; //Gravity formula: Force = G*(m1*m2)/d^2
//Perform some trigonometric magic to decide direction.x and direction.y as a numbet between -1 and 1.
a.fx += f*direction.x; //Adds force to particle. At end of main iteration, x-position is increased by fx/mass and so forth.
a.fy += f*direction.y;
b.fx -= f*direction.x; //Apply inverse force to other particle (Newton's 3rd law)
b.fy -= f*direction.y;
}
}
}
}
Is there a more accurate way of deciding the x and y pull strength with some trigonometric magic without killing performance when particles are several hundreds? Something I thought about was doing some sort of (int)dx/dy with % operator or so and get an index of a pre-calculated array of values.
Anyone have a clue? Thanks!
hehe, I think we're working on the same kind of thing, except I'm using HTML5 canvas. I came across this trying to figure out the same thing. I didn't find anything but I figured out what I was going for, and I think it will work for you too.
You want an identity vector that points from one particle to the another. The length will be 1, and x and y will be between -1 and 1. Then you take this identity vector and multiply it by your force scalar, which you're already calculating
To "point at" one particle from another, without using square root, first get the heading (in radians) from particle1 to particle2:
heading = Math.atan2(dy, dx)
Note that y is first, I think this is how it works in Java. I used x first in Javascript and that worked for me.
Get the x and y components of this heading using sin/cos:
direction.x = Math.sin(heading)
direction.y = Math.cos(heading)
You can see an example here:
https://github.com/nijotz/triforces/blob/c7b85d06cf8a65713d9b84ae314d5a4a015876df/src/cljs/triforces/core.cljs#L41
It's Clojurescript, but it may help.

How to convert an image to a Box2D polygon using the alpha layer and triangulation?

I'm coding a game using Box2D and SFML, and I'd like to let my users import their own textures to use as physics polygons. The polygons are created using the images' alpha layer. It doesn't need to be pixel perfect, and this is where my problem is. If it's pixel-perfect, it's going to be way too buggy when the player gets stuck between two rather complex shapes. I have a working edge-detection algorithm, and it produces something like this. It's pixel per pixel (and the shape it's tracing is simply a square with an dip). After that, I have a simplifying algorithm that produces this. It works fine to me, but if every single corner is traced like that, I'm going to have some problems. The code for the vector-simplifying is this:
//borders is a std::vector containing simple Box2D b2Vec2 (2D vector class containing an x and a y)
//vector shortener
for(unsigned int i = 0; i < borders.size(); i++)
{
int x = 0, y = 0;
int counter = 0;
//get the values for x and y that need to be added to check whether in a line or not
x = borders[i].x - borders[i-1].x;
y = borders[i].y - borders[i-1].y;
//while points are aligned..
while((borders[i].x + x*counter == borders[i + counter].x) && (borders[i].y + y*counter == borders[i+counter].y))
{
counter++;
}
if(counter-1 > i)
{
borders.erase(borders.begin() + i, borders.begin() + i + counter -1);
}
}
So my question is, how can I transform the previous set of vectors into something a bit less precise? Are there any rounding algorithms out there? If so, which is best? Any tips you can give me? It doesn't matter whether the resulting polygon is convex or concave, I'm triangulating it anyways.
Thanks,
AsterAlff

How do I calculate a line from a series of points?

Probably an easy question, but I could not find an easy solution so far. I'm working on a simple image recognition software for a very specific use case.
Given is a bunch of points that are supposedly on a straight line. However, some of the points are mistakenly placed and away from the line. Especially near the ends of the line, points may happen to be more or less inaccurate.
Example:
X // this guy is off
X // this one even more
X // looks fine
X
X
X // a mistake in the middle
X
X // another mistake, not as bad as the previous
X
X
X
X
X // we're off the line again
The general direction of the line is known, in this case, it's vertical. The actual line in the example is in fact vertical with slight diagonal slope.
I'm only interested in the infinite line (that is, it's slope and offset), the position of the endpoints is not important.
As additional information (not sure if it is important), it is impossible for 2 points to lie next to each other horizontally. Example:
X
X
X
X X // cannot happen
X
X
Performance is not important. I'm working in C#, but I'm fine with any language or just a generic idea, too.
I think you're looking for Least squares fit via Linear Regression
Linear regression (as mentioned by others) is good if you know you do not have outliers.
If you do have outliers, then one of my favorite methods is the median median line method:
http://education.uncc.edu/droyster/courses/spring00/maed3103/Median-Median_Line.htm
Basically you sort the points by the X values and then split the points up into three equal sized groups (smallest values, medium values, and largest values). The final slope is the slope of the line going through the median of the small group and through the median of the large group. The median of the middle group is used with the other medians to calculate the final offset/intercept.
This is a simple algorithm that can be found on several graphing calculators.
By taking the three medians, you are completely ignoring any outliers (either on the far left, far right, far up, or far down).
The image below shows the linear regression and median-median lines for a set of data with a couple of large outliers.
Mike is spot on! Use the following:
double[] xVals = {...};
double[] yVals = {...};
double xMean = 0;
double yMean = 0;
double Sxy = 0;
double Sxx = 0;
double beta0, beta1;
int i;
for (i = 0; i < xVals.Length; i++)
{
xMean += xVals[i]/xVals.Length;
yMean += yVals[i]/yVals.Length;
}
for (i = 0; i < xVals.Length; i++)
{
Sxy += (xVals[i]-xMean)*(yVals[i]-yMean);
Sxx += (xVals[i]-xMean)*(xVals[i]-xMean);
}
beta1 = Sxy/Sxx;
beta0 = yMean-beta1*xMean;
Use beta1 as the slope and beta0 as the y-intercept!

Datastructure and algorithm to detect collisions of irregular shaped moving objects

I came across this interview question
Many irregularly shaped objects are moving in random directions. Provide a data structure and algorithm to detect collisions. Remember that the number of objects is in the millions.
I am assuming that every object would have an x and y coordinate. Other assumptions are most welcome. Also a certain kind of tree should be used, I suppose, but I am clueless about the algorithm.
Any suggestions?
I would have a look at the Plane Sweep Algorithm or the Bently-Ottmann Algorithm. It uses plane sweep to determine in O(n log(n)) time (and O(n) space) the intersection of lines on a euclidian plane.
Most likely what you want is to sub-divide the plane with a space-filling-curve like a z-curve or a hilbert-curve and thus reducing the complexity of a 2D problem to a 1D problem. Look for quadtree.
Link: http://dmytry.com/texts/collision_detection_using_z_order_curve_aka_Morton_order.html
There are many solutions to this problem. First: Use bounding boxes or circles (balls in 3D). If the bounding boxes do not intersect then no further tests are needed. Second: Subdivide your space. You do not have to test every object against all other objects (that is O(n^2)). You can have an average complexity of O(n) with quadtrees.
I guess there should be a loop which takes reference of 1 object find co-ordinates and then checks with rest of all other objects to see if there is any collision. I am not sure how good my solution is for millions of objects.
Psuedo-code:
For each irregular shaped object1
int left1, left2;
int right1, right2;
int top1, top2;
int bottom1, bottom2;
bool bRet = 1; // No collision
left1 = object1->x;
right1 = object1->x + object1->width;
top1 = object1->y;
bottom1 = object1->y + object1->height;
For each irregular shaped object2
{
left2 = object2->x;
right2 = object2->x + object2->width;
top2 = object2->y;
bottom2 = object2->y + object2->height;
if (bottom1 < top2) bRet =0;
if (top1 > bottom2) bRet = 0;
if (right1 < left2) bRet = 0;
if (left1 > right2) bRet = 0;
}
return bRet;

Resources