Rosetta Code: Circles of given radius through two points

Tell us what’s happening:
Describe your issue in detail here.
Floating point rounding issue… Wrong floating-point data being appended to the final array. Where specifically do I need to append the statement internally in order to accommodate the final appending process…?

I would do this via

[details]
Math.floor(expr*10000)/10000;
[/details] … Could someone please help?

  **Your code so far**
const hDist = (p1,p2) => Math.hypot(...p1.map((e, i) => e-p2[i]))/2;
const pAng = (p1,p2) => Math.atan(p1.map((e,i) => e-p2[i]).reduce(
(p, c) => c/p, 1));
const solveF = (p,r) => t => [r*Math.cos(t)+p[0], r*Math.sin(t)+p[1]];
const diamPts = (p1,p2) => p1.map((e,i) => e+(p2[i]-e)/2); 
const getCircles = (...args) => {
const [p1,p2,s] = args;
const solve = solveF(p1,s), halfDist = hDist(p1,p2);
let debugMsg = `p1: ${p1}, p2: ${p2}, r:${s}`;
console.log(`${debugMsg}`);
let msg = `Result: `, dCheck = Math.sign(s-halfDist), newArr = [];
switch (dCheck) {
  case 0:
    s ? newArr.push(diamPts(p1,p2)) : (msg='Radius Zero');
    break;
  case 1:
    if (!halfDist) {
      msg = 'Coincident point. Infinite solutions';
    } else {
      let theta = pAng(p1,p2), theta2 = Math.acos(halfDist/s);
      [1,-1].map(e => solve(theta + e*theta2)).forEach(e => 
      newArr.push(e));
    }
    break;
  case -1:
    msg ='No intersection. Points further apart than circle diameter';
    break;
} 
  console.log(`BEFORE: newArr: ${newArr}`);
  newArr.forEach((el) => el = [Math.floor(el[0]*10000)/10000, 
    Math.floor(el[1]*10000)/10000]);
  console.log(`AFTER: newArr: ${newArr}`);
  return (msg !=`Result: `) ? (msg): newArr; 
};
  **Your browser information:**

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36

Challenge: Circles of given radius through two points

Link to the challenge:

forEach doesn’t mutate array on it own and it always returns undefined, callback function might mutate the array, but it’d be more complicated than this. Consider using map method instead.

1 Like

Got the map for nA1, new map that floats corresponding… It’s flipping me the bird by making the second mapped el to be off by (+/- 1.0e-4)…
Else, it worked perfectly… Thank you for the assist.

const hDist = (p1,p2) => Math.hypot(...p1.map((e, i) => e-p2[i]))/2;
const pAng = (p1,p2) => Math.atan(p1.map((e,i) => e-p2[i]).reduce(
(p, c) => c/p, 1));
const solveF = (p,r) => t => [r*Math.cos(t)+p[0], r*Math.sin(t)+p[1]];
const diamPts = (p1,p2) => p1.map((e,i) => e+(p2[i]-e)/2); 
const getCircles = (...args) => {
  const [p1,p2,s] = args;
  const solve = solveF(p1,s), halfDist = hDist(p1,p2);
  let debugMsg = `p1: ${p1}, p2: ${p2}, r:${s}`;
  console.log(`${debugMsg}`);
  let msg = `Result: `, dCheck = Math.sign(s-halfDist), newArr = [];
  if (dCheck == 0){
      s ? newArr.push(diamPts(p1,p2)) : (msg='Radius Zero');
     } else if (dCheck ==1) {
       if (!halfDist) {
        msg = 'Coincident point. Infinite solutions';
      } else {
        let theta = pAng(p1,p2), theta2 = Math.acos(halfDist/s);
        [1,-1].map(e => solve(theta + e*theta2)).forEach(e => 
        newArr.push(e));
      } } else if(dCheck == -1) {
      msg ='No intersection. Points further apart than circle diameter';
      }
    let nA1 = newArr.map((el) => el = [(Math.floor(el[0]* 10000)/10000).toFixed(4),(Math.floor(el[1]*10000)/10000).toFixed(4)]);
    let consoleStrDebug = `nA1:`;
    if(nA1.length > 1) {consoleStrDebug += '['; }
    for(let i=0; i < nA1.length; i++) {
      let finalChar = (i < nA1.length-1) ? ', ':'';
     consoleStrDebug +=`[${nA1[i][0]},${nA1[i][1]}]${finalChar}`;
    }
    if(nA1.length > 1) {consoleStrDebug += ']'; }
    console.log(`${consoleStrDebug}\n`);
    return (msg !=`Result: `) ? (msg): nA1; 
};

Take a closer look at the calculations rounding the coordinates. To be a little more specific consider what actually happens when Math.floor method is used on the number below a zero.

In other words,

(round(expr*10000)/10000).toFixed(4)

in order to allow for upwards/ downwards modification…

Yes. There’s left just one small detail with using toFixed. It returns string and number of decimals is always the number passed to it, even if that would be only 0s. So it is here not needed.

const hDist = (p1,p2) => Math.hypot(...p1.map((e, i) => e-p2[i]))/2;
const pAng = (p1,p2) => Math.atan(p1.map((e,i) => e-p2[i]).reduce(
(p, c) => c/p, 1));
const solveF = (p,r) => t => [r*Math.cos(t)+p[0], r*Math.sin(t)+p[1]];
const diamPts = (p1,p2) => p1.map((e,i) => e+(p2[i]-e)/2); 
const getCircles = (...args) => {
  const [p1,p2,s] = args;
  const solve = solveF(p1,s), halfDist = hDist(p1,p2);
  let debugMsg = `p1: ${p1}, p2: ${p2}, r:${s}`;
  console.log(`${debugMsg}`);
  let msg = `Result: `, dCheck = Math.sign(s-halfDist), newArr = [];
  if (dCheck == 0){
      s ? newArr.push(diamPts(p1,p2)) : (msg='Radius Zero');
     } else if (dCheck ==1) {
       if (!halfDist) {
        msg = 'Coincident point. Infinite solutions';
      } else {
        let theta = pAng(p1,p2), theta2 = Math.acos(halfDist/s);
        [1,-1].map(e => solve(theta + e*theta2)).forEach(e => 
        newArr.push(e));
      } } else if(dCheck == -1) {
      msg ='No intersection. Points further apart than circle diameter';
      }
    let nA1 = newArr.map((el) => el = [(Math.round(el[0]*10000)/10000),
    (Math.round(el[1]*10000)/10000)]);
    let consoleStrDebug = `nA1:`;
    if(nA1.length > 1) { consoleStrDebug += '['; }
    for(let i=0; i < nA1.length; i++) {
      let finalChar = (i < nA1.length-1) ? ', ':'';
     consoleStrDebug +=`[${nA1[i][0]},${nA1[i][1]}]${finalChar}`;
    }
    if(nA1.length > 1) {consoleStrDebug += ']'; }
    console.log(`${consoleStrDebug}\n`);
    return (msg !=`Result: `) ? (msg): nA1; 
};

// running tests

getCircles([0.0000, 2.0000], [0.0000, 0.0000], 1.0)

should return

[0, 1]
// tests completed 
// console output 
p1: 0.1234,0.9876, p2: 0.8765,0.2345, r:2 
nA1:[[1.8631,1.9742], [-0.8632,-0.7521]] 

p1: 0,2, p2: 0,0, r:1 
nA1:[0,1] 

p1: 0.1234,0.9876, p2: 0.1234,0.9876, r:2 
nA1: p1: 0.1234,0.9876, p2: 0.8765,0.2345, r:0.5

nA1: 

p1: 0.1234,0.9876, p2: 0.1234,0.9876, r:0 
nA1:

… Needless to say, it is really close, just something is going wrong…

Printing to console the actual return value should give some idea what’s wrong:

console.log(getCircles([0.0000, 2.0000], [0.0000, 0.0000], 1.0))

It’s a multi-dim array… Bollocks…

const hDist = (p1,p2) => Math.hypot(...p1.map((e, i) => e-p2[i]))/2;
const pAng = (p1,p2) => Math.atan(p1.map((e,i) => e-p2[i]).reduce(
(p, c) => c/p, 1));
const solveF = (p,r) => t => [r*Math.cos(t)+p[0], r*Math.sin(t)+p[1]];
const diamPts = (p1,p2) => p1.map((e,i) => e+(p2[i]-e)/2); 
const getCircles = (...args) => {
  const [p1,p2,s] = args;
  const solve = solveF(p1,s), halfDist = hDist(p1,p2);
  let debugMsg = `p1: ${p1}, p2: ${p2}, r:${s}`;
  console.log(`${debugMsg}`);
  let msg = `Result: `, dCheck = Math.sign(s-halfDist), newArr = [];
  if (dCheck == 0){
      s ? newArr.push(diamPts(p1,p2)) : (msg='Radius Zero');
     } else if (dCheck ==1) {
       if (!halfDist) {
        msg = 'Coincident point. Infinite solutions';
      } else {
        let theta = pAng(p1,p2), theta2 = Math.acos(halfDist/s);
        [1,-1].map(e => solve(theta + e*theta2)).forEach(e => 
        newArr.push(e));
      } } else if(dCheck == -1) {
      msg ='No intersection. Points further apart than circle diameter';
      }
    let nA1 = [];
    for(let i=0; i< newArr.length; i++){
      if(newArr.length == 1) { 
        nA1 = [(Math.round(newArr[i][0]*10000)/10000),
                (Math.round(newArr[i][1]*10000)/10000)]; 
      } else {
        nA1.push([(Math.round(newArr[i][0]*10000)/10000),
                (Math.round(newArr[i][1]*10000)/10000)]);
      } 
    }  
    let consoleStrDebug = `nA1:`;
    if(nA1.length > 1) { consoleStrDebug += '['; }
    for(let i=0; i < nA1.length; i++) {
      let finalChar = (i < nA1.length-1) ? ', ':'';
     consoleStrDebug +=`[${nA1[i][0]},${nA1[i][1]}]${finalChar}`;
    }
    if(nA1.length > 1) {consoleStrDebug += ']'; }
    console.log(`${consoleStrDebug}\n`);
    return (msg !=`Result: `) ? (msg): nA1; 
};

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.