【问题标题】:2d cross product definition二维叉积定义
【发布时间】:2020-01-16 21:03:37
【问题描述】:

determine if line segment is inside polygon 我注意到接受的答案有一个不寻常的二维交叉产品定义:

(u1, u2) x (v1, v2) := (u1 - v2)*(u2 - v1)

我从未遇到过这样的二维叉积定义。谁能告诉我这样的定义是从哪里来的?

【问题讨论】:

  • 这不起作用。想象一下,多边形很小且靠近原点,而一个点在矢量(1,1) 上很远。

标签: algorithm geometry 2d linear-algebra


【解决方案1】:

我建议你看看Exterior Algebra。它概括了叉积和行列式的概念。描述飞机区域的“动机示例”部分正好回答了您的问题。

它适用于任何维度。 3D 是一个特殊情况,其中两个向量的叉积的结果也有 3 个分量。但是,在 2D 中,只有一个结果分量,而在 4D 中,有 6 个。在 4D 中,您可以使用 3 个向量应用一种叉积,这也给您 4 个分量。

请务必注意,虽然 3D 中叉积的结果有 3 个分量,但单位和含义是不同的。例如,x 分量具有面积单位,并表示 YZ 平面中的面积,这与“标准”向量相反,其中 x 分量具有长度单位并且差异是坐标。使用外部代数,这些差异变得更加清晰,因为符号也不同(dx vs dy^dz)。

注意:您引用的答案有误。而不是(u1, u2) x (v1, v2) := (u1 - v2)*(u2 - v1),应该是(u1, u2) x (v1, v2) := u1*v2 - u2*v1

【讨论】:

  • 感谢您的回复。我同意您对 * 而不是 - 对于 2d 叉积公式的错误的解释。
【解决方案2】:

Wikipedia's entry on Cross Product, section "Computational geometry" 解释:

在平面的计算几何中,叉积用于确定由三个点定义的锐角的符号。

p1 = (x1,y1), p2=(x 2,y2)p3 = (x3, y3)。它对应于两对点(p1, p2)定义的两个共面向量的叉积的方向(向上或向下) (p1, p3)。锐角的符号就是表达式的符号

      P = (x2 - x1)(y3 - y1) - (y2 - y1)(x3 - x1)

这是两个向量叉积的有符号长度。

the other question & answer you refer to中叉积的定义与此有偏差,不正确。

这里我提供了一个可运行的小sn-p,用它可以通过画一个角度来测试两个不同的公式。上面引用的 p1 是固定在中心的。其他两个点可以通过鼠标向下 (u) 和拖动 (v) 来定义。在按住鼠标的同时,u 点会跟随光标。您可以同时查看两个竞争公式的计算值。显然,(正确的)叉积的符号表明第三点相对于固定点和第二点在哪“边”上。

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>

【讨论】:

    【解决方案3】:

    不是数学专家,而是 ND 中的 CROSS 乘积被定义为 N-1 向量的运算,导致向量垂直于每个向量。这些东西被计算为矩阵的行列式,其中第一行是单位方向向量(i,j,k,...),其他每一行都包含每个向量操作数。所以对于 2D 它是:

    cross( (x0,y0) ) = | i  j  | = i*y0 - j*x0 = (y0,-x0)
                       | x0 y0 |
    

    垂直于(x0,y0)所以你所拥有的不是二维叉积!!!

    在 CG 中通常需要通过 3D 叉积获得某个 2D 表面的法线向量:

    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 |
    

    现在如果(x0,y0,z0),(x1,y1,z1) 的两个向量是二维的,那么z0,z1 都是零,所以:

    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)
    

    这与您的定义更相似,但看起来不一样,所以您拥有的是以下之一:

    1. 不同的东西不是交叉产品
    2. 用我还没有看到的一些数学恒等式转换的叉积。
    3. 该答案中的错误(小错字,或复制错误的代码行......我也经常发生)
    4. 更多方程融合在一起(交叉只是答案的一小部分)

    在链接答案的上下文中您需要 3D 叉积 z 坐标结果:

    z = x0*y1-y0*x1
    

    哪个符号会告诉您关于多边形缠绕规则及其边缘之一的点是顺时针还是逆时针...

    但要绝对清楚,你应该直接在那个问题线程中问这个Niklas B.(使用评论),因为你的代表很低,我会为你做这件事并将你的问题链接到那里......

    【讨论】:

    • 感谢您的帮助,甚至向 Niklas 寻求解释。我认为 Gilles-Philippe Paillé 的回答是对那个奇怪的叉积定义最可能的解释,因此我会接受他的回答。再次感谢:)
    猜你喜欢
    • 1970-01-01
    • 2010-09-19
    • 2011-01-20
    • 2017-02-24
    • 2013-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    相关资源
    最近更新 更多