在javascript中逆时针排序点

时间:2017-08-13 13:14:51

标签: javascript sorting canvas

我在画布中引入了一组点: My canvas with set of points

我必须将此算法应用于: Algo NoObtuse and example of graph produced by this algo

我的问题是从最右边的点开始,以逆时针顺序找到以下点(算法中的第2点)。

那么,每次从一个点开始,我们如何才能在这个方向找到以下几点?

编辑: - > Blindman67

的代码结果
//First points (before sort and anti-clockwise)
//(6) [Point, Point, Point, Point, Point, Point]
0: Point {x: 458, y: 249, col: "red"}
1: Point {x: 333, y: 40, col: "red"}
2: Point {x: 138, y: 111, col: "red"}
3: Point {x: 336, y: 209, col: "red"}
4: Point {x: 237, y: 251, col: "red"}
5: Point {x: 60, y: 351, col: "red"}

//Points after sort and anti-clockwise
//(6) [Point, Point, Point, Point, Point, Point]
0: Point {x: 336, y: 209, col: "red", angle: 6.456745983859364}
1: Point {x: 333, y: 40, col: "red", angle: 5.156558533568968}
2: Point {x: 138, y: 111, col: "red", angle: 3.75120843247896}
3: Point {x: 60, y: 351, col: "red", angle: 2.4782921522301162}
4: Point {x: 237, y: 251, col: "red", angle: 1.9481922940313214}
5: Point {x: 458, y: 249, col: "red", angle: 0.26263427391514854}

1 个答案:

答案 0 :(得分:5)

按旋转顺序对点进行排序

从最右边开始以某个方向对点进行排序,并使用空间中心作为参考点。

// Array of points;
const points = [{x:?,y:?},{x:?,y:?},{x:?,y:?},...?];

// Find min max to get center
// Sort from top to bottom
points.sort((a,b)=>a.y - b.y);

// Get center y
const cy = (points[0].y + points[points.length -1].y) / 2;

// Sort from right to left
points.sort((a,b)=>b.x - a.x);

// Get center x
const cx = (points[0].x + points[points.length -1].x) / 2;

// Center point
const center = {x:cx,y:cy};

// Pre calculate the angles as it will be slow in the sort
// As the points are sorted from right to left the first point
// is the rightmost

// Starting angle used to reference other angles
var startAng;
points.forEach(point => {
    var ang = Math.atan2(point.y - center.y,point.x - center.x);
    if(!startAng){ startAng = ang }
    else {
         if(ang < startAng){  // ensure that all points are clockwise of the start point
             ang += Math.PI * 2;
         }
    }
    point.angle = ang; // add the angle to the point
 });


 // Sort clockwise;
 points.sort((a,b)=> a.angle - b.angle);

更新更正

 // ****************************************************
 // UPDATE the following code is incorrect
 // ****************************************************
 // Sort anti clockwise;
 // points.sort((a,b)=> b.angle - a.angle);
 // ****************************************************

 //=====================================================
 // the correct way to sort anticlockwise     
 //=====================================================

 // first sort clockwise
 points.sort((a,b)=> a.angle - b.angle);

 // then reverse the order
 const ccwPoints = points.reverse();

 // move the last point back to the start
 ccwPoints.unshift(ccwPoints.pop());

实施例

单击画布以重新运行以逆时针顺序排序的一组新随机点。

//.......................................................
// support code not part of the answer
const doFor = (count, cb) => { var i = 0; while (i < count && cb(i++) !== true); }; // the ; after while loop is important don't remove
const setOf = (count, cb = (i)=>i) => {var a = [],i = 0; while (i < count) { a.push(cb(i ++)) } return a };
const eachOf = (array, cb) => { var i = 0; const len = array.length; while (i < len && cb(array[i], i++, len) !== true ); };

const randI = (min, max = min + (min = 0)) => (Math.random() * (max - min) + min) | 0;
const rand  = (min = 1, max = min + (min = 0)) => Math.random() * (max - min) + min;
//.......................................................


// set up canvas and context
const ctx = canvas.getContext("2d");
canvas.width = 500;
canvas.height = 250;
ctx.font = "12px airal";
ctx.textAlign = "center";
ctx.textBaseline = "middle";


// create random points and then sort them in counterclockwise order 
// starting at the right most 
function doIt() {

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    function drawPoints() {
        eachOf(points, (point, i) => {
            ctx.beginPath();
            ctx.lineTo(center.x, center.y);
            ctx.lineTo(point.x, point.y);
            ctx.stroke();
            ctx.fillStyle = "white"
            ctx.fillText(i, point.x-2, point.y);
            ctx.fillText(i, point.x+2, point.y);
            ctx.fillText(i, point.x, point.y-2);
            ctx.fillText(i, point.x, point.y+2);
            ctx.fillStyle = "black"
            ctx.fillText(i, point.x, point.y);
        })
    }

    // Array of points;
    var points = setOf(8, () => ({
        x : rand(20, canvas.width - 40),
        y : rand(20, canvas.height - 40),
        angle : 0
    }));

    // Find min max to get center
    // Sort from top to bottom
    points.sort((a, b) => a.y - b.y);

    // Get center y
    const cy = (points[0].y + points[points.length - 1].y) / 2;

    // Sort from right to left
    points.sort((a, b) => b.x - a.x);

    // Get center x
    const cx = (points[0].x + points[points.length - 1].x) / 2;

    // Center point
    var center = {
        x : cx,
        y : cy
    };
    // Pre calculate the angles as it will be slow in the sort
    // As the points are sorted from right to left the first point
    // is the rightmost

    // Starting angle used to reference other angles
    var startAng;
    points.forEach(point => {
        var ang = Math.atan2(point.y - center.y, point.x - center.x);
        if (!startAng) {
            startAng = ang
        } else {
            if (ang < startAng) { // ensure that all points are clockwise of the start point
                ang += Math.PI * 2;
            }
        }
        point.angle = ang; // add the angle to the point
    });

    // first sort clockwise
    points.sort((a, b) => a.angle - b.angle);

    // then reverse the order
    const ccwPoints = points.reverse();

    // move the last point back to the start
    ccwPoints.unshift(ccwPoints.pop());
    drawPoints();
}
doIt()
canvas.onclick = doIt;
canvas { border : 2px solid black; }
<canvas id="canvas"></canvas>