Sphere texturing and poles - c#

I use Managed DirectX with C# to texture a sphere (Mesh.Sphere).
I use the following code to calculate U and V:
CustomVertex.PositionNormalTextured[] vertData = (CustomVertex.PositionNormalTextured[])tempMesh.VertexBuffer.Lock(0, typeof(CustomVertex.PositionNormalTextured), LockFlags.None, tempMesh.NumberVertices);
for (int i = 0; i < vertData.Length; ++i)
{
vertData[i].Tu = (float)(1.0 - (double)(0.5f + Math.Atan2(vertData[i].Nz, vertData[i].Nx) / (Math.PI * 2)));
vertData[i].Tv = (float)(0.5 - Math.Asin(vertData[i].Ny) / Math.PI);
}
Now I have the problem, that the poles of the sphere and the poles of my texture (equirectangular projection) does not match.
The red points in the picture are the place where the poles of the sphere currently match the texture.
Can someone tell me what I can do to fix this problem?

Your above code works perfectly provided the sphere is centered at the origin and y is up. I will demonstrate:
Applying the maths with the assumption that poles exist at 0, 1, 0 and 0, -1, 0 gives the following numbers of the poles.
u = 1.0 - (0.5 + (atan2( 0, 0 ) / (2 * PI));
=> u = 1.0 - (0.5 + (0 / (2 * PI));
=> u = 1.0 - 0.5;
=> u = 0.5
v = 0.5 - (asin( 1 ) / PI)
=> v = 0
and
u = 0.5
v = 0.5 - (asin( -1 ) / PI)
=> v = 0.5 - -0.5
=> v = 1.0
Which are the correct values, for u and v, ie (0.5, 0) and (0.5, 1).
If you are using z-up then this WILL give incorrect values (as you would need to swap the y and z over in your calculations) but it still does not give the pole values you are suggesting:
u = 1.0 - (0.5 + (atan2( 1, 0 ) / (2 * PI));
=> u = 1.0 - (0.5 + (PI / (2 * PI)))
=> u = 1.0 - (0.5 + 0.5);
=> u = 0
v = 0.5 - (asin( 0 ) / PI)
=> v = 0.5 - (0 / PI)
=> v = 0.5
and
u = 1.0 - (0.5 + (atan2( -1, 0 ) / (2 * PI));
=> u = 1.0 - (0.5 + (-PI / (2 * PI)))
=> u = 1.0 - (0.5 - 0.5);
=> u = 1.0
v = 0.5 - (asin( 0 ) / PI)
=> v = 0.5 - (0 / PI)
=> v = 0.5
The reason for this is fairly sensible. In the u direction the sphere wraps entirely round. ie a u of 0 is the same as a u of 1. This happens entirely in the x-z plane in the equation you have posted (y is not considered for u). This is why it is divided by 2 * pi or the number of radians in a full circle. The v direction does not wrap around. In fact it only applies to half the range and thus a division pi. You'll note that only y is used in the calculation and, hence, x and z do not affect the v calculation.
Hope that helps.

Related

Get Vector2 that has distance x to two vectors

I want to calculate the Position(s) that have the same distance to PositonA and PositionB.
Example:
PositionA: (3,2)
PositionB: (5,4)
Distance: 5
If I'm not mistaken there are two possibilities, but I don't know how to calculate either mathematically.
Update:
Based on mrk's answer, I adapted the question, although it was not clear to me before that it is then a circle in three-dimensional space. Thank you very much for that.
I have added an image to clarify the two-dimensional variant.
The goal is to calculate the best escape route based on the positions of the two attackers. In this example the distance is fixed at 5, but later variable.
From your conditions you get three equations with three variables (X,
Y, Z) that are the coordinates of the points P for which the conditions
hold. Based on your points A (A1, A2, A3) and B (B1, B2, B3).
The first equation reflects the fact, that the Point P has the same distance to both A and B
Math.Pow(X - A1, 2) + Math.Pow(Y - A2, 2) = Math.Pow(X - B1, 2) + Math.Pow(Y - B2, 2)
The second equations reflects the fact, that the Point P has a distance d (= 5) from Point A
Math.Pow(X - A1, 2) + Math.Pow(Y - A2, 2) + Math.Pow(Z, 2) = Math.Pow(d, 2)
The second equations reflects the fact, that the Point P has a distance d (= 5) from Point B
Math.Pow(X - B1, 2) + Math.Pow(Y - B2, 2) + Math.Pow(Z, 2) = Math.Pow(d, 2)
This leaves you with a system of quadratic equations. You can now solve it by either solving equation 1 for X and inserting into equation 2 and solving this equation for Y then inserting the terms for X and Y into equation 3, in this manner you can solve for Z. Now you go the same way back, inserting the solution for Z in equation 2 and solving for Y and finally inserting the solution for Y and Z in equation 1 solving for X. (This might sound confusing at first, here is a more detailed description of the approach with an easier hands-on example)
An example how a system of quadratic equations is solved in C# can be found here.
Note:
The distance of 5 can be thought of as a sphere around your points A and B. In 2D this would result in 2 solutions where the circles cross each other. In 3D, as you can see in the picture, this will result in an infinite number of possible solutions, since the 2 spheres overlap, resulting in a circle.
This might help you to choose an appropriate approach to your task, since you will need to add at least one more condition to get the specific coordinates of a point.
Update:
The task now changed to finding the best escape route, given two
attackers. One on either side of our player.
Without caring much about the values of the distances, it is obvious, that we want to escape orthogonal to the connection of Attacker 1 (A) and Attacker 2 (B), to maximize the distance to both:
The vector for the escape route is thus given by the scalar product:
(A1-B1) * (X-0.5*(B1-A1)) + (A2-B2) * (Y-0.5*(B2-A2)) = 0
Since we only care about the direction to escape you can set X or Y as you like and solve for the other variable.
In case you do care, introduce a second equation that includes the condition you care about, such as length of your new vector and solve for both X and Y
With the help of mrk's answer the result given in the form of C# and less mathematics.
public static Vector2 GetEscapeVector(this float distance, Vector2 one, Vector2 two)
{
var center = (one + two) / 2;
// rotate by 90° which equals to 1.5708F radians
var rotated = Vector2.Transform(center, Matrix3x2.CreateRotation(1.5708F));
var escapeVector = Vector2.Normalize(rotated) * distance;
return escapeVector;
}
Is later used like this:
currentPosition + 20F.GetEscapeVector(one, two)
or
currentPosition - 20F.GetEscapeVector(one, two)
Pythagorean theorem:
The squared distance of a point (x,y,z) to PositionA is
(x-3)² + (y-2)² + z²
Similarly, the squared distance to PositionB is
(x-5)² + (y-4)² + z²
You know that both are equal to 5²
Can you take it from there?
If your problem is limited to 2D this method does what you're looking for:
private Tuple<PointF, PointF> SameDistancePoints(PointF p1, PointF p2, float distance)
{
// Calculate the coefficients for the equation
// x^2 + y^2 + a1x + b1y + c = 0
// which represents the circle of all the points that are at distance d from p1:
// (x-p1.X)^2 + (y-p1.Y)^2 = distance^2
// which is
// x^2 -2p1.X*x + (p1.X)^2 + y^2 -2p1.Y*y + (p1.Y)^2 - distance^2 = 0
float a1 = -2 * p1.X;
float b1 = -2 * p1.Y;
float c1 = (float)Math.Pow(p1.X, 2) + (float)Math.Pow(p1.Y, 2) - (float)Math.Pow(distance, 2);
// do the same for p2
float a2 = -2 * p2.X;
float b2 = -2 * p2.Y;
float c2 = (float)Math.Pow(p2.X, 2) + (float)Math.Pow(p2.Y, 2) - (float)Math.Pow(distance, 2);
// Now we have the system with the 2 equations:
// x^2 + y^2 + a1x + b1y + c1 = 0
// x^2 + y^2 + a2x + b2y + c2 = 0
// subtracting the second equation from the first we get
// (a1-a2)x + (b1-b2)y + c1 - c2 = 0
// from which
// y = (c2-c1)/(b1-b2) - (a1-a2)x/(b1-b2)
// y = d - ex
float d = (c2 - c1) / (b1 - b2);
float e = (a1 - a2) / (b1 - b2);
// replacing the last equation in the first one of the system:
// x^2 + (d-ex)^2 + a1x + b1(d-ex) + c1 = 0;
// x^2 + d^2 - 2dex +(ex)^2 + a1x + b1d - b1ex + c1 = 0
// (1+e^2)x^2 + (a1-2de-b1e)x + d^2 + b1d + c1 = 0
// which can be written as
// a3x^2 + b3x + c3 = 0
// where
float a3 = 1 + (float)Math.Pow(e, 2);
float b3 = a1 - 2 * d * e - b1 * e;
float c3 = (float)Math.Pow(d, 2) + b1 * d + c1;
// now it's simlple
float delta = (float)Math.Pow(b3, 2) - 4 * a3 * c3;
if (delta < 0)
return null;
float x1 = (-b3 + (float)Math.Sqrt(delta)) / (2 * a3);
float y1 = d - e * x1;
float x2 = (-b3 - (float)Math.Sqrt(delta)) / (2 * a3);
float y2 = d - e * x2;
return new Tuple<PointF, PointF>(new PointF(x1, y1), new PointF(x2, y2));
}

Is it true equation written on C #?

The equation is:
Is it true I have written?
Double x = 14.26
Double y = -1.22
Double z = 3.5 * Math.Pow(10.0, -2)
Double t;
t = ( 2 * Math.Cos( x - Math.PI / 6 ) ) / ( 0.5 + Math.Pow( Math.Sin( y ), 2 ) ) * ( (1 + Math.Pow( z, 2 ) ) / ( 3 - Math.Pow( z, 2 ) / 5 ) );
Because the result does not coincide with the above desired result -- t = 0,188451240697501, and I need to t deduced 0.564849.
Double x = 14.26, y = -1.22, z = 3.5 * Math.Pow(10.0, -2), t;
t = (2*Math.Cos(x-Math.PI/6))/(0.5+Math.Pow(Math.Sin(y), 2)) * ( 1 + (Math.Pow(z, 2)) / (3-Math.Pow(z, 2)/5));
Console.WriteLine(t); // 0.5648...
You have parenthesis issue, change ((1 + Math.Pow(z, 2)) to (1 + (Math.Pow(z, 2)), the addition of 1 should be calculated after the division.
Also, consider computing the numerators and denominators separately.
I think that one error it is here:
((1 + Math.Pow(z, 2)) / (3-Math.Pow(z, 2)/5))
you should do:
(1 + (Math.Pow(z, 2) / (3-Math.Pow(z, 2)/5)))

Calculating floating point error bound

I have geometrical algorithms and im struggling with floating point inaccuracies.
For example, I'm calculating wether a point lies on the left/right/on a plane (C#):
const double Epsilon = 1e-10;
internal double ComputeDistance(Vector3D v)
{
Vector3D normal = Plane.Normal;
Vertex v0 = Plane.Origin;
double a = normal.X;
double b = normal.Y;
double c = normal.Z;
double d = -(a * v0.X + b * v0.Y + c * v0.Z);
return a * v.X + b * v.Y + c * v.Z + d;
}
internal string DistanceSign(Vector3D v)
{
var distance = ComputeDistance(v);
return (distance > Epsilon ? "left" : (distance < -Epsilon ? "right" : "on"));
}
As shown in the code, I use a fixed Epsilon value.
But I don't trust this fixed epsilon because I don't know the size of the floating point error. If the fp error is bigger than my epsilon interval, then my algorithm will fail.
How can I make it robust? I have searched on the internet but haven't found a solution so far. I have read "What Every Computer Scientist Should Know About Floating-Point Arithmetic", it describes why fp errors occur but not how to solve them practically.
Edit
Here is a shewchuk predicate that doesn't seem work:
double[] pa = {0, 0};
double[] pb = {2 * Double.Epsilon, 0};
double[] pc = { 0, Double.Epsilon };
Assert.IsTrue(GeometricPredicates.Orient2D(pa, pb, pc) > 0);
The assertion fails because Orient2D return 0. The code is here
Edit2
Shouldn't it be possible to calculate an error bound by using the machine epsilon? According to wikipedia, the machine epsilon is an upper bound due to rounding. For double, it is 2^−53. So as I take it, when I have an arithmetic calculation:
double x = y + z
then the maximum error should be 2^−53. Shouldn't this fact enable the possiblity to calculate an appropriate epsilon? So two rewrite my method:
double const Machine_Eps = 1.11022302462516E-16 // (2^-53)
double Epsilon = Machine_Eps;
internal double ComputeDistance(Vector3D v)
{
Vector3D normal = Plane.Normal;
Vertex v0 = Plane.Origin;
double a = normal.X;
double b = normal.Y;
double c = normal.Z;
// 3 multiplications + 2 additions = maximum of 5*Machine_Eps
double d = -(a * v0.X + b * v0.Y + c * v0.Z);
// 3 multiplications + 3 additions = maximum of 6*Machine_Eps
Epsilon = 11 * Machine_Eps;
return a * v.X + b * v.Y + c * v.Z + d;
}
internal string DistanceSign(Vector3D v)
{
var distance = ComputeDistance(v);
return (distance > Epsilon ? "left" : (distance < -Epsilon ? "right" : "on"));
}
Ok now you can tell me how wrong I am. :)

Dicom Window width & level formula not giving greyvalues

I'm trying to implement the Window Width and level formula from de Dicom specification in my application. Only it's not returning any grayscales at the moment. The dicom specifies the formula as following:
These Attributes are applied according to the following pseudo-code, where x is the input value, y
is an output value with a range from ymin to ymax, c is Window Center (0028,1050) and w is
Window Width (0028,1051):
if (x <= c - 0.5 - (w-1)/2), then y = ymin
else if (x > c - 0.5 + (w-1)/2), then y = ymax,
else y = ((x - (c - 0.5)) / (w-1) + 0.5) * (ymax - ymin)+ ymin
So i've translated this into the following c# syntax:
if (pixelData[i] <= wLevel - 0.5 - (wWidth - 1) / 2)
oColor = 0;
else if (pixelData[i] > wLevel - 0.5 + (wWidth - 1) / 2)
oColor = 255;
else
oColor = (int)((pixelData[i] - (wLevel - 0.5)) / (wWidth - 1) + 0.5) * (255 - 0) + 0;
Howevery, the last part of the formula
oColor = (int)((pixelData[i] - (wLevel - 0.5)) / (wWidth - 1) + 0.5) * (255 - 0) + 0;
Only seems to return 0
Anyone sees how this is possible?
The meaning of VOI LUT is to map a given pixel range to displayable values (usually 0..0xFF), using clamping for out of range pixel values.
This means that for a given window/level we can compute the displayable range:
level-window/2 , level + window/2 .
For pixel values that are in that range, linear transformation is used:
((pixel - lower_window_limit) / window) * displayable_range
where lower_window_limit is level - window/2
This -window/2 is missing in your formula.

How to tell whether a point is to the right or left side of a line

I have a set of points. I want to separate them into 2 distinct sets. To do this, I choose two points (a and b) and draw an imaginary line between them. Now I want to have all points that are left from this line in one set and those that are right from this line in the other set.
How can I tell for any given point z whether it is in the left or in the right set? I tried to calculate the angle between a-z-b – angles smaller than 180 are on the right hand side, greater than 180 on the left hand side – but because of the definition of ArcCos, the calculated angles are always smaller than 180°. Is there a formula to calculate angles greater than 180° (or any other formula to chose right or left side)?
Try this code which makes use of a cross product:
public bool isLeft(Point a, Point b, Point c){
return ((b.X - a.X)*(c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X)) > 0;
}
Where a = line point 1; b = line point 2; c = point to check against.
If the formula is equal to 0, the points are colinear.
If the line is horizontal, then this returns true if the point is above the line.
Use the sign of the determinant of vectors (AB,AM), where M(X,Y) is the query point:
position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax))
It is 0 on the line, and +1 on one side, -1 on the other side.
You look at the sign of the determinant of
| x2-x1 x3-x1 |
| y2-y1 y3-y1 |
It will be positive for points on one side, and negative on the other (and zero for points on the line itself).
The vector (y1 - y2, x2 - x1) is perpendicular to the line, and always pointing right (or always pointing left, if you plane orientation is different from mine).
You can then compute the dot product of that vector and (x3 - x1, y3 - y1) to determine if the point lies on the same side of the line as the perpendicular vector (dot product > 0) or not.
Using the equation of the line ab, get the x-coordinate on the line at the same y-coordinate as the point to be sorted.
If point's x > line's x, the point is to the right of the line.
If point's
x < line's x, the point is to the left of the line.
If point's x == line's x, the point is on the line.
I implemented this in java and ran a unit test (source below). None of the above solutions work. This code passes the unit test. If anyone finds a unit test that does not pass, please let me know.
Code: NOTE: nearlyEqual(double,double) returns true if the two numbers are very close.
/*
* #return integer code for which side of the line ab c is on. 1 means
* left turn, -1 means right turn. Returns
* 0 if all three are on a line
*/
public static int findSide(
double ax, double ay,
double bx, double by,
double cx, double cy) {
if (nearlyEqual(bx-ax,0)) { // vertical line
if (cx < bx) {
return by > ay ? 1 : -1;
}
if (cx > bx) {
return by > ay ? -1 : 1;
}
return 0;
}
if (nearlyEqual(by-ay,0)) { // horizontal line
if (cy < by) {
return bx > ax ? -1 : 1;
}
if (cy > by) {
return bx > ax ? 1 : -1;
}
return 0;
}
double slope = (by - ay) / (bx - ax);
double yIntercept = ay - ax * slope;
double cSolution = (slope*cx) + yIntercept;
if (slope != 0) {
if (cy > cSolution) {
return bx > ax ? 1 : -1;
}
if (cy < cSolution) {
return bx > ax ? -1 : 1;
}
return 0;
}
return 0;
}
Here's the unit test:
#Test public void testFindSide() {
assertTrue("1", 1 == Utility.findSide(1, 0, 0, 0, -1, -1));
assertTrue("1.1", 1 == Utility.findSide(25, 0, 0, 0, -1, -14));
assertTrue("1.2", 1 == Utility.findSide(25, 20, 0, 20, -1, 6));
assertTrue("1.3", 1 == Utility.findSide(24, 20, -1, 20, -2, 6));
assertTrue("-1", -1 == Utility.findSide(1, 0, 0, 0, 1, 1));
assertTrue("-1.1", -1 == Utility.findSide(12, 0, 0, 0, 2, 1));
assertTrue("-1.2", -1 == Utility.findSide(-25, 0, 0, 0, -1, -14));
assertTrue("-1.3", -1 == Utility.findSide(1, 0.5, 0, 0, 1, 1));
assertTrue("2.1", -1 == Utility.findSide(0,5, 1,10, 10,20));
assertTrue("2.2", 1 == Utility.findSide(0,9.1, 1,10, 10,20));
assertTrue("2.3", -1 == Utility.findSide(0,5, 1,10, 20,10));
assertTrue("2.4", -1 == Utility.findSide(0,9.1, 1,10, 20,10));
assertTrue("vertical 1", 1 == Utility.findSide(1,1, 1,10, 0,0));
assertTrue("vertical 2", -1 == Utility.findSide(1,10, 1,1, 0,0));
assertTrue("vertical 3", -1 == Utility.findSide(1,1, 1,10, 5,0));
assertTrue("vertical 3", 1 == Utility.findSide(1,10, 1,1, 5,0));
assertTrue("horizontal 1", 1 == Utility.findSide(1,-1, 10,-1, 0,0));
assertTrue("horizontal 2", -1 == Utility.findSide(10,-1, 1,-1, 0,0));
assertTrue("horizontal 3", -1 == Utility.findSide(1,-1, 10,-1, 0,-9));
assertTrue("horizontal 4", 1 == Utility.findSide(10,-1, 1,-1, 0,-9));
assertTrue("positive slope 1", 1 == Utility.findSide(0,0, 10,10, 1,2));
assertTrue("positive slope 2", -1 == Utility.findSide(10,10, 0,0, 1,2));
assertTrue("positive slope 3", -1 == Utility.findSide(0,0, 10,10, 1,0));
assertTrue("positive slope 4", 1 == Utility.findSide(10,10, 0,0, 1,0));
assertTrue("negative slope 1", -1 == Utility.findSide(0,0, -10,10, 1,2));
assertTrue("negative slope 2", -1 == Utility.findSide(0,0, -10,10, 1,2));
assertTrue("negative slope 3", 1 == Utility.findSide(0,0, -10,10, -1,-2));
assertTrue("negative slope 4", -1 == Utility.findSide(-10,10, 0,0, -1,-2));
assertTrue("0", 0 == Utility.findSide(1, 0, 0, 0, -1, 0));
assertTrue("1", 0 == Utility.findSide(0,0, 0, 0, 0, 0));
assertTrue("2", 0 == Utility.findSide(0,0, 0,1, 0,2));
assertTrue("3", 0 == Utility.findSide(0,0, 2,0, 1,0));
assertTrue("4", 0 == Utility.findSide(1, -2, 0, 0, -1, 2));
}
First check if you have a vertical line:
if (x2-x1) == 0
if x3 < x2
it's on the left
if x3 > x2
it's on the right
else
it's on the line
Then, calculate the slope: m = (y2-y1)/(x2-x1)
Then, create an equation of the line using point slope form: y - y1 = m*(x-x1) + y1. For the sake of my explanation, simplify it to slope-intercept form (not necessary in your algorithm): y = mx+b.
Now plug in (x3, y3) for x and y. Here is some pseudocode detailing what should happen:
if m > 0
if y3 > m*x3 + b
it's on the left
else if y3 < m*x3 + b
it's on the right
else
it's on the line
else if m < 0
if y3 < m*x3 + b
it's on the left
if y3 > m*x3+b
it's on the right
else
it's on the line
else
horizontal line; up to you what you do
I wanted to provide with a solution inspired by physics.
Imagine a force applied along the line and you are measuring the torque of the force about the point. If the torque is positive (counterclockwise) then the point is to the "left" of the line, but if the torque is negative the point is the "right" of the line.
So if the force vector equals the span of the two points defining the line
fx = x_2 - x_1
fy = y_2 - y_1
you test for the side of a point (px,py) based on the sign of the following test
var torque = fx*(py-y_1)-fy*(px-x_1)
if torque>0 then
"point on left side"
else if torque <0 then
"point on right side"
else
"point on line"
end if
Assuming the points are (Ax,Ay) (Bx,By) and (Cx,Cy), you need to compute:
(Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Ax)
This will equal zero if the point C is on the line formed by points A and B, and will have a different sign depending on the side. Which side this is depends on the orientation of your (x,y) coordinates, but you can plug test values for A,B and C into this formula to determine whether negative values are to the left or to the right.
basically, I think that there is a solution which is much easier and straight forward, for any given polygon, lets say consist of four vertices(p1,p2,p3,p4), find the two extreme opposite vertices in the polygon, in another words, find the for example the most top left vertex (lets say p1) and the opposite vertex which is located at most bottom right (lets say ). Hence, given your testing point C(x,y), now you have to make double check between C and p1 and C and p4:
if cx > p1x AND cy > p1y ==> means that C is lower and to right of p1
next
if cx < p2x AND cy < p2y ==> means that C is upper and to left of p4
conclusion, C is inside the rectangle.
Thanks :)
#AVB's answer in ruby
det = Matrix[
[(x2 - x1), (x3 - x1)],
[(y2 - y1), (y3 - y1)]
].determinant
If det is positive its above, if negative its below. If 0, its on the line.
Here's a version, again using the cross product logic, written in Clojure.
(defn is-left? [line point]
(let [[[x1 y1] [x2 y2]] (sort line)
[x-pt y-pt] point]
(> (* (- x2 x1) (- y-pt y1)) (* (- y2 y1) (- x-pt x1)))))
Example usage:
(is-left? [[-3 -1] [3 1]] [0 10])
true
Which is to say that the point (0, 10) is to the left of the line determined by (-3, -1) and (3, 1).
NOTE: This implementation solves a problem that none of the others (so far) does! Order matters when giving the points that determine the line. I.e., it's a "directed line", in a certain sense. So with the above code, this invocation also produces the result of true:
(is-left? [[3 1] [-3 -1]] [0 10])
true
That's because of this snippet of code:
(sort line)
Finally, as with the other cross product based solutions, this solution returns a boolean, and does not give a third result for collinearity. But it will give a result that makes sense, e.g.:
(is-left? [[1 1] [3 1]] [10 1])
false
Issues with the existing solution:
While I found Eric Bainville's answer to be correct, I found it entirely inadequate to comprehend:
How can two vectors have a determinant? I thought that applied to matrices?
What is sign?
How do I convert two vectors into a matrix?
position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax))
What is Bx?
What is Y? Isn't Y meant to be a Vector, rather than a scalar?
Why is the solution correct - what is the reasoning behind it?
Moreover, my use case involved complex curves rather than a simple line, hence it requires a little re-jigging:
Reconstituted Answer
Point a = new Point3d(ax, ay, az); // point on line
Point b = new Point3d(bx, by, bz); // point on line
If you want to see whether your points are above/below a curve, then you would need to get the first derivative of the particular curve you are interested in - also known as the tangent to the point on the curve. If you can do so, then you can highlight your points of interest. Of course, if your curve is a line, then you just need the point of interest without the tangent. The tangent IS the line.
Vector3d lineVector = curve.GetFirstDerivative(a); // where "a" is a point on the curve. You may derive point b with a simple displacement calculation:
Point3d b = new Point3d(a.X, a.Y, a.Z).TransformBy(
Matrix3d.Displacement(curve.GetFirstDerivative(a))
);
Point m = new Point3d(mx, my, mz) // the point you are interested in.
The Solution:
return (b.X - a.X) * (m.Y - a.Y) - (b.Y - a.Y) * (m.X - a.X) < 0; // the answer
Works for me! See the proof in the photo above. Green bricks satisfy the condition, but the bricks outside were filtered out! In my use case - I only want the bricks that are touching the circle.
Theory behind the answer
I will return to explain this. Someday. Somehow...
An alternative way of getting a feel of solutions provided by netters is to understand a little geometry implications.
Let pqr=[P,Q,R] are points that forms a plane that is divided into 2 sides by line [P,R]. We are to find out if two points on pqr plane, A,B, are on the same side.
Any point T on pqr plane can be represented with 2 vectors: v = P-Q and u = R-Q, as:
T' = T-Q = i * v + j * u
Now the geometry implications:
i+j =1: T on pr line
i+j <1: T on Sq
i+j >1: T on Snq
i+j =0: T = Q
i+j <0: T on Sq and beyond Q.
i+j: <0 0 <1 =1 >1
---------Q------[PR]--------- <== this is PQR plane
^
pr line
In general,
i+j is a measure of how far T is away from Q or line [P,R], and
the sign of i+j-1 implicates T's sideness.
The other geometry significances of i and j (not related to this solution) are:
i,j are the scalars for T in a new coordinate system where v,u are the new axes and Q is the new origin;
i, j can be seen as pulling force for P,R, respectively. The larger i, the farther T is away from R (larger pull from P).
The value of i,j can be obtained by solving the equations:
i*vx + j*ux = T'x
i*vy + j*uy = T'y
i*vz + j*uz = T'z
So we are given 2 points, A,B on the plane:
A = a1 * v + a2 * u
B = b1 * v + b2 * u
If A,B are on the same side, this will be true:
sign(a1+a2-1) = sign(b1+b2-1)
Note that this applies also to the question: Are A,B in the same side of plane [P,Q,R], in which:
T = i * P + j * Q + k * R
and i+j+k=1 implies that T is on the plane [P,Q,R] and the sign of i+j+k-1 implies its sideness. From this we have:
A = a1 * P + a2 * Q + a3 * R
B = b1 * P + b2 * Q + b3 * R
and A,B are on the same side of plane [P,Q,R] if
sign(a1+a2+a3-1) = sign(b1+b2+b3-1)
equation of line is y-y1 = m(x-x1)
here m is y2-y1 / x2-x1
now put m in equation and put condition on y < m(x-x1) + y1 then it is left side point
eg.
for i in rows:
for j in cols:
if j>m(i-a)+b:
image[i][j]=0
A(x1,y1) B(x2,y2) a line segment with length L=sqrt( (y2-y1)^2 + (x2-x1)^2 )
and a point M(x,y)
making a transformation of coordinates in order to be the point A the new start and B a point of the new X axis
we have the new coordinates of the point M
which are
newX = ((x-x1)(x2-x1)+(y-y1)(y2-y1)) / L
from (x-x1)*cos(t)+(y-y1)*sin(t) where cos(t)=(x2-x1)/L, sin(t)=(y2-y1)/L
newY = ((y-y1)(x2-x1)-(x-x1)(y2-y1)) / L
from (y-y1)*cos(t)-(x-x1)*sin(t)
because "left" is the side of axis X where the Y is positive, if the newY (which is the distance of M from AB) is positive, then it is on the left side of AB (the new X axis)
You may omit the division by L (allways positive), if you only want the sign

Categories