I have a 2D map which wraps at the edges. So if you move off the right edge you will reappear at the left side of the map. Likewise with the three other edges.
This is inheritable a problem for the KDTree which I use to find elements in range of points. Normally you would check whether the hyper sphere collides with the hyper plane to see if you should continue searching the other side of the tree, but this check does not work with wrapping edges.
Is there any way to modify the KD Tree to work with donut 2D spaces?
The data structure doesn't have to change, but the search procedure does. Represent each point by coordinates (x, y) in [0, w) * [0, h), where w is the width of the map, h is the height, and * denotes a Cartesian product. Store these points in a normal KD tree.
The fundamental primitive for searching a KD tree is, given a point (x, y) and a rectangle [a, b] * [c, d], determine the distance (squared) from the point to the rectangle. Normally this is g(x, a, b)2 + g(y, c, d)2, where
g(z, e, f) = e - z if z < e
0 if e <= z <= f
z - f if f < z
is the one-dimensional distance of z to [e, f]. In a toroidal space, we modify g slightly to account for wraparound.
g(z, e, f, v) = min(e - z, (z + v) - f) if z < e
0 if e < z < f
min(z - f, (e + v) - z) if f < z.
and the distance squared is g(x, a, b, w)2 + g(y, c, d, h)2. I expect that the running times will be comparable for this variant. (I'd redo the recurrences, but the worst-case for regular KD trees is much worse than practice most of the time - O(n1/2) for identifying the nearest neighbor in 2D among n points.)
Jitamaro suggested but didn't explain a method based on a "2x size" quadtree. It's a reasonable suggestion, except the quadtree uses four times as many nodes rather than two, as I'll explain below before tentatively suggesting an alternative method.
Suppose each (x,y) coordinate has -.5 < x <= .5 and -.5 < y <= .5 and whenever j, k are integers, point (x+j,y+k) is identical with point (x,y). Let quadtree T cover points with coordinates in the range -1 < x,y <= 1. Each time you add an item at (x,y) to T, where -.5 < x,y <= .5, let x' = {x-1 if x>0 else x+1}, and y' = {y-1 if y>0 else y+1}. Also add the item at (x,y'), (x',y'), and (x',y). [When you delete points later, again calculate (x', y') et al and delete them too.] It's easy to see that nearest-point lookups will work properly, so long as any lookup coordinate outside interval (-.5,.5] is adjusted properly.
If the four-fold number of nodes is a deal-breaker, note that if coordinates as described above are used in subtrees above say level k=3, and relative coordinates are stored below level k, it should be possible to maintain single copies of subtrees below level k. That is, each subtree at level k would have four parents. (I haven't thought about this enough to know if this totally works; will edit answer if I find it doesn't.)
A quadtree is a KD-tree with 4 leafs. A quadtree doesn't help to wrap because its data structure is a wrap itself. You just need to use a quadtree 2x size of your structure.
Related
I have two 3D Points viz. (x1,y1,z1) and (x2,y2,z2) and a 3D Point (x,y,z).
I would like to know if (x,y,z) lies on the line connecting (x1,y1,z1) and (x2,y2,z2).
I tried the following algorithm:
if ((((x - x1) / x2-x1) == ((y - y1) / y2-y1)) && (((x - x1) / x2 - x1)
== ((z - z1) / z2- z1)) --> then,the 3D Line intersects (x,y,z)
But,what if my x1 = x2 (or) y1 = y2 (or) z1=z2? Then I would be getting an error saying "Division by zero" is not possible.
I would be glad,if someone can propose some alternative method.
Thanks in Advance.
I would use point-line distance measurement, and return true if the distance is less than some error threshold close to zero.
To elaborate, we are using a line made of two points, p1 and p2. We want to know if p3 is on the line. First we find d using the point-to-line distance formula.
d = ((p0 - p1).cross(p0 - p2)).length() / (p2 - p1).length()
That is, assuming you can use +, -, cross, length operations. You might prefer to find d squared for performance reasons.
d2 = ((p0 - p1).cross(p0 - p2)).lengthSquared() / (p2 - p1).lengthSquared()
Now, if d or d2 are exactly zero, then you must be on the line. But this is floating point arithmetic so I would allow a little bit of leeway depending on your application. So in essence, d < 1e6 or something should do the trick.
simple dot product can do this easily ... so let consider we got line defined by two points p0,p1. Any point p on that line will have the same or negative slope to any of the endpoints so
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) = 1.0
to make it more robust with floating point compare like this:
|dot(p1-p0,p-p0)|/(|p1-p0|*|p-p0|) >= 1.0-1e-10;
Where 1e-10 is small enough epsilon ... rewriten to code:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
q*=q;
q/=(dx*dx+dy*dy+dz*dz);
q/=(ex*ex+ey*ey+ez*ez);
if (q>=1.0-1e-10) point p(x,y) is on the line
else p(x,y) is not on line
As you can see no need for the sqrt we can compare the power instead ...
However you should handle edge case when p==p0 then either use p1 or return true right away.
In case you want points only inside the line segment (not outside the edge points) then you need a slight change in code
0.0 <= dot(p1-p0,p-p0)/|p-p0| <= 1.0
So:
dx=x1-x0;
dy=y1-y0;
dz=z1-z0;
ex=x-x0;
ey=y-y0;
ez=z-z0;
q =dx*ex;
q+=dy*ey;
q+=dz*zy;
if (q<0.0) p(x,y) is not on line
q*=q;
q/=(ex*ex+ey*ey+ez*ez);
if (q<=1.0) point p(x,y) is on the line
else p(x,y) is not on line
btw the result of the dot product gives you ratio of one vector projected to another perpendicularly or cos of the angle between them (if they are normalized) so for parallel vectors the result is 100% of length or 1.0. If you tweak the 1e-10 value using goniometry and p-p0 you can convert this to detect points up to some perpendicular distance to line (which might get handy for thick lines and or mouse selecting).
To solve the above-mentioned problem you need to check the area of the triangle considering them as 3 points in the 3-d space. To find the area go through this link. If area = 0 then given points are collinear.
if you are not concerned about performance issue you can use the parametric equation of a segment in the space.
P(t) = P0 + t(P1 - P0)
where P0 and P1 are 3d point and t is a parameter ranging from 0 to 1.
this lead to 3 equations
x(t) = x0 + t(x1 - x0)
y(t) = y0 + t(y1 - y0)
z(t) = z0 + t(z1 - z0)
so to check if your (x,y,z) point lies in the line, you could get an initial value for t, for example t = (x - x0)/(x1-x0) then check if that satisfies the other two equations
t = (x - x0)/(x1-x0)
if ( (y0 + t(y1-y0) == y) and (z0 + t(z1-z0) == z) ) then
---> we are in the line
Like #Jay pointed out, this is floating point math you have to deal with some tolerance with values. For example to test y could be y0 + t(y1-y0) - y < 0.001
As you yourself point out, doing this in a robust way is not trivial. Therefore, I suggest you don't reinvent the wheel and use a geometric library. I have good experience with using Wild Magic from geometrictools.com.
In your case, the predicate to use would be gte::DCPQuery to get the distance between a point and the line, and then test if it's close enough to zero for your purpose of "on the line."
An example of use could look like this:
using namespace gte;
Line3<double> line({x1, y1, z1}, {x2 - x1, y2 - y1, z2 - z1});
Vector3<double> point{x, y, z};
DCPPoint3Line3 query;
auto result = query(point, line);
bool pointIsOnLine = (result.distance < some_epsilon);
(Code note touched by compiler, intended to show the approach, not to be "semicolon-perfect").
I'm using C#, I have a list of Vector points and would like to try and approximate how close they look like a circle.
Any ideas how to implement this or if someone else has?
Based on the "gestures" tag I guess you not only want to know how close are these points to the smallest-circle (search for "Smallest-circle problem"), but you have to be concerned also about their order and spread:
I would start with the distance from the smallest-circle. If they are too far, you're done, it's not a circle.
If they are close enough to your configured threshold, compute the angle between the vector defined by the circle center, first point and each other point (picture bellow)
Check that each angle is greater than the previous.
Check that difference between any two angles next to each other is not over some configured threshold.
Check that the last point is close enough to the first one.
You will probably think of some other checks eventually, so make it simple to extend.
Another possibility:
Find the centroid
(http://en.wikipedia.org/wiki/Centroid#Of_a_finite_set_of_points) of
the points
Determine the distance (radius) of each point from the location of
the centroid
Calculate the distribution and determine if the points
are within acceptable tolerances (e.g. standard deviation < ±0.05 × mean radius or something like that)
Without knowing more about the source of the points, it's hard to suggest the best solution.
These might be of use: http://link.springer.com/article/10.1007%2FBF02276879#page-1 and http://www.dtcenter.org/met/users/docs/write_ups/circle_fit.pdf. Those methods will give you the best fitting circle through the points, but you are still going to need to determine whether your data points are close enough for your purposes.
UPDATE: based on the 'gesture' tag, somebody has already implemented it: http://depts.washington.edu/aimgroup/proj/dollar/
1) Pick any three points from that list, find the center of their appropriate circle
We can do this, using triangle circumcircle construction method, you find the medians of all three sides (two are sufficient) and their intersection is the center of the circle. Something like this:
public PointF findCenter(PointF a, PointF b, PointF c)
{
float k1 = (a.Y - b.Y) / (a.X - b.X) //Two-point slope equation
float k2 = (a.Y - c.Y) / (a.X - c.X) //Same for the (A,C) pair
PointF midAB = new PointF((a.X + b.X) / 2, (a.Y + b.Y) / 2) //Midpoint formula
PointF midAC = new PointF((a.X + c.X) / 2, (a.Y + c.Y) / 2) //Same for the (A,C) pair
k1 = -1*k1; //If two lines are perpendicular, then the product of their slopes is -1.
k2 = -1*k2; //Same for the other slope
float n1 = midAB.Y - k1*midAB.X; //Determining the n element
float n2 = midAC.Y - k2*midAC.Y; //Same for (A,C) pair
//Solve y1=y2 for y1=k1*x1 + n1 and y2=k2*x2 + n2
float x = (n2-n1) / (k1-k2);
float y = k1*x + n1;
return new PointF(x,y);
}
2) Check if the other points are equivalently distanced from this center, if yes, you have a circle, if no, you don't.
P.S. I haven't tested the code, so be prepared to debug. Ask if you need anything else
Take any three points from your point set.
If the points are co-linear then, your point set doesn't all lie on a circle.
Find the circumcircle of the triangle. The diameter is given by: d = (a*b*c)/2*area. The center of the circle is the point of intersection of the perpendicular bisectors of the three sides.
Now for every remaining point in the point set, if the distance from the center is not equal to the radius then the points are not on a circle. You can speed up the calculations by comparing the square of the radius against the square of the distance between the given point and the center.
How can i calulate a valid range (RED) for my object's (BLACK) traveling direction (GREEN). The green is a Vector2 where x and y range is -1 to 1.
What I'm trying to do here is to create rocket fuel burn effekt. So what i got is
rocket speed (float)
rocket direction (Vector2 x = [-1, 1], y = [-1, 1])
I may think that rocket speed does not matter as fuel burn effect (particle) is created on position with its own speed.
A cheap and cheerful trick with 2D vectors is to transpose the x and y, then flip the sign on one of them to get the perpendicular vector (pseudo code):
Vector2 perpendicular ( -original.y, original.x ) // Or original.y, -original.x
Then you could do something like:
direction + perpendicular * rand(-0.3 , 0.3)
Update: having realised the question asks for the opposite vector (too busy looking at the picture!) I figure I had better answer that too. Multiply 'direction' by -1 to get the opposite vector. So this:
perpendicular * rand(-0.3 , 0.3) - direction
should give you a random direction vector somewhere in your range (not normalised, but close enough for these purposes). Then you can multiply that result by a random number depending on how long you want the tail.
If to expend upon OlduwanSteve's answer, you can make is such that it's somewhat physically accurate.
You want to create several vectors that will represent the expulsion (the red lines).
First define the number of vectors you want to represent the expulsion with - lets mark it n.
You want to get a set of n numbers which sum up to Vx. These numbers will be the x components of the expulsion vectors. You can do this like so (semi-pseudo code):
SumX = Vx;
for (i = 0; i < n; i++)
{
Ax[i] = -rand(0..SumX); // Ax is the array of all expulsion vectors x components
SumX -= Ax[i];
}
Now you'll want to calculate Ay (the y components of the expulsion vectors). This is quite similar to calculating the, except that SumY = 0.
Here instead of splitting up SumY among n elements, you need to decide a maximal y component. Best way I can think of to select this is to define a maximal allowed angle for the expulsion vectors and define the maximal Vy using: maxVy = minVx*tan(maxAlpha).
Now you can get Ay using this (semi-pseudo code):
SumY = maxVy*2; // The actual range is (-maxVy, maxVy), but using (0, 2*maxVy) is simpler IMO
for (i = 0; i < n; i++)
{
Ay[i] = rand(0..SumY);
SumY -= Ay[i];
}
for (i = 0; i < n; i++)
{
Ay[i] -= maxVy; // Translate the range back to (-maxVy, maxVy) from (0, 2*maxVy)
}
Now you have arrays of both the x and y components of the expulsion vectors. Iterate over both arrays and pair up elements to create the vectors (you don't have to iterate both arrays in the same order).
Notes:
• I align the axes in my calculations such that X is parallel to the objects speed vector (the green line).
• The calculation for maxVy does NOT guarantee that a vector of angle maxAlpha will be produced, it only guarantees that no vector of larger angle will be.
• The lines Ay[i] = rand(0..SumY) and Ax[i] = -rand(0..SumX) may lead to vectors with components of size 0. This may lead to annoying scenarios, I'd recommend to handle away such cases (for instance "while rand returns zero, call it again").
I have a terrain, which is represented by elements and coordinates ( they are just a list of mesh), and I have a plane.
How to find the intersection between the plane and the terrain? Should I just break the plane up into a list of lines, and then use ray casting technique or other technique to compute the list of intersection, and join them up together? Or is there other ways of doing?
This question is a special case of my question here, in which I actually discretized the plane by breaking it into a lot of lines, and find the intersection points in order to get the lines where the plane intersect with the terrain, but I really wonder is there a better method.
define the plane using its implicit equation. Find a, b, c, and d so that ax + by + cz + d = 0 for all (x, y, z) on the plane
Go through every square that defines a segment of your terrain. Interpret the square as two separate triangles
For each vertex v1 = (x1, y1, z1), v2 = (x2, y2, z2), v3 = (x3, y3, z3) of a triangle, determine which side of the plane it lies on:
l1 = ax1 + by1 + c*z1 + d
l2 = ax2 + by2 + c*z2 + d
l3 = ax3 + by3 + c*z3 + d
Now there are two options.
either l1, l2, l3 are all > 0 or l1, l2, l3 are all < 0 - in that case the plane does not intersect the triangle and you have nothing to do.
or two of the l values are positive/negative and the third one is the opposite, e.g. l1>0, l2>0 and l3<0 - then the triangle edges v1-v3 and v2-v3 are being intersected
edge-plane intersection is easy to calculate. Assuming the v1-v2 edge is intersected:
xi = (x1*l1 - x2*l2)/(l1 - l2)
yi = (y1*l1 - y2*l2)/(l1 - l2)
zi = (z1*l1 - z2*l2)/(l1 - l2)
This way you will obtain a list of edges that correspond to intersection of the plane with your terrain. It is a slow method, but easy to explain... if you wanted to speed it up, you would need to use octrees or similar data structure to limit the amount of point/plane tests you need to do.
I'm trying to draw a vertical scrollbar for my G15 applet, but am having difficulty positioning it properly (if you haven't done anything for the G15 LCD screen, think of it as drawing on a 160x43 pixel image).
This is my current code for positioning:
perc = (float)Math.Round( range / Items.Count+1 );
y = ( perc * SelectedID+1 );
The upper edge of the scrollbar is at 5px from the top, the bottom edge is at 32px.
Y in this case would be the upper end of the scrollbar, and I'm using a length of 2 pixels; I did try to impliment a variable length bar, it went about as well as the code above.
SelectionID is 0 based.
All I need is the math to figure out the position, no need for code for drawing it.
Thanks.
So you're just after straightforward linear interpolation, right?
As in you have a value c in the range a..b and you need a resulting value in the range x..y based on its linear position between a and b?
The equation for this situation is (assuming the numbers in question are floats or doubles):
// c is between a and b
pos = (c-a)/(b-a) // pos is between 0 and 1
result = pos * (y-x) + x // result is between x and y
Now if everything is 0-indexed, you can omit a and x to get
pos = c/b
result = pos * y
If any of the numbers you're working with are integer types, you'll need to cast them to doubles or floats (or any real number type) before the divisions.
You can combine all of the equations together if you can't cast anything to doubles, though:
result = (c * y) / b
This will guarantee that c and y are multiplied together before the integer division takes place, which will reduce the error associated with integer division.