如何连接平面上的 4 个点,使它们不会自行折叠(它们总是创建一个四边形)

How to connect 4 points on a plane so they do not fold on themselves(they always create a Quadrilateral)

我创建了一个小型 Raphael 应用程序来展示我的奋斗。

我创建了四个可以移动的把手。 'sheet' 覆盖了整个屏幕,除了 4 个手柄之间的正方形。

只要拖动手柄,就会相应地放置 sheet。

最终发生的是,在某些情况下,sheet 弃牌。

最好只看到 fiddle。你会明白我在说什么

http://jsfiddle.net/8qtffq0s/

我怎样才能避免这种情况?

注意:屏幕是白色的。黑色部分是sheet,白色部分是sheet中的空隙而不是相反。

   //raphael object
            var paper = Raphael(0, 0, 600, 600)
            //create 4 handles
            h1 = paper.circle(50, 50, 10).attr("fill","green")
            h2 = paper.circle(300, 50, 10).attr("fill", "blue")
            h3 = paper.circle(300, 300, 10).attr("fill", "yellow")
            h4 = paper.circle(50, 300, 10).attr("fill", "red")

            //create covering sheet          
            path = ["M", 0, 0, "L", 600, 0, 600, 600, 0, 600, 'z', "M", h1.attrs.cx, h1.attrs.cy,"L", h4.attrs.cx, h4.attrs.cy, h3.attrs.cx, h3.attrs.cy, h2.attrs.cx, h2.attrs.cy,'z']
            sheet = paper.path(path).attr({ "fill": "black", "stroke": "white" }).toBack()

            //keep starting position of each handle on dragStart
            var startX,startY
            function getPos(handle) {
                startX= handle.attrs.cx
                startY = handle.attrs.cy
            }
            //Redraw the sheet to match the new handle placing
            function reDrawSheet() {
                path = ["M", 0, 0, "L", 600, 0, 600, 600, 0, 600, 'z', "M", h1.attrs.cx, h1.attrs.cy, "L", h4.attrs.cx, h4.attrs.cy, h3.attrs.cx, h3.attrs.cy, h2.attrs.cx, h2.attrs.cy, 'z']
                sheet.attr("path",path)
            }
            //enable handle dragging
            h1.drag(function (dx, dy) {
                this.attr("cx", startX + dx)
                this.attr("cy", startY + dy)
                reDrawSheet()
            },
            function () {
                getPos(this)
            })
            h2.drag(function (dx, dy) {
                this.attr("cx", startX + dx)
                this.attr("cy", startY + dy)
                reDrawSheet()
            },
            function () {
                getPos(this)
            })
            h3.drag(function (dx, dy) {
                this.attr("cx", startX + dx)
                this.attr("cy", startY + dy)
                reDrawSheet()
            },
            function () {
                getPos(this)
            })
            h4.drag(function (dx, dy) {
                this.attr("cx", startX + dx)
                this.attr("cy", startY + dy)
                reDrawSheet()
            },
            function () {
                getPos(this)
            })

更新:我改进了函数"reDrawSheet",现在它可以将字符串上的点分类为左上角、左下角、右下角和右上角

这解决了我的许多问题,但在某些情况下,sheet 仍然会自行弃牌。

新 fiddle: http://jsfiddle.net/1kj06co4/

新密码: 函数重新绘制表(){ //c代表坐标 c = [{ x: h1.attrs.cx, y: h1.attrs.cy }, { x: h4.attrs.cx, y: h4.attrs.cy }, { x: h3.attrs.cx, y: h3.attrs.cy }, { x: h2.attrs.cx, y: h2.attrs.cy }]

                //arrange the 4 points by height
                c.sort(function (a, b) {
                    return a.y - b.y
                })

                //keep top 2 points
                cTop = [c[0], c[1]]

                //arrange them from left to right
                cTop.sort(function (a, b) {
                    return a.x - b.x
                })

                //keep bottom 2 points
                cBottom = [c[2], c[3]]
                //arrange them from left to right
                cBottom.sort(function (a, b) {
                    return a.x - b.x
                })

                //top left most point
                tl = cTop[0]
                //bottom left most point
                bl = cBottom[0]
                //top right most point
                tr = cTop[1]
                //bottom right most point
                br = cBottom[1]

                path = ["M", 0, 0, "L", 600, 0, 600, 600, 0, 600, 'z', "M", tl.x,tl.y, "L", bl.x,bl.y, br.x,br.y, tr.x,tr.y, 'z']
                sheet.attr("path",path)
            }

为了让事情变得非常清楚,这是我要避免的事情:

更新二:

通过检查三个可能路径中哪条路径最短并选择它,我能够避免顶点交叉。

为此,我添加了一个检查两点之间距离的函数

                  function distance(a, b) {
                return Math.sqrt(Math.pow(b.x - a.x, 2) + (Math.pow(b.y - a.y, 2)))
            }

然后像这样修改代码:

function reDrawSheet() {
                    //c stands for coordinates
                    c = [{ x: h1.attrs.cx, y: h1.attrs.cy }, { x: h4.attrs.cx, y: h4.attrs.cy }, { x: h3.attrs.cx, y: h3.attrs.cy }, { x: h2.attrs.cx, y: h2.attrs.cy }]
                    //d stands for distance
                    d=distance
                    //get the distance of all possible paths
                    d1 = d(c[0], c[1]) + d(c[1], c[2]) + d(c[2], c[3]) + d(c[3], c[0])
                    d2 = d(c[0], c[2]) + d(c[2], c[3]) + d(c[3], c[1]) + d(c[1], c[0])
                    d3 = d(c[0], c[2]) + d(c[2], c[1]) + d(c[1], c[3]) + d(c[3], c[0])
                    //choose the shortest distance
                    if (d1 <= Math.min(d2, d3)) {
                        tl = c[0]
                        bl = c[1]
                        br = c[2]
                        tr = c[3]
                    }
                    else if (d2 <= Math.min(d1, d3)) {
                        tl = c[0]
                        bl = c[2]
                        br = c[3]
                        tr = c[1]
                    }
                    else if (d3 <= Math.min(d1, d2)) {
                        tl = c[0]
                        bl = c[2]
                        br = c[1]
                        tr = c[3]
                    }



                    path = ["M", 0, 0, "L", 600, 0, 600, 600, 0, 600, 'z', "M", tl.x,tl.y, "L", bl.x,bl.y, br.x,br.y, tr.x,tr.y, 'z']
                    sheet.attr("path",path)
                }

现在这条线并没有像我附上的图片那样自己交叉,而是 sheet "flips" 所以一切都变黑了。

你可以看到路径被正确绘制以通过白色描边连接for点,但没有留下空隙

新 fiddle: http://jsfiddle.net/1kj06co4/1/

问题图片:

所以……麻烦的是要分清里面和外面。

您需要以下功能:

function sub(a, b) {
    return { x: a.x - b.x , y: a.y - b.y };
}

function neg(a) {
    return { x: -a.x , y: -a.y };
}

function cross_prod(a, b) {
    // 2D vecs, so z==0.
    // Therefore, x and y components are 0.
    // Return the only important result, z.
    return (a.x*b.y - a.y*b.x);
}

找到 tl、tr、br 和 bl 后,您需要执行以下操作:

tlr = sub(tr,tl);
tbl = sub(bl,tl);
brl = sub(bl,br);
btr = sub(tr,br);

cropTL = cross_prod(    tbl,     tlr );
cropTR = cross_prod(neg(tlr),neg(btr));
cropBR = cross_prod(    btr,     brl );
cropBL = cross_prod(neg(brl),neg(tbl));

cwTL = cropTL > 0;
cwTR = cropTR > 0;
cwBR = cropBR > 0;
cwBL = cropBL > 0;

if (cwTL) {
    tmp = tr;
    tr = bl;
    bl = tmp;
}
if (cwTR == cwBR && cwBR == cwBL && cwTR!= cwTL) {
    tmp = tr;
    tr = bl;
    bl = tmp;
}

我的 fiddle 版本在这里。 :) http://jsfiddle.net/1kj06co4/39/