Average value from 2d space - c++

I'm currently working on a pice of software that interpolates data from existing measurements and makes estimates from this. The data is arranged in a 2D environment where we've got a wind speed on one axis and a wind angle on the other and each point represents a target speed.
For an example I've got three points:
p1: wind speed 6 knots, wind angle 90 degrees => target speed 5
p2: wind speed 6 knots, wind angle 70 degrees => target speed 6
p3: wind speed 8 knots, wind angle 70 degrees => target speed 7
Now I want to interpolate the point of wind speed 6 knots and wind angle 80 degrees. I would like an algorithm that uses all of these points and gives me an average of these three points.
Ages ago I made a 3D renderer and I think I used a technique there to color a polygon and I think this can be useful in this scenario. All the examples that I've found on the internet rely on OpenGL and such and that won't work for me as I want this solution to be pure c/c++ for an embedded environment. Since i run in an embedded environment I've got limited resources mainly in terms of program size.
Do any of you guys have any pointers to help me get past this problem? Thanks!

After diving into my old calculus i found a mathematical answer to this problem.
Given that I've got three points in the space I can form a plane:
P: (Px, Py, Pz)
Q: (Qx, Qy, Qz)
R: (Rx, Ry, Rz)
These points and the math described in here http://tutorial.math.lamar.edu/Classes/CalcIII/EqnsOfPlanes.aspx allowed me to move forward.
Vector(PQ) = (PQx, PQy, PQz)
Vector(PR) = (PRx, PRy, PRz)
Now I apply the cross product to these two vectors and this gives the normal vector of the plane
(Cross product math described here: http://tutorial.math.lamar.edu/Classes/CalcII/CrossProduct.aspx#Vectors_CrossProd_Ex2)
Vector(PQ) x Vector(PR) = Vector(PQy * PRz - PQz * PRy,
PQz * PRx - PQx * PRz,
PQx * PRy - PQy * PRx)
So, this is what I've got as a plane equation, without respect to that it has to pass trough one of the points:
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) = 0
To get the full equation of my plane that passes trough all of the points, I have to apply one point, as described in example 1 in the first link.
x(PQy * PRz - PQz * PRy) + y(PQz * PRx - PQx * PRz) + z(PQx * PRy - PQy * PRx) =
Px(PQy * PRz - PQz * PRy) + Py(PQz * PRx - PQx * PRz) + Pz(PQx * PRy - PQy * PRx)
To apply my example to this formula I get the following equation:
P: (90, 6, 5)
Q: (70, 6, 6)
R: (70, 8, 7)
Vector(PQ) = (20, 0, -1)
Vector(PR) = (20, -2, -2)
Cross product of these gives me this formula:
-2x + 20y - 40z = 0
If I now apply the point P to this I can get the full equatio of my plane:
-2x + 20y - 40z = -2 * 90 + 20 * 6 - 40 * 5
-2x + 20y - 40z = -260
z = (-2x + 20y + 260) / 40
As I seek the z value where x = 6 and y = 80 I put these values into the equation.
x = 80
y = 6
z = (-2 * 80 + 20 * 6 + 260) / 40
z = 5.5
5.5 is the expected answer for this example as it exactly in the middle of P and Q.
The final implementation of this algorithm:
float TargetSpeed::PlaneInterpolation(Point3D p, Point3D q, Point3D r, int x, int y)
{
Point3D pq = Point3D(p.X - q.X, p.Y - q.Y, p.Z - q.Z);
Point3D pr = Point3D(p.X - r.X, p.Y - r.Y, p.Z - r.Z);
Point3D n = Point3D(pq.Y * pr.Z - pq.Z * pr.Y,
pq.Z * pr.X - pq.X * pr.Z,
pq.X * pr.Y - pq.Y * pr.X);
float d = n.X * p.X + n.Y * p.Y + n.Z * p.Z;
float z = (d - n.X * (float)x - n.Y * (float)y) / n.Z;
return z;
}

Is the data on a regular grid? If so, I would just use something like linear interpolation. If not, then look at something like qhull.

Related

How to check if a point in a triangle (or on it's edge)

I'm trying to write an algorithm to determine if point is located inside a triangle or on it's edge in 3D coordinate space.
For example, I try to reach such results for different cases
I've figured out how to check if point P inside the triangle, I calculated normal vectors for triangles ABP, BCP, CAP and checked if they are similar.
Can someone explain how to check if a point is on the edge of a triangle (but not outside of a triangle)? You can provide formulas or code as you wish.
Make vectors:
r = p - A (r.x = p.x - A.x, r.y = p.y - A.y, r.z = p.z - A.z)
s = B - A
q = C - A
Calculate normal to ABC plane:
n = s x q (vector product)
Check if p lies in ABC plane using dot product:
dp = n.dot.r
If dp is zero (or has very small value like 1.0e-10 due to the floating point errors, then p is in the plane, and we can continue
Decompose vector p by base vectors s and q. At first check if z-component of normal (n.z) is non-zero. If so, use the next pair of equations (otherwise choose equations for x/z or y/z components):
px = a * sx + b * qx
py = a * sy + b * qy
Solve this system
a = (sy * qx - sx * qy) / (py * qx - px * qy)
b = (px - a * sx) / qx
If resulting coefficients a and b fulfill limits:
a >= 0
b >= 0
a + b <= 1.0
then point p lies in triangle plane inside it.

How to check if vectors are facing same direction

I am working on a question where I am working within a right-handed coordinate system where the y-axis is straight up. I am supplied a structure that represents a 3-dimensional vector that looks like this:
struct vec{float x; float y; float z; };
I need to write a function that takes in a unit vector representing north and a unit vector represent a player's forward vector, and return if they are facing more north than south. Unfortunatly I have no idea where to go from here, I believe I have to do something like:
PlayerDirection = sqrt((PlayerVector.x *= PlayerVector.x)
+ (PlayerVector.y *= PlayerVector.y)
+ (PlayerVector.z *= PlayerVector.z));
But I do not know where to go from here. Any help/explanation would help, thanks.
apply a dot product to both vectors. The dot product will be positive if the angle between both vectors is smaller than 90 degrees, and negative otherwise.
The formula you include (and which contains an error - the product is "*", not "*=") gives you the entity of the movement - the length of the vector. Which you already know, since it is a unit vector and therefore has length 1.
You need instead to perform the dot product between the two vectors. You get 1 if the two unit vectors are completely aligned (parallel), -1 if they're antiparallel, and zero if they're normal to each other.
"More north than south" means that the scalar product is positive, so:
return if they are facing more north than south
Alignment = ((PlayerVector.x * NorthVector.x)
+ (PlayerVector.y * NorthVector.y)
+ (PlayerVector.z * NorthVector.z));
return (Alignment > 0);
Questions
What if I wanted to tell if it was facing east/west?
The dot product tells you how much two vectors are aligned. It is the same formula shown by Kevin Glasson, without the unit vectors norms since they are 1, and dividing by one doesn't change anything.
So, you can't use it to tell where a vector is facing except in terms of another vector. And that's why you're given the north vector; with the player vector alone you can't run a dot product. To tell whether the player is facing east, you need the east vector (or the west vector, and then take the opposite sign).
So if the number comes back as say 35 it means it is facing more north than south but why?
Why it is so: you can find it explained on the Wikipedia page, the dot product is equal to the product of the two lengths by the cosine of their angle. Since the lengths are both 1, it is just the cosine. The cosine varies between 1 and -1 (so you can't ever get 35). When the cosine is 1, it means that the angle is zero and the vectors are aligned; when it is -1, they're opposite. A cosine of zero means the vectors are normal to each other, i.e. form an angle of 90°, and in this case it means that the player is facing either East, West, or Up, or Down - but it doesn't tell you which.
I think what would work is taking the 'dot product' of the vectors. Using the following form:
Where you would re-arrange for theta. This would give you the angle between the two vectors.
In my mind at least if the angle was 0 then you are pointing exactly north and if the angle were greater than 90 then you were facing more south.
I don't know exactly how you intend to use this, but this should work for being able to tell North from South in 3D space.
Well you can use the dot-product to get the angle between 2 vectors. The formula is the following:
cos(phi) = (a * b) / (|a|*|b|)
Which converts to this:
phi = acos((ax*bx + ay*by + az * bz) / (sqrt(ax^2 + ay^2 + az^2)+sqrt(bx^2 + by^2 + bz^2)))
Now the dot product is symmetric, meaning: (1,1,1)(2,2,2) gives you the same result as (2,2,2)(1,1,1). Hence you have to add a further step. By adding a third vector, whose angle to the first given vector you do know, you can verify the true angle between the two vectors. Optaining this reference vector can be done by turning the first vector arround an axis, now to ensure it is a valid reference it has to be in the same plane as the vectors a and b.
This means that your axis to turn your first vector arround has to be orthogonal to vector 1 and 2, the vectorproduct of 2 vectors gives a vector orthogonal to both, so we will use the so obtained vector as axis.
axis = a x b
This is equal to:
axis = (aybz-azby, azbx-axbz, axby-aybx)
To turn a vector by a given amount arround an axis the following has to be done:
double R[3][3] = {};
Vector axis = Axis.getUnitVector();
double deg = degrees / 180 * M_PI;
R[0][0] = axis.X * axis.X * (1 - cos(deg)) + cos(deg); R[0][1] = axis.X * axis.Y * (1 - cos(deg)) - axis.Z * sin(deg); R[0][2] = axis.X * axis.Z * (1 - cos(deg)) + axis.Y * sin(deg);
R[1][0] = axis.Y * axis.X * (1 - cos(deg)) + axis.Z * sin(deg); R[1][1] = axis.Y * axis.Y * (1 - cos(deg)) + cos(deg); R[1][2] = axis.Y * axis.Z * (1 - cos(deg)) - axis.X * sin(deg);
R[2][0] = axis.Z * axis.X * (1 - cos(deg)) - axis.Y * sin(deg); R[2][1] = axis.Z * axis.Y * (1 - cos(deg)) + axis.X * sin(deg); R[2][2] = axis.Z * axis.Z * (1 - cos(deg)) + cos(deg);
double x = this->X * R[0][0] + this->Y * R[0][1] + this->Z * R[0][2];
double y = this->X * R[1][0] + this->Y * R[1][1] + this->Z * R[1][2];
double z = this->X * R[2][0] + this->Y * R[2][1] + this->Z * R[2][2];
The unitvector is defined as following:
e_a = (ax / sqrt(ax^2+ay^2+az^2),ay / sqrt(ax^2+ay^2+az^2),az / sqrt(ax^2+ay^2+az^2))
Using this new axis we can rotate our first vector a 90°. By calculating the angle between our reference and our second vector we can now evaluate the real angle between the first and second vector. If the angle to the reference is bigger than 90° the 2nd vector is in the 3rd or 4th sector or a cartesian coordinate system, meaning to get the real angle we'll have to substract our aquired angle between the first and the 2nd vector from 360°. If the angle to the reference it is smaller than 90° the calculated angle is the real angle.
Now there is another issue, what/where is north? If we know north we could just calculate the angle between north and the two vectors and the one with the smaller angle would be more north. This means there is no reason to evaluate a reference vector or build and apply the rotation matrix.
In case of a fixed north you could also project your vectors on a plane containing north, and simplify the calculations required.
Provide more information and I will edit this.
edit:/ since you provide the north and a player vector, just calculate the angle between them.

line-width for ellipse is not constant

I am drawing hollow ellipse using opengl. I calculate vertices in c++ code using standard ellipse formula. In fragment shader i just assign color to each fragment. The ellipse that i see on the screen has thinner line width on the sharper curves as compared to that where curve is not that sharp. So question is, how to make line-width consistent across the entire parameter of ellipse? Please see the image below:
C++ code :
std::vector<float> BCCircleHelper::GetCircleLine(float centerX, float centerY, float radiusX, float radiusY, float lineWidth, int32_t segmentCount)
{
auto vertexCount = (segmentCount + 1) * 2;
auto floatCount = vertexCount * 3;
std::vector<float> array(floatCount);
const std::vector<float>& data = GetCircleData (segmentCount);
float halfWidth = lineWidth * 0.5f;
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
float sin = data [i * 2];
float cos = data [i * 2 + 1];
array [i * 6 + 0] = centerX + sin * (radiusX - halfWidth);
array [i * 6 + 1] = centerY + cos * (radiusY - halfWidth);
array [i * 6 + 3] = centerX + sin * (radiusX + halfWidth);
array [i * 6 + 4] = centerY + cos * (radiusY + halfWidth);
array [i * 6 + 2] = 0;
array [i * 6 + 5] = 0;
}
return std::move(array);
}
const std::vector<float>& BCCircleHelper::GetCircleData(int32_t segmentCount)
{
int32_t floatCount = (segmentCount + 1) * 2;
float segmentAngle = static_cast<float>(M_PI * 2) / segmentCount;
std::vector<float> array(floatCount);
for (int32_t i = 0; i < segmentCount + 1; ++i)
{
array[i * 2 + 0] = sin(segmentAngle * i);
array[i * 2 + 1] = cos(segmentAngle * i);
}
return array;
}
Aiming this:
The problem is likely that your fragments are basically line segments radiating from the center of the ellipse.
If you draw a line, from the center of the ellipse through the ellipse you've drawn, at any point on the perimeter, you could probably convince yourself that the distance covered by that red line is in fact the width that you're after (roughly, since you're working at low spatial resolution; somewhat pixelated). But since this is an ellipse, that distance is not perpendicular to the path being traced. And that's the problem. This works great for circles, because a ray from the center is always perpendicular to the circle. But for these flattened ellipses, it's very oblique!
How to fix it? Can you draw circles at each point on the ellipse, instead of line segments?
If not, you might need to recalculate what it means to be that thick when measured at that oblique angle - it's no longer your line width, may require some calculus, and a bit more trigonometry.
Ok, so a vector tangent to the curve described by
c(i) = (a * cos(i), b * sin(i))
is
c'(i) = (- a * sin(i), b * cos(i))
(note that this is not a unit vector). The perpendicular to this is
c'perp = (b * cos(i), a * sin(i))
You should be able to convince yourself that this is true by computing their dot product.
Lets calculate the magnitude of c'perp, and call it k for now:
k = sqrt(b * b * cos(i) * cos(i) + a * a * sin(i) * sin(i))
So we go out to a point on the ellipse (c(i)) and we want to draw a segement that's perpendicular to the curve - that means we want to add on a scaled version of c'perp. The scaling is to divide by the magnitude (k), and then multiply by half your line width. So the two end points are:
P1 = c(i) + halfWidth * c'perp / k
P2 = c(i) - halfWidth * c'perp / k
I haven't tested this, but I'm pretty sure it's close. Here's the geometry you're working with:
--
Edit:
So the values for P1 and P2 that I give above are end-points of a line-segment that's perpendicular to the ellipse. If you really wanted to continue with just altering the radiusX and radiusY values the way you were doing, you could do this. You just need to figure out what the 'Not w' length is at each angle, and use half of this value in place of halfWidth in radiusX +/- halfWidth and radiusY +/- halfwidth. I leave that bit of geometry as an exercise for the reader.

OpenGL - Creating a circle, change radius?

I must be the worst person on the planet when it comes to math because i can't figure out how to change this circle radius:
from math import *
posx, posy = 0,0
sides = 32
glBegin(GL_POLYGON)
for i in range(100):
cosine=cos(i*2*pi/sides)+posx
sine=sin(i*2*pi/sides)+posy
glVertex2f(cosine,sine)
I'm not entirely sure how or why this becomes a circle because the *2 confuses me a bit.
Note that this is done in Pyglet under Python2.6 calling OpenGL libraries.
Followed Example 4-1: http://fly.cc.fer.hr/~unreal/theredbook/chapter04.html
Clarification: This works, i'm interested in why and how to modify the radius.
This should do the trick :)
from math import *
posx, posy = 0,0
sides = 32
radius = 1
glBegin(GL_POLYGON)
for i in range(100):
cosine= radius * cos(i*2*pi/sides) + posx
sine = radius * sin(i*2*pi/sides) + posy
glVertex2f(cosine,sine)
But I would pick another names for variables. cosine and sine is not exactly what these variables are.
And as far as I see, you son't need a loop from 1 to 100 (or from 0 to 99, I'm not too good at Python), you just need a loop from 1 to sides.
Explanation:
When you calculate
x = cos (angle)
y = sin(angle)
you get a point on a circle with radius = 1, and centre in the point (0; 0) (because sin^2(angle) + cos^2(angle) = 1).
If you want to change a radius to R, you simply multiply cos and sin by R.
x = R * cos (angle)
y = R * sin(angle)
If you want to transfer the circle to another location (for example, you want the circle to have it's centre at (X_centre, Y_centre), you add X_centre and Y_xentre to x and y accordingly:
x = R * cos (angle) + X_centre
y = R * sin(angle) + Y_centre
When you need to loop through N points (in your case N = sides) on your circle, you should change the angle on each iteration. All those angles should be equal and their sum should be 2 * pi. So each angle should be equal to 2 * pi/ N. And to get i-th angle you multiply this value by i: i * 2 * pi / N.
math : P=pr^2=p*r*r= p*r*2 programming i*2*pi/sides
together : i = p i*2, *2=r^2 this should help you

Finding Y given X on a Cubic Bezier Curve?

I need a method that allows me to find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate.
I've come across lots of places telling me to treat it as a cubic function then attempt to find the roots, which I understand. HOWEVER the equation for a Cubic Bezier curve is (for x-coords):
X(t) = (1-t)^3 * X0 + 3*(1-t)^2 * t * X1 + 3*(1-t) * t^2 * X2 + t^3 * X3
What confuses me is the addition of the (1-t) values. For instance, if I fill in the X values with some random numbers:
400 = (1-t)^3 * 100 + 3*(1-t)^2 * t * 600 + 3*(1-t) * t^2 * 800 + t^3 * 800
then rearrange it:
800t^3 + 3*(1-t)*800t^2 + 3*(1-t)^2*600t + (1-t)^3*100 -400 = 0
I still don't know the value of the (1-t) coefficients. How I am I supposed to solve the equation when (1-t) is still unknown?
There are three common ways of expressing a cubic bezier curve.
First x as a function of t
x(t) = sum( f_i(t) x_i )
= (1-t)^3 * x0 + 3*(1-t)^2 * t * x1 + 3*(1-t) * t^2 * x2 + t^3 * x3
Secondly y as a function of x
y(x) = sum( f_i(x) a_i )
= (1-x)^3 * y0 + 3*(1-x)^2 * x * y1 + 3*(1-x) * x^2 * y2 + x^3 * y3
These first two are mathematically the same, just using different names for the variables.
Judging by your description "find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate on it." I'm guessing that you've got a question using the second equation are are trying to rearrange the first equation to help you solve it, where as you should be using the second equation. If thats the case, then no rearranging or solving is required - just plug your x value in and you have the solution.
Its possible that you have an equation of the third kind case, which is the ugly and hard case.
This is both the x and y parameters are cubic Beziers of a third variable t.
x(t) = sum( f_i(t) x_i )
y(t) = sum( f_i(t) y_i )
If this is your case. Let me know and I can detail what you need to do to solve it.
I think this is a fair CS question, so I'm going to attempt to show how I solved this. Note that a given x may have more than 1 y value associated with it. In the case where I needed this, that was guaranteed not to be the case, so you'll have to figure out how to determine which one you want.
I iterated over t generating an array of x and y values. I did it at a fairly high resolution for my purposes. (I was looking to generate an 8-bit look-up table, so I used ~1000 points.) I just plugged t into the bezier equation for the next x and the next y coordinates to store in the array. Once I had the entire thing generated, I scanned through the array to find the 2 nearest x values. (Or if there was an exact match, used that.) I then did a linear interpolation on that very small line segment to get the y-value I needed.
Developing the expression further should get you rid of the (1 - t) factors
If you run:
expand(800*t^3 + 3*(1-t)*800*t^2 + 3*(1-t)^2*600*t + (1-t)^3*100 -400 = 0);
In either wxMaxima or Maple (you have to add the parameter t in this one though), you get:
100*t^3 - 900*t^2 + 1500*t - 300 = 0
Solve the new cubic equation for t (you can use the cubic equation formula for that), after you got t, you can find x doing:
x = (x4 - x0) * t (asuming x4 > x0)
Equation for Bezier curve (getting x value):
Bx = (-t^3 + 3*t^2 - 3*t + 1) * P0x +
(3*t^3 - 6*t^2 + 3*t) * P1x +
(-3*t^3 + 3*t^2) * P2x +
(t^3) * P3x
Rearrange in the form of a cubic of t
0 = (-P0x + 3*P1x - 3*P2x + P3x) * t^3+
(3*P0x - 6*P1x + 3*P2x) * t^2 +
(-3*P0x + 3*P1x) * t +
(P0x) * P3x - Bx
Solve this using the cubic formula to find values for t. There may be multiple real values of t (if your curve crosses the same x point twice). In my case I was dealing with a situation where there was only ever a single y value for any value of x. So I was able to just take the only real root as the value of t.
a = -P0x + 3.0 * P1x - 3.0 * P2x + P3x;
b = 3.0 * P0x - 6.0 * P1x + 3.0 * P2x;
c = -3.0 * P0x + 3.0 * P1x;
d = P0x;
t = CubicFormula(a, b, c, d);
Next put the value of t back into the Bezier curve for y
By = (1-t)^3 * P0x +
3t(1-t)^2 * P1x +
3t^2(1-t) * P2x +
t^3 * P3x
So I've been looking around for some sort of method to allow me to find the Y-coordinate on a Cubic Bezier Curve, given an x-coordinate on it.
Consider a cubic bezier curve between points (0, 0) and (0, 100), with control points at (0, 33) and (0, 66). There are an infinite number of Y's there for a given X. So there's no equation that's going to solve Y given X for an arbitrary cubic bezier.
For a robust solution, you'll likely want to start with De Casteljau's algorithm
Split the curve recursively until individual segments approximate a straight line. You can then detect whether and where these various line segments intercept your x or whether they are vertical line segments whose x corresponds to the x you're looking for (my example above).