I have a triangle where two points have the same Z-Value and one has a different Value. Now I want to transform the point with the different Z-Value, so that it optically generates a "vertical" Triangle. Assuming point C is the one with the different height-Value, I somehow need to move the X and Y Coordinates of point C orthogonal to the Difference-Vector of A and B, until they vertically line up, e.g. the slope is exactly 90 degrees. But unfortunately, I am a complete idiot concerning rotations and stuff. Could you give me any hints how to solve that?
The code I need it for is written in C++, but a simple pseudo-code would be enough :)
But preferably a rather quick way, because it has to be called up to 700000 times per player, per chunk load
Let's say you have points A B C, and A.z == B.z, and z represents the vertical direction.
First, project the x,y co-ordinates of C onto the line between A and B in 2D:
// find normalized AB vector:
AB.x = B.x - A.x;
AB.y = B.y - A.y;
length = sqrt(AB.x * AB.x + AB.y * AB.y);
// test for length == 0 to avoid div by zero
AB.x /= length;
AB.y /= length; // note: you could save a division by dividing dot by length instead
// project C onto AB:
AC.x = C.x - A.x;
AC.y = C.y - A.y;
// this gives us how far along the line AB the projected point is:
dot = (AC.x * AB.x) * (AC.y * AB.y);
newC.x = A.x + (AB.x * dot);
newC.y = A.y + (AB.y * dot);
newC.z = A.z; // same as B.z
Next find the 3D distance between the projected point and C, which will be the vertical height above the AB line of the new point, if the triangle were rotated into a vertical position using AB as a hinge:
newCC.x = C.x - newC.x;
newCC.y = C.y - newC.y;
newCC.z = C.z - newC.z;
height = sqrt((newCC.x * newCC.x) + (newCC.y * newCC.y) + (newCC.z * newCC.z));
Set the z value:
newC.z += height;
Related
How can I check if a vector that starts at one point passes through another one point?
It is on two-dimensional coordinates.
Mainly uses c ++, but other languages are possible.
float2 startToTarget = target - start;
if ((startToTarget.x) * vec.y - (startToTarget.y) * vec.x >= -floatingPoint && (startToTarget.x) * vec.y - (startToTarget.y) * vec.x <= floatingPoint)
if ((startToTarget.x) * vec.x + (startToTarget.y) * vec.y >= -floatingPoint && (startToTarget.x) * vec.x + (startToTarget.y) * vec.y <= floatingPoint) intersecting = true;
Calculate cross product of vector d (direction) and AB vector. If result is zero, then these vectors are collinear, so B point lies on the line, defined by point A and direction vector d.
To check direction, evaluate also dot product, it's sign is positive, when direction d coincides with direction AB
abx = B.x - A.x;
aby = B.y - A.y;
//cross product //dot product
if (abs(abx*dy - aby*dx) < 1.0e-10 and abx*dx + aby*dy>0)
{B lies on the ray A+d}
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.
I am making a little game and I am now working on a "radar". Now to do this I need to find two points based off how much a point has rotated around a center point.
A is going to rotate around C.
As A rotates around C, B & D will move along with A and stay in the same "positions" based off of where A is.
So for example, if A rotates around C 90 degrees B & D would then move and be in this position
But I am not very good at trig, so I don't really know the math I would need in order to find B & D based off how much A has rotated around C.
How do i find B & D based off of how much A has rotated around C?
I would image the final math would look somewhat similar to this:
float * returnB(float * APoint, float * CPoint)
{
float B_Out[2];
//calculate where B is based off A & C
B_Out[0] = B_X;
B_Out[1] = B_Y;
return B_Out;
}
float B[2];
B[0] = returnB(A,C)[0];
B[1] = returnB(A,C)[1];
float * returnD(float * APoint, float * CPoint)
{
float D_Out[2];
//calculate where D is based off A & C
D_Out[0] = D_X;
D_Out[1] = D_Y;
return D_Out;
}
float D[2];
D[0] = returnD(A,C)[0];
D[1] = returnD(A,C)[1];
You can rotate a point (x, y) around the origin by performing a simple matrix multiplication, which gives the following equations for the transformed point (x0, y0):
x0 = x * cos(theta) - y * sin(theta);
y0 = x * sin(theta) + y * cos(theta);
So you know A's relative 2d position respect to C. Lets say it is (ax, ay).
If you cross product(0,0,1) with (ax, ay, 0) you will find relative position of D that will be something like (dx, dy, 0)
d = (dx, dy) is relative position of D.
b is also -d
https://en.wikipedia.org/wiki/Cross_product
So I am using a quaternion to create a segment of two points in 3D space, and trying to recompute a similar quaternion later on (one representing the same vector through space; I am aware that the segment's rotation around itself is undefined). I am creating the segment as such:
sf::Vector3<float> Start(0, 0, 0);
sf::Vector3<float> End = Start;
//Create a vector from the start to the end
sf::Vector3<float> Translation = Orientation.MultVect(sf::Vector3<float>(0, 1, 0));
//Add that vector onto the start position
End.x += Translation.x * Length;
End.y += Translation.y * Length;
End.z += Translation.z * Length;
Where Orientation::MultVect() looks like this:
sf::Vector3<float> Quaternion::MultVect(sf::Vector3<float> Vector)
{
//From http://www.idevgames.com/articles/quaternions
Quaternion VectorQuat = Quaternion();
VectorQuat.x = Vector.x;
VectorQuat.y = Vector.y;
VectorQuat.z = Vector.z;
VectorQuat.w = 0.0;
Quaternion Inverse = (*this);
Inverse.Invert();
Quaternion Result = Inverse * VectorQuat * (*this);
sf::Vector3<float> ResultVector;
ResultVector.x = Result.x;
ResultVector.y = Result.y;
ResultVector.z = Result.z;
return ResultVector;
}
Now this function seems to work rather well in other contexts, so I don't think the problem is here, but you never know. I should also mention that the point ends up where I expect it to, given the Quaternion I feed if (which I construct from Euler angles, sometimes with multiplication with other quaternions).
The problem appears, to me, to lie in recomputing the quaternion from Start and End. To do so, I use this function, which works well when orienting objects in the scene towards other objects (unless the objects in question are along the exact same Y axis, in which case I get quaternions with NaN values). Here is how I do that:
Quaternion Quaternion::FromLookVector(sf::Vector3<float> FromPoint, sf::Vector3<float> ToPoint)
{
///Based on this post:
///http://stackoverflow.com/questions/13014973/quaternion-rotate-to
//Get the normalized vector from origin position to ToPoint
sf::Vector3<double> VectorTo(ToPoint.x - FromPoint.x,
ToPoint.y - FromPoint.y,
ToPoint.z - FromPoint.z);
//Get the length of VectorTo
double VectorLength = sqrt(VectorTo.x*VectorTo.x +
VectorTo.y*VectorTo.y +
VectorTo.z*VectorTo.z);
//Normalize VectorTo
VectorTo.x /= -VectorLength;
VectorTo.y /= -VectorLength;
VectorTo.z /= -VectorLength;
//Define a unit up vector
sf::Vector3<double> VectorUp(0, -1, 0);
//The X axis is the cross product of both
//Get the cross product as the axis of rotation
sf::Vector3<double> AxisX(VectorTo.y*VectorUp.z - VectorTo.z*VectorUp.y,
VectorTo.z*VectorUp.x - VectorTo.x*VectorUp.z,
VectorTo.x*VectorUp.y - VectorTo.y*VectorUp.x);
//Normalize the axis
//Get the length of VectorTo
double AxisXLength = sqrt(AxisX.x*AxisX.x +
AxisX.y*AxisX.y +
AxisX.z*AxisX.z);
//Normalize VectorTo
AxisX.x /= AxisXLength;
AxisX.y /= AxisXLength;
AxisX.z /= AxisXLength;
//Get the adjusted Y vector
//Get the cross product of the other two axes
sf::Vector3<double> AxisY(VectorTo.y*AxisX.z - VectorTo.z*AxisX.y,
VectorTo.z*AxisX.x - VectorTo.x*AxisX.z,
VectorTo.x*AxisX.y - VectorTo.y*AxisX.x);
//Normalize the axis
//Get the length of VectorTo
double AxisYLength = sqrt(AxisY.x*AxisY.x +
AxisY.y*AxisY.y +
AxisY.z*AxisY.z);
//Normalize VectorTo
AxisY.x /= AxisYLength;
AxisY.y /= AxisYLength;
AxisY.z /= AxisYLength;
//A matrix representing the Thing's orientation
GLfloat RotationMatrix[16] = {(float)AxisX.x,
(float)AxisX.y,
(float)AxisX.z,
0,
(float)AxisY.x,
(float)AxisY.y,
(float)AxisY.z,
0,
(float)VectorTo.x,
(float)VectorTo.y,
(float)VectorTo.z,
0,
0,
0,
0,
1};
Quaternion LookQuat = Quaternion::FromMatrix(RotationMatrix);
//Reset the quaternion orientation
return LookQuat;
}
So when I compute the segments, I also check what their reconstructed values would be, like this:
sf::Vector3<float> Start(0, 0, 0);
sf::Vector3<float> End = Start;
//Create a vector from the start to the end
sf::Vector3<float> Translation = Orientation.MultVect(sf::Vector3<float>(0, 1, 0));
//Add that vector onto the start position
End.x += Translation.x * Length;
End.y += Translation.y * Length;
End.z += Translation.z * Length;
std::cout << "STATIC END (";
std::cout << End.x << ",";
std::cout << End.y << ",";
std::cout << End.z << ")\n";
///TEST
Quaternion Reconstructed = Quaternion::FromLookVector(Start, End);
Translation = Reconstructed.MultVect(sf::Vector3<float>(0, 1, 0));
sf::Vector3<float> TestEnd = Start;
TestEnd.x += Translation.x * Length;
TestEnd.y += Translation.y * Length;
TestEnd.z += Translation.z * Length;
std::cout << "RECONSTRUCTED END (";
std::cout << TestEnd.x << ",";
std::cout << TestEnd.y << ",";
std::cout << TestEnd.z << ")\n";
And the two don't match up. For example, if the static end point is (0,14.3998,0.0558498), then the recomputed point is (0,8.05585,-6.39976). The two should be identical, though. The undefined part of the rotation shouldn't change the position of the end point, only the roll (or Z-rotation, or whatever you want to call it), which, since this is a segment, doesn't matter.
Note that when I end up using this for things other than simple segments, the roll will matter, which is why I use an up vector to make sure the objects I place along these segments will always have their tops facing upwards as much as possible (objects looking straight up or down can have a special arbitrary roll determined separately, if need be). Another goal is creating multiple segments strung together, each rotating relative to the orientation of the one that came before it rather than rotating relative to global space.
So what am I doing wrong here? Why can't I recompute a second quaternion that performs the same translation as the first one?
I'm not entirely sure how you're calculating the 'rotating' quaternion between the two vectors, but I'm pretty sure it's very cumbersome. At least, if I understand you correctly, you have 'look' vectors which point in some direction, and the object 'looks' along that direction from the origin (0,0,0), correct?.
If the above is the case, it should not be too difficult. One thing I find quite peculiar though is that your quaternion - vector multiplication seems to be in reverse order. I have quaternion * vector defined as:
quat qt = *this * quat(0, vec.x, vec.y, vec.z) * inverse();
return vec3(qt.x, qt.y, qt.z);
In which the quat constructor is defined as quat(w, x, y, z) and the inverse() method returns a copy. Inverse is equal to conjugate, and it is defined as (w, -x, -y, -z). BUT, for this to be true your quaternions have to be normalized, only then will they actually represent an orientation (and only then will the inverse equal the conjugate). Then I have quaternion multiplication defined as follows:
// This describes A * B (not communative!)
w = A.w * B.w - A.x * B.x - A.y * B.y - A.z * B.z;
x = A.w * B.x + A.x * B.w + A.y * B.z - A.z * B.y;
y = A.w * B.y + A.y * B.w + A.z * B.x - A.x * B.z;
z = A.w * B.z + A.z * B.w + A.x * B.y - A.y * B.x;
With that out of the way, you want to be able to construct a quaternion from 'angle-axis'. Meaning it should take an axis of rotation, and an angle to rotate around that axis (in radians). I shall just give you that algorithm, as it doesn't make much sense intuitively:
// if axis is already unit length, remove the division
double halfAngle = angle * 0.5f; // In radians
double scale = sin(halfAngle) / axis.magnitude();
w = cos(halfAngle);
x = axis.x * scale;
y = axis.y * scale;
z = axis.z * scale;
So now we just have to calculate an axis to rotate around, and how much we want to rotate around it, in radians. At first sight this might seem complex, but it is just a case of understanding what is going on. You have two vectors, A and B. You want to calculate a quaternion which describes a rotation FROM A, TO B. To get the axis to rotate around, we just want a perpendicular axis to both, obviously this would be done by taking the cross product. If you're using a right handed coordinate system, it would be:
axis = A × B
If you're using a left handed coordinate system, I think you should just inverse the order, but don't take my word on that. Now to get the angle between the two vectors. This can very simply be done by taking the dot product. The only catch is that you have to normalize both vectors, so they have length 1, and won't alter the outcome of the dot product. This way the dot product will return the cosine of the angle, so to get the actual angle we can do:
angle = acos(normalize(A) * normalize(B))
The multiplication sign stands for the dot product of course. Now we just plug the axis and angle in the algorithm I gave you above, and we have a quaternion describing a 'rotation' from look vector A to look vector B. Now if the vectors point in the exact same direction, it would be unwise to apply the algorithm, as the axis will be (0,0,0). If you look at the algorithm I hope you see that will either try to divide by zero or simply output all zeros. So whenever I apply that algorithm I first check if the axis is not all zeros.
The formula you're currently using seems very strange and inefficient to me. I don't really understand why you're first computing a matrix either, computing a quaternion from a matrix is quite an expensive computation. In fact I believe computing the opposite, a matrix from a quaternion, is even faster.
Anyway, good luck getting it to work!
I have a 2D bitmap-like array of let's say 500*500 values. I'm trying to create a linear gradient on the array, so the resulting bitmap would look something like this (in grayscale):
(source: showandtell-graphics.com)
The input would be the array to fill, two points (like the starting and ending point for the Gradient tool in Photoshop/GIMP) and the range of values which would be used.
My current best result is this:
alt text http://img222.imageshack.us/img222/1733/gradientfe3.png
...which is nowhere near what I would like to achieve. It looks more like a radial gradient.
What is the simplest way to create such a gradient? I'm going to implement it in C++, but I would like some general algorithm.
This is really a math question, so it might be debatable whether it really "belongs" on Stack Overflow, but anyway: you need to project the coordinates of each point in the image onto the axis of your gradient and use that coordinate to determine the color.
Mathematically, what I mean is:
Say your starting point is (x1, y1) and your ending point is (x2, y2)
Compute A = (x2 - x1) and B = (y2 - y1)
Calculate C1 = A * x1 + B * y1 for the starting point and C2 = A * x2 + B * y2 for the ending point (C2 should be larger than C1)
For each point in the image, calculate C = A * x + B * y
If C <= C1, use the starting color; if C >= C2, use the ending color; otherwise, use a weighted average:
(start_color * (C2 - C) + end_color * (C - C1))/(C2 - C1)
I did some quick tests to check that this basically worked.
In your example image, it looks like you have a radial gradient. Here's my impromtu math explanation for the steps you'll need. Sorry for the math, the other answers are better in terms of implementation.
Define a linear function (like y = x + 1) with the domain (i.e. x) being from the colour you want to start with to the colour your want to end with. You can think of this in terms of a range the within Ox0 to OxFFFFFF (for 24 bit colour). If you want to handle things like brightness, you'll have to do some tricks with the range (i.e. the y value).
Next you need to map a vector across the matrix you have, as this defines the direction that the colours will change in. Also, the colour values defined by your linear function will be assigned at each point along the vector. The start and end point of the vector also define the min and max of the domain in 1. You can think of the vector as one line of your gradient.
For each cell in the matrix, colours can be assigned a value from the vector where a perpendicular line from the cell intersects the vector. See the diagram below where c is the position of the cell and . is the the point of intersection. If you pretend that the colour at . is Red, then that's what you'll assign to the cell.
|
c
|
|
Vect:____.______________
|
|
I'll just post my solution.
int ColourAt( int x, int y )
{
float imageX = (float)x / (float)BUFFER_WIDTH;
float imageY = (float)y / (float)BUFFER_WIDTH;
float xS = xStart / (float)BUFFER_WIDTH;
float yS = yStart / (float)BUFFER_WIDTH;
float xE = xEnd / (float)BUFFER_WIDTH;
float yE = yEnd / (float)BUFFER_WIDTH;
float xD = xE - xS;
float yD = yE - yS;
float mod = 1.0f / ( xD * xD + yD * yD );
float gradPos = ( ( imageX - xS ) * xD + ( imageY - yS ) * yD ) * mod;
float mag = gradPos > 0 ? gradPos < 1.0f ? gradPos : 1.0f : 0.0f;
int colour = (int)( 255 * mag );
colour |= ( colour << 16 ) + ( colour << 8 );
return colour;
}
For speed ups, cache the derived "direction" values (hint: premultiply by the mag).
There are two parts to this problem.
Given two colors A and B and some percentage p, determine what color lies p 'percent of the way' from A to B.
Given a point on a plane, find the orthogonal projection of that point onto a given line.
The given line in part 2 is your gradient line. Given any point P, project it onto the gradient line. Let's say its projection is R. Then figure out how far R is from the starting point of your gradient segment, as a percentage of the length of the gradient segment. Use this percentage in your function from part 1 above. That's the color P should be.
Note that, contrary to what other people have said, you can't just view your colors as regular numbers in your function from part 1. That will almost certainly not do what you want. What you do depends on the color space you are using. If you want an RGB gradient, then you have to look at the red, green, and blue color components separately.
For example, if you want a color "halfway between" pure red and blue, then in hex notation you are dealing with
ff 00 00
and
00 00 ff
Probably the color you want is something like
80 00 80
which is a nice purple color. You have to average out each color component separately. If you try to just average the hex numbers 0xff0000 and 0x0000ff directly, you get 0x7F807F, which is a medium gray. I'm guessing this explains at least part of the problem with your picture above.
Alternatively if you are in the HSV color space, you may want to adjust the hue component only, and leave the others as they are.
void Image::fillGradient(const SColor& colorA, const SColor& colorB,
const Point2i& from, const Point2i& to)
{
Point2f dir = to - from;
if(to == from)
dir.x = width - 1; // horizontal gradient
dir *= 1.0f / dir.lengthQ2(); // 1.0 / (dir.x * dir.x + dir.y * dir.y)
float default_kx = float(-from.x) * dir.x;
float kx = default_kx;
float ky = float(-from.y) * dir.y;
uint8_t* cur_pixel = base; // array of rgba pixels
for(int32_t h = 0; h < height; h++)
{
for(int32_t w = 0; w < width; w++)
{
float k = std::clamp(kx + ky, 0.0f, 1.0f);
*(cur_pixel++) = colorA.r * (1.0 - k) + colorB.r * k;
*(cur_pixel++) = colorA.g * (1.0 - k) + colorB.g * k;
*(cur_pixel++) = colorA.b * (1.0 - k) + colorB.b * k;
*(cur_pixel++) = colorA.a * (1.0 - k) + colorB.a * k;
kx += dir.x;
}
kx = default_kx;
ky += dir.y;
}
}