Is there any ways around to find the index position of a curve, based on the current xPosition,
let's say I have a curve Item - MyCurve, which has 20k points and when the mouse moves I could get the mouse location & then I could get the x & y positions by simply using the following function.
double xPos=0, yPos=0;
this.zedGraphControl1.GraphPane.ReverseTransform(MouseLoc, out xPos, out yPos);
but I want to find the data points from the curve item, any suggestions...?
Thanks in advance....:)
Bear in mind that the following is only an approximation, it should be accurate especially when you the mouse gets closer to the point, but as you are looking at the mouse position you may not be directly on a point on your curve. It also assumes that your CurveItem Curve has points, and that they are evenly distributed.
double startPos = Curve.Points[0].X
double xStep = Curve.Points[Curve.NPts - 1].X / Curve.NPts;
int xIndex = (int)(xPos / xStep + startPos);
// Make sure it is in bounds
xIndex = xIndex < 0 ? 0 : xIndex > Curve.NPts - 1 ? Curve.NPts - 1 : xIndex;
OR you can use the following function:
CurveItem n_curve;
int index;
zedGraphControl1.GraphPane.FindNearestPoint(mousePt, out n_curve, out index);
But keep in mind that that will look for the nearest curve and the index of the nearest point within that curve.
If you are not concerned with using the positions programmatically, but only want to see the positions displayed in your graph, you can set zedGraphControl1.IsShowPointValues to true:
Related
I'm trying to find a solution for best performance.
I need to find closet point on multisegment line (List points) to given point.
My line have thousands of points and I need to check distance to this line few times per second. So solution need to be very fast.
Right now I have something like below. It works but it is going to be slow when line have 10000+ points.
Maybe someone have idea how to make it faster?
public static float GetSqrDistXZ(Vector3 a, Vector3 b)
{
Vector3 vector = new Vector3(a.x - b.x, 0, a.z - b.z);
return vector.sqrMagnitude;
}
public static Vector3 NearestPointOnFiniteLine(Vector3 start, Vector3 end, Vector3 pnt)
{
Vector3 line = (end - start);
float len = Mathf.Sqrt(line.sqrMagnitude);
line.Normalize();
Vector3 v = pnt - start;
float d = (v.x * line.x) + (v.z * line.z);
d = Mathf.Clamp(d, 0f, len);
return start + line * d;
}
int pointsCount = line.points3.Count - 1; // line - List<Vector3> points.
float[] distances = new float[pointsCount];
for (int i = 0; i < pointsCount+1; i++) {
if (i >= 1) {
distances [i - 1] = GetSqrDistXZ (point, NearestPointOnFiniteLine (line.points3 [i - 1], line.points3 [i], point));
}
}
int minListIndexLeft = System.Array.IndexOf (distances, Mathf.Min (distances));
float minimalDistance = distances[minListIndexLeft];
Vector3 closestPoint = NearestPointOnFiniteLine (line.points3[minListIndexLeft], line.points3[minListIndexLeft+1], point);
You'll want to think about space partitioning. In this example I'm going to assume a 2D space, but this works in 3D just as well. Also there are much better solutions like BSP trees and stuff, but we'll keep it simple here.
Imagine putting a grid over your 2D space. Every segment (distance between 2 points) of your line intersects with one or more cells of that grid. What you have to do is to store the intersecting segments for every cell. If your line does not change, you can do that in one single pass on startup, or even store that information statically in an Asset.
But once you have that information, all you have to do is calculate the cell that your point is inside and then only check the line segments that intersect with that specific cell or a number of direct neighbours (see below). This makes finding the closest point lightning fast in comparison.
If you play with this idea on a piece of paper you may come across cases where this solution does not yield the closest point, because it did not consider a neighboring cell that contained a closer point. The easiest way to solve this is the following approach:
1. Find cell C, which is the cell your point is in
2. Let cellRange = 0
3. Let point B be undefined
4. Find closest point P among all segments that intersect cell C and its neighboring cells of range cellRange*
5. If B is the same as newly found point P then P is the solution. You are done.
6. Increase cellRange by 1
7. Let B = P
8. Repeat from step 4
* "neighboring cells of range cellRange" means:
cellRange 0: only cell C, no neighbours
cellRange 1: cell C and direct neighbours
cellRange 2: cell C, direct neighbours and their direct neighbours
...
This solution basically checks if increasing the search range improves the solution. As soon as increasing the range did not improve the solution, you found the closest point.
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.
I'm trying to find out if a point (mouse click) is within the boundaries of a box based on the top left x/y and bottom right x/y of the box. The position could be positive or negative. As you move up, y value increases, as you move down, y decreases. As you move right, x value increases, as you move left, x decreases.
Vector2 positions could be negative or positive depending on where is clicked.
I thought this would simply work but it doesn't seem to like negative numbers. Any suggestions? My brain is fried tonight after doing Vector arithmetic all night on other things. I wish I was one of you who seem to understand this without problem. ;)
if(point.x >= topLeft.x && point.y <= topLeft.y &&
point.x <= bottomRight.x && point.y >= bottomRight.y)
{
// is within box
}
Edit
Here is how the top left and bottom right are calculated. As it turns out, the problem was not with the above but rather I forgot to add the position.y to the top left calculation below.
Vector2 topLeft = new Vector2(transform.position.x - (transform.localScale.x/2),
transform.position.y + (transform.localScale.y/2));
Vector2 bottomRight = new Vector2(transform.position.x + (transform.localScale.x/2),
transform.position.y - (transform.localScale.y/2));
For anyone coming across this thread, the above check is correct.
Example 1:
Example 2:
I think you've wrongly inverted the boolean expression. It's easier to check for all cases where the click is outside the box.
Semantically, a certain point is outside of a rectangle if it is:
Higher than the highest point of the rectangle
Lower than the lowestpoint of the rectangle
More left than the left side of the rectangle
More right than the right side of the rectangle
If one of these is true, it's outside the box.
if(
clickPosition.x < topLeft.x
||
clickPosition.x > bottomRight.x
||
clickPosition.y < bottomRight.y
||
clickPosition.y > topLeft.y
)
{
//Now you're sure the click was outside the box.
}
Why not using a Rectangle and then check if it contains the point?
var rectangle = new Rectangle(-100,0,100,-100);
if(rectangle.Contains(-25,-25))
{
// is within box
}
For the rest, it appears your code should work. Then there may be a problem with the the assignment of the values of point, topLeft and bottomRight.
the problem with the negative numbers is that your top left isn't your top left
if you say
topY = max(corner1y, corner2y, corner3y)
bottomY = min (corner1y, corner2y, corner3y)
after that your check will work fine again.
I believe you're using the wrong signs on the Y checks.
If your topleft is 50, 100 and the bottom right is 100, 50, then 80 (y) still must be between 50 and 100, it doesn't matter which direction your Y is moving in relation to the screen, as long as you're also inverting your definition of top left.
if(point.x >= topLeft.x && point.y >= topLeft.y && //flipped sign in the second condition
point.x <= bottomRight.x && point.y <= bottomRight.y) //flipped sign in the second condition
{
// is within box
}
If you're not inverting your definition of top left, your original code is correct even for negative numbers.
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 rectangle.
Its height (RH) is 400.
Its width (RW) is 500.
I have circle.
Its height (CH) is 10.
Its width (CW) is 10.
Its starting location (CX1, CY1) is 20, 20.
The circle has moved.
Its new location (CX2, CY2) is 30, 35.
Assuming my circle continues to move in a straight line.
What is the circle's location when its edge reaches the boundary?
Hopefully you can provide a reusable formula.
Perhaps some C# method with a signature like this?
point GetDest(size itemSize, point itemPos1, point itemPos2, size boundarySize)
I need to calculate what that location WILL be once it arrives - knowing that it is not there yet.
Thank you.
PS: I need this because my application is watching the accelerometer on my Windows Phone. I am calculating the target necessary to animate the motion of the circle inside the rectangle as the user is tilting their device.
It is 1 radius away from the boundar(y/ies).
The answer is X=270 Y=395
first define the slope V as dy/dx =(y2-y1)/(x2-x1). In your example: (35-20)/(30-20)=1.5
the line equation is
y = V * (x-x1) + y1. You are interested in the horizontal locations x at:
y= CH/2 OR y= H-CH/2
so (not code, just math)
if (y2-y1)<0:
x=(CH/2 -y1)/V +x1 10 for your example. OR
if (y2-y1)>0:
x=(H-CH/2 -y1)/V +x1 270 for your example
else (that is: y2==y1)
the upper or lower lines were not hit.
if CH/2 <= x <= W-CH/2 the circle did hit the that upper or lower side: since V>0, we use x=270 and that is within CH/2 and W-CH/2.
So the answer to your question is y=H-CH/2 = 395 , X=270
For the side lines it's similar:
(if (x2-x1)<0)
y=(CH/2 -x1)*V +y1
(if (x2-x1)>0)
y=(W-CH/2 -x1)*V +y1
else (that is: x2==x1)
the side lines were not hit.
if CH/2 <= y <= H-CH/2 the circle did hit that side at that y.
be careful with the trivial cases of completely horizontal or vertical movement so that you don't divide by zero. when calculating V or 1/V. Also deal with the case where the circle did not move at all.
Since you now asked, here's metacode which you should easily be able to convert to a real method. It deals with the special cases too. The input is all the variables you listed in your example. I here use just one symbol for the circle size, since it's a circle not an ellipse.
method returning a pair of doubles getzy(x1,y1,W,H,CH){
if (y2!=y1){ // test for hitting upper or lower edges
Vinverse=(x2-x1)/(y2-y1)
if ((y2-y1)<0){
xout=(CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=CH/2
return xout,yout
}
}
if ((y2-y1)>0){
xout=(H-CH/2 -y1)*Vinverse +x1
if (CH/2 <= y <= H-CH/2) {
yout=H-CH/2
return xout,yout
}
}
}
// reaching here means upper or lower lines were not hit.
if (x2!=x1){ // test for hitting upper or lower edges
V=(y2-y1)/(x2-x1)
if ((x2-x1)<0){
yout=(CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=CH/2
return xout,yout
}
}
if ((x2-x1)>0){
yout=(H-CH/2 -x1)*V +y1
if (CH/2 <= x <= W-CH/2) {
xout=H-CH/2
return xout,yout
}
}
}
// if you reach here that means the circle does not move...
deal with using exceptions or some other way.
}
It's easy; no calculus required.
Your circle has radius R = CW/2 = CH/2, since the diameter of the circle D = CW = CH.
In order to have the circle touch the vertical edge of the rectangle at a tangent point, you have to move the circle to the right by a distance (W - (CX1 + CW/2))
Likewise, the circle will touch the bottom edge of the rectangle at a tangent point when you move it down by a distance (H - (CY1 + CH/2)).
If you do this in two separate translations (e.g., first to the right by the amount given, then down by the amount given or visa versa), you'll see that the circle will touch both the right hand vertical and the bottom horizontal edges at tangent points.
When the moving circle arrives at a wall (boundary) then it will be tangent at one of four points on the circle, call them N, S, E, and W. You know their initial coordinates.
The points travel in a line with a slope known to you: m=(y2-y1)/(x2-x1); where in your example (x1, y1) - (20,20) and (x2, y2)= (30, 35).
Your problem is to find the trajectory of the first point N, S, E, or W which reaches any wall. The trajectory will be a line with slope m.
You can do this by adding (or subtracting) the direction vector for the line to the point N, S, E, or W, scaled by some t.
For example, N is (20, 15). The direction vector is (x2-x1,y2-y1) = (10, 15). Then (20, 15) + t * (10, 15) will hit the boundary lines at different t's. You can solve for these; for example 20 + t*10 = 0, and 20 + t*10 = 400, etc.
The t that is smallest in magnitude, over all four trajectories, gives you your tangent point.
Not sure its calculus..wouldn't it just be the following:
if y >= 390 then it reached the top edge of the rectangle
if x >= 490 then it reached the right edge of the rectangle
if y <= 0 then it reached the bottom edge of the rectangle
if x <= 0 then it reached the left edge of the rectangle