In determine if line segment is inside polygon I noticed the accepted answer has an unusual 2d cross roduct definition of:
(u1, u2) x (v1, v2) := (u1 - v2)*(u2 -
I suggest you to take a look at Exterior Algebra. It generalizes the notion of cross product and determinant. The "Motivation examples" section describing areas in the plane answers exactly your question.
It works in any dimension. 3D is a specific case where the result of the cross product of two vectors also has 3 components. However, in 2D, there is only one resulting component, and in 4D, there is 6. In 4D, you can apply a kind of cross product using 3 vectors, which give you also 4 components.
It is important to note that while the result of a cross product in 3D has 3 components, the units and the meaning are different. For example, the x-component has units of area, and represents the area in the YZ plane, as opposed to a "standard" vector where the x-component has unit of length and is a difference is coordinates. Using exterior algebra, these differences become clearer since the notation is also different (dx
vs dy^dz
).
Note: The answer that you referenced has a mistake. Instead of (u1, u2) x (v1, v2) := (u1 - v2)*(u2 - v1)
, it should be (u1, u2) x (v1, v2) := u1*v2 - u2*v1
not a math expert but CROSS product in ND is defined as operation of N-1
vectors resulting in vector perpendicular to each. The stuff is computed as determinant of matrix where its first line are unit direction vectors (i,j,k,...)
and each of the other lines holds each vector operand. So for 2D it is:
cross( (x0,y0) ) = | i j | = i*y0 - j*x0 = (y0,-x0)
| x0 y0 |
which is perpendicular to (x0,y0)
. So what you have is not a 2D cross product !!!
Its usual in CG to need a normal vector to some 2D surface that is obtained by 3D cross product:
cross( (x0,y0,z0),(x1,y1,z1) ) = | i j k | = i*(y0*x1-z0*y1) + j*(z0*x1-x0*z1) + k*(x0*y1-y0*x1)
| x0 y0 z0 |
| x1 y1 z1 |
Now if the two vectors (x0,y0,z0),(x1,y1,z1)
are 2D then z0,z1
are both zero so:
cross( (x0,y0,z0),(x1,y1,z1) ) = i*(y0*x1-0*y1) + j*(0*x1-x0*0) + k*(x0*y1-y0*x1)
cross( (x0,y0,z0),(x1,y1,z1) ) = k*(x0*y1-y0*x1)
cross( (x0,y0,z0),(x1,y1,z1) ) = (0,0,x0*y1-y0*x1)
This is more similar to your definition but does not look the same so what you have is one of these:
in context of the linked answer you need the 3D cross products z
coordinate result:
z = x0*y1-y0*x1
which sign will tell you if the points is CW or CCW in respect to polygon winding rule and one of its edges...
But to be absolutely clear you should ask this Niklas B.
in that question thread directly (using comment) since you're low rep I will do it for you and link your question there ...
Wikipedia's entry on Cross Product, section "Computational geometry" explains:
In computational geometry of the plane, the cross product is used to determine the sign of the acute angle defined by three points.
p1 = (x1,y1), p2=(x2,y2) and p3 = (x3, y3). It corresponds to the direction (upward or downward) of the cross product of the two coplanar vectors defined by the two pairs of points (p1, p2) and (p1, p3). The sign of the acute angle is the sign of the expression
P = (x2 − x1)(y3 − y1) − (y2 − y1)(x3 − x1)
which is the signed length of the cross product of the two vectors.
The definition of the cross product in the other question & answer you refer to deviates from this, and is incorrect.
Here I provide a little runnable snippet, with which the two different formulas can be tested by drawing an angle. What the above quote calls p1 is fixed in the centre. The other two points can be defined by a mouse-down (u) and drag (v). While keeping the mouse down, the point u follows the cursor. You can at the same time see the calculated value from the two competing formulas. Clearly, the (correct) cross product's sign gives the indication on which "side" the third point is relative to the fixed and second point.
let translation = { x: 150, y: 75 };
let zero = { x: 0, y: 0 };
let ctx = document.querySelector("canvas").getContext("2d");
let output1 = document.querySelector("#p1");
let output2 = document.querySelector("#p2");
let u;
let isMouseDown = false;
function drawLine(ctx, a, b, color="black") {
ctx.beginPath();
ctx.moveTo(a.x, a.y);
ctx.lineTo(b.x, b.y);
ctx.strokeStyle = color;
ctx.stroke();
}
function text(ctx, a, txt, color) {
ctx.fillStyle = color;
ctx.fillText(txt, a.x+2, a.y-2);
}
function refresh(ctx, u, v) {
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.translate(translation.x, translation.y);
drawLine(ctx, zero, u, "black");
drawLine(ctx, zero, v, "red");
text(ctx, u, "U", "black");
text(ctx, v, "V", "red");
output1.textContent = (u.x - v.y) * (u.y - v.x);
output2.textContent = u.x * v.y - u.y * v.x;
}
let getXY = (e) => ({
x: e.clientX-e.target.offsetLeft - translation.x,
y: e.clientY-e.target.offsetTop - translation.y,
});
ctx.canvas.onmousedown = function(e) {
u = getXY(e);
refresh(ctx, u, u);
isMouseDown = true;
}
ctx.canvas.onmouseup = () => isMouseDown = false;
ctx.canvas.onmousemove = function(e) {
if (!isMouseDown) return;
let v = getXY(e);
refresh(ctx, u, v);
}
canvas { border: 1px solid; float: left }
<canvas width="300" height="150"></canvas>
<pre> Wrong: (u.x−v.y) * (u.y−v.x): <span id="p1"></span>
Right: u.x * v.y − u.y * v.x: <span id="p2"></span>
</pre>