简体   繁体   中英

Getting closest angle from array of angles clockwise and anticlockwise

I have four angles of div corners from origin, I have one more new angle suppose θ to compare to these angles, now I need the closest angle anticlockwise and clockwise to θ.

θ = -26 // new angle
a = [-15, 15, -165, -195]; // array of angles

anticlockangle = ? // closest angle anticlockwise to θ from array
clockangle = ? // closest angle clockwise to θ from array

In my opinion this is the most optimal solution. We sort the array by order then we look for the next value of the array thanks to find and our condition.

 const θ = 90 // new angle let a = [-15, 15, -165, -195]; // array of angle a.sort((a, b) => ab); let anticlockangle; for (i = θ; i > -360; i -= 1) { if (a.find(element => element === i)) { anticlockangle = i; break; } } if (anticlockangle === undefined) { anticlockangle = a[a.length - 1]; } let clockangle; for (i = θ; i < 360; i += 1) { if (a.find(element => element === i)) { clockangle = i; break; } } if (clockangle === undefined) { clockangle = a[0]; } console.log(anticlockangle); console.log(clockangle);

This is not the most optimal solution, but something like this should get you close:

const theta = -26
const angles = [-15, 15, -165, -195]
let lowestAngle = null
let highestAngle = null
let previousAngle = null
let nextAngle = null
for (let index = 0; index < a.length; index++) {
  const angle = angles[index]
  if (lowestAngle === null || angle < lowestAngle) {
    lowestAngle = angle
  }
  if (highestAngle === null || angle > highestAngle) {
    highestAngle = angle
  }
  if (angle < theta) {
    // If this is the first angle less than theta or if this angle is closer to theta than the current previous, save it
    if (previousAngle === null || angle > previousAngle) {
      previousAngle = angle
    }
  }
  else if (angle > theta) {
    // If this is the first angle greater than theta or if this angle is closer to theta than the current next, save it
    if (nextAngle === null || angle < nextAngle) {
      nextAngle = angle
    }
  }
  else {
    // angle matches theta...what do you want to do here?
  }
}
// No previous angle found; loop around to the highest angle
if (previousAngle === null) {
  previousAngle = highestAngle
}
// No next angle found; loop around to the lowest angle
if (nextAngle === null) {
  nextAngle = lowestAngle
}

My solution takes in account wraparounds and works for any angles. Even if input range exceeds the standard ranges 0°...360° and -180°... +180° (as it does with the -195 value in example) or if the values are float and not int. I now fixed the program and wrote it in proper javascript - and tested it on https://playcode.io/

θi = -26;
ai = [-15, 15, -165, -195];
// loop test: ai = [-161.5, -82.6, +53.7, +174.8]; // array of angles

a = [0, 0, 0, 0]
for (i = 0; i < ai.length; i++)
{
    a[i] = getValueBetween0And360(ai[i]);
}
console.log(`a = ${ai} (${a})`);

// loop test: for(θi = -400; θi <= +400; θi += 33.3) // new angle
{
    θ = getValueBetween0And360(θi);
    //console.log(`θi = ${θi}, θ = ${θ}`);
    
    
    ccw = ai[getIndexOfNearestAngle(a, θ, -1)]; // closest angle anticlockwise to θ from array
    cw = ai[getIndexOfNearestAngle(a, θ, +1)]; // closest angle clockwise to θ from array
    console.log(`θ = ${θi.toFixed(1)} (${θ.toFixed(1)}),\tccw = ${ccw.toFixed(1)} (${getValueBetween0And360(ccw).toFixed(1)}),\tcw = ${cw.toFixed(1)} (${getValueBetween0And360(cw).toFixed(1)})`);

}

function getValueBetween0And360(input)
{
    if (input < 0)
    {
        return (input + (Math.trunc(-input / 360) + 1.0) * 360.0) % 360.0;
    }
    return input % 360.0;
}

function getValueBetweenPlusMinus180(input)
{
    in360 = getValueBetween0And360(input);
    return 180 < in360
             ? in360 - 360
             : in360;
}

// sign = +1 for clock wise (cw), -1 for counter clock wise (ccw)
// starting from angle θ towards found angle in array a
function getIndexOfNearestAngle(a, θ, sign)
{
    var iF = -1;
    var diffF = 1000;

    for (var i = 0; i < a.length; i++)
    {
        var diff = sign * getDiffClockWise(a[i], θ);
        var diffPos = getValueBetween0And360(diff);
        //console.log(`start a[${i}] = ${a[i]}, diffPos = ${diffPos}, iF = ${iF}, diffF = ${diffF}, sign = ${sign}`);
        
        if (diffPos < diffF)
        {
            diffF = diffPos;
            iF = i;
        }
        //console.log(`end   a[${i}] = ${a[i]}, diffPos = ${diffPos}, iF = ${iF}, diffF = ${diffF}`);
    }
    
    return iF;
}
 
function getDiffClockWise(a, θ)
{
    //console.log(`diff = ${a - θ}, a = ${a}, θ = ${θ}`)
    return a - θ;
}

The result is:

a = -15,15,-165,-195 (345,15,195,165)
θ = -26.0 (334.0),  ccw = -165.0 (195.0),   cw = -15.0 (345.0)

If the // loop test: is replaced in the code with nothing, it reports these examples showing wrap arounds and float work too:

a = -161.5,-82.6,53.7,174.8 (198.5,277.4,53.7,174.8)
θ = -400.0 (320.0), ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = -366.7 (353.3), ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = -333.4 (26.6),  ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = -300.1 (59.9),  ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = -266.8 (93.2),  ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = -233.5 (126.5), ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = -200.2 (159.8), ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = -166.9 (193.1), ccw = 174.8 (174.8),    cw = -161.5 (198.5)
θ = -133.6 (226.4), ccw = -161.5 (198.5),   cw = -82.6 (277.4)
θ = -100.3 (259.7), ccw = -161.5 (198.5),   cw = -82.6 (277.4)
θ = -67.0 (293.0),  ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = -33.7 (326.3),  ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = -0.4 (359.6),   ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = 32.9 (32.9),    ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = 66.2 (66.2),    ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = 99.5 (99.5),    ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = 132.8 (132.8),  ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = 166.1 (166.1),  ccw = 53.7 (53.7),  cw = 174.8 (174.8)
θ = 199.4 (199.4),  ccw = -161.5 (198.5),   cw = -82.6 (277.4)
θ = 232.7 (232.7),  ccw = -161.5 (198.5),   cw = -82.6 (277.4)
θ = 266.0 (266.0),  ccw = -161.5 (198.5),   cw = -82.6 (277.4)
θ = 299.3 (299.3),  ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = 332.6 (332.6),  ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = 365.9 (5.9),    ccw = -82.6 (277.4),    cw = 53.7 (53.7)
θ = 399.2 (39.2),   ccw = -82.6 (277.4),    cw = 53.7 (53.7)

Okay depending on ag-dev's first answer in revision history, I came up with following,

 θ = -26 // new angle a = [-15, 15, -165, -195]; // array of angles anticlockangle = getClosestAngle(θ,a,false); clockangle = getClosestAngle(θ,a,true); console.log(anticlockangle); console.log(clockangle); function getClosestAngle(θ, arr, is_clock) { arr.sort(); return is_clock? arr.find(element => element < θ): arr.find(element => element > θ); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM