检查是否给定由4个元素数组的坐标表示的三个线段可以形成三角形

时间:2016-02-15 22:05:24

标签: javascript math geometry

我需要检查给定三个线段是否形成三角形。线段可以表示为4个整数的数组,给出[x1,y1,x2,y2]形式的端点坐标。 所以我需要编写一个函数作为输入给出三个线段K,L和M,如果它们形成一个三角形将返回1,否则返回0。 如果输入参数超出算法支持的范围,我需要返回-1。 示例:

function trigTest(K, L, M)

var K=[2,3,6,9], L=[8,1,6,9], M=[8,1,2,3], X=[1,7,6,9]
trigTest(K, L, M) // -> 1
trigTest(L, K, M) // -> 1
trigTest(M, K, L) // -> 1
trigTest(L, L, M) // -> 0
trigTest(X, L, M) // -> 0

enter image description here

我实际上有一个解决方案,但它非常麻烦,我不认为这是正确的方法。首先,我计算每个线段的距离,然后使用triangle inequalities检查它们是否实际上可以根据它们的长度形成三角形。

function distance(line){
var x1 = line[0],
y1 = line[1],
x2 = line[2],
y2 = line[3];

return Math.sqrt(Math.pow((x2-x1),2) + Math.pow(y2-y1),2) 
}

function trigTest(K,L,M){
var distanceK = distance(K), distanceL = distance(L), distanceM = distance(M);
if((distanceK + distanceL) > distanceM && (distanceK + distanceM) > distanceL && distanceL + distanceM > distanceK){
// algorithm here
}else{
return 0;
}
}

更新

感谢@antoniskamamis和@​​trincot我有一个类似的解决方案,如果有人想坚持使用数组而不是使用字符串。对他们大喊大叫。

function trigTest(K, L, M) {
  var points = [];
  var k = dots(K), l = dots(L), m = dots(M);

  if(ifDotsOnSameLineAreEqual(k) || ifDotsOnSameLineAreEqual(l) || ifDotsOnSameLineAreEqual(m)){
    return false;
  }else{
    return points.concat(k,l,m).every(function(point, index, array){
      return array.filter(function(i){ return ifTwoDotsAreEqual(i,point)}).length == 2;
    })
  }
}

function dots(line) {
  var x1 = line[0], 
      y1 = line[1],
      x2 = line[2],
      y2 = line[3];
  return [[x1,y1],[x2, y2]];
}

function ifTwoDotsAreEqual(x,y){
  return x[0] == y[0] && x[1] == y[1];
}

function ifDotsOnSameLineAreEqual(line){
  return ifTwoDotsAreEqual(line[0],line[1]);
}

3 个答案:

答案 0 :(得分:3)

你可以使用这种方法

function trigTest(a,b,c){
   var parts = [];
   Array.prototype.slice.call(arguments).forEach(function(item){
    parts.push(item.slice(0,2).join("|"));
    parts.push(item.slice(2).join("|"));
   })

   return parts.every(function(item, index, array){
     return array.filter( function(x){ return x == item}).length == 2;
   })
}

它的作用是:

  1. 遍历参数列表 Array.prototype.slice.call(arguments).forEach
  2. 将数组分成前两个点,最后两个作为字符串parts.push(item.slice(0,2).join(""));parts.push(item.slice(2).join(""));
  3. 给定点数组,它检查每个点是否存在两次parts.every(function(item, index, array){ return array.filter( function(x){ return x == item}).length == 2; })
  4. 使用'一个班轮'

    function trigTest(a,b,c){
       var slice = Array.prototype.slice;
       return slice.call(arguments).reduce(function(previous, current){
         previous.push(current.slice(0,2).join("|"));
         previous.push(current.slice(2).join("|"));
         return previous;
       }, [])
      .every(function(item, index, array){
        return array.filter( function(x){ return x == item; }).length == 2;
       })
    }
    

    检查零线长度

    如果我们知道在我们必须添加一个检查之前输入没有被验证为行,如果任何给定的行具有相同的起点和终点(是0长度线或点)

    在这种情况下,我们的代码必须像这样

    function trigTest(a,b,c){
       var slice = Array.prototype.slice;
    
       if(slice.call(arguments).some(isPoint)){
         return false;
       };
    
       return slice.call(arguments).reduce(function(previous, current){
         previous.push(current.slice(0,2).join("|"));
         previous.push(current.slice(2).join("|"));
         return previous;
       }, [])
      .every(function(item, index, array){
        return array.filter( function(x){ return x == item; }).length == 2;
       })
    }
    
    function isPoint(value){
      return value[0] == value[2] && value[1] == value[3];
    }
    

答案 1 :(得分:1)

根据你的例子,关键标准是你有三个x,y坐标的两个副本,所以不是从几何或三角学的角度来处理这个问题,你可以更容易地在基础上处理这个问题。 set-theory:有一个由三个点A,B,C组成的三角形,你的线段必须遵循[Ax,Ay,Bx,By],[Bx,By,Cx,Cy],[Cx,Cy, Ax,Ay]。

这些段不需要按顺序排列,例如[Bx,By,Ax,Ay]也适用于第一个词。

要检查有效三角形,首先计算重复坐标以验证三个唯一坐标的两个重复(这也将消除重复的线段),然后验证每个线段的长度是否为非零(不是[Ax,Ay] ,Axe,Ay])。这两项检查将处理前两项要求。

我不知道边界限制,所以我不能建议如何测试它是否超出算法范围,但我怀疑需要检查实际坐标范围,即整数算术。

这种方法应该可以在任何javascript引擎中使用,尽管您选择的javascript引擎将决定实现它的最佳方式。

答案 2 :(得分:0)

    var getRandom = () => 1+ Math.floor( Math.random() * 3 ) ;

    // get random line
    var getLine = () => 
        {   
            do
                var l =  { 
                        'a' : {
                            'x' : getRandom(), 
                            'y' : getRandom()
                        },
                        'b' : {
                            'x' : getRandom(),
                            'y' : getRandom() 
                        }
                };

            // repeat until startPoint differ from endPoint
            while ( l.a.x == l.b.x & l.a.y == l.b.y )

            return l;
        };

    var match = (K, L, M) => {

        // Tirangle consist of three points

        // three lines -> six points
        var p1 = K.a.x + "," + K.a.y,
            p2 = K.b.x + "," + K.b.y,
            p3 = L.a.x + "," + L.a.y,
            p4 = L.b.x + "," + L.b.y,
            p5 = M.a.x + "," + M.a.y,
            p6 = M.b.x + "," + M.b.y;

        // count frequency
        var freq = {};

        freq[p1] = freq[p1] + 1 || 1;
        freq[p2] = freq[p2] + 1 || 1;
        freq[p3] = freq[p3] + 1 || 1;
        freq[p4] = freq[p4] + 1 || 1;
        freq[p5] = freq[p5] + 1 || 1;
        freq[p6] = freq[p6] + 1 || 1;

        // result Array
        var result = Array();

        for ( point in freq ){

            // if the point is common for two lines add to result array
            freq[point] == 2 ? result.push( point ) : false;
        }

        return result;
    }

    var test = () => {

        // Three random lines
        var K = getLine(), L = getLine(), M = getLine();

        // Test if three lines has three common points
        if ( match(K, L, M).length == 3 ) {

            printSvg(K,L,M);

            return 1

        } else {

            return 0
        }
    }

    // run when document ready
    var app = () => {

        // div#box needed to print svg with triangles
        const box = document.getElementById('box');

        // test random lines, repeat
        for (x =0;  x <= 1000; x++) {

                t = test ();
        }
    }

    // fire app() when document ready
    document.onreadystatechange = ()=> document.readyState == "complete" ? app() : false;


    // format legend html
    var printWsp = (L) => "("+ L.a.x + ","+ L.a.y+") ("+L.b.x+","+L.b.y+")";

    // append svg to div#box
    var printSvg = (K, L, M) => {

        var legend = '<div class="legend">K ' + printWsp(K) +"<br>L " + printWsp(L) +"<br>M "+ printWsp(M) + "</div>";

        var svgStr = "<svg height='250' width='250'>";
            svgStr += "<line x1="+K.a.x*60 +" y1="+K.a.y*60 +" x2="+K.b.x*60 +" y2="+K.b.y*60 +" style='stroke:rgb(255,0,0);stroke-width:2' />";
            svgStr += "<line x1="+L.a.x*60 +" y1="+L.a.y*60 +" x2="+L.b.x*60 +" y2="+L.b.y*60 +" style='stroke:rgb(0,255,0);stroke-width:2' />";
            svgStr += "<line x1="+M.a.x*60 +" y1="+M.a.y*60 +" x2="+M.b.x*60 +" y2="+M.b.y*60 +" style='stroke:rgb(255,0,255);stroke-width:2' />";
            svgStr += "</svg> ";

        box.insertAdjacentHTML('beforeend', legend);
        box.insertAdjacentHTML('beforeend', svgStr);

    }