Why does this code create arrays filled with the same repeating value?

I have been trying to write a simulator using the HTML5 Canvas. I have the following code to generate equipotential lines for electric fields.

function drawEqLines(charges) {
        // don't bother if there aren't any charges
        if (charges.length == 0) return;

        // the Charge class contains the charge of the charge as well as its x and y coordinates
        
        var fieldFilled = [];
        
        for (var i = 0; i < 10; i++) {
            fieldFilled.push([]);
            
            for (var j = 0; j < 10; j++) {
                fieldFilled[i].push(false);
            }
        }
        
        var calculatedFields = [];
        var maxForce = 0;

        for (var i = 0; i < fieldFilled.length; i++) {
            var direction = 1;
            for (var jj=0; jj < fieldFilled[i].length; jj++) {
               if (!fieldFilled[i][jj]) {
                   //create a path here

                   //Iterate at most 2 times in case the surface gets out of the area
                   for (var circleTimes = 0; circleTimes < 3; circleTimes+=2) {

                       //Define the center of the current block as a starting point of the surface
                       /* 
                       horizontalBlock and verticalBlock are the width and height of the canvas divided into 10 different sections.
                       _BlockHalf is half of one of the blocks
                       */
                       var curX = i * this.horizontalBlock + this.horizontalBlockHalf;
                       var curY = jj * this.verticalBlock + this.verticalBlockHalf;
                       // Point is a class that contains an x and y value
                       var curPt = new Point(curX, curY);

                       var direction = 1 - circleTimes;
                       var dots = [];
                       dots.push(curPt);

                       //Superposition the fields from all charges, and get the resulting force vector
                       var dirX = 0;
                       var dirY = 0;
                       var totalForce = 0;
                       for (var j = 0; j < charges.length; j++) {
                           var distX = curPt.x - charges[j].x;
                           var distY = curPt.y - charges[j].y;
                           var distanceSq = distX * distX + distY * distY;
                           var force = charges[j].charge / distanceSq;

                           var distanceFactor = force / Math.sqrt(distanceSq);

                           //Measure the initial force in order to match the equipotential surface points
                           totalForce += force;
                           dirX += distX * distanceFactor;
                           dirY += distY * distanceFactor;
                       }

                       //Maximum 2000 dots per surface line
                       var times = 2000;
                       while (times-- > 0) {

                           var dirTotal = Math.sqrt(dirX * dirX + dirY * dirY);
                           var stepX = dirX / dirTotal;
                           var stepY = dirY / dirTotal;
                           //The equipotential surface moves normal to the force vector
                           curPt.x = curPt.x + direction * 6 * stepY;
                           curPt.y = curPt.y - direction * 6 * stepX;

/*
 *
 * ***********************LOG LINE HERE***********************************
 *
*/
                           // this prints out unique values
                           console.log(curPt.x + ", " + curPt.y);

                           //Correct the exact point a bit to match the initial force as near it can
                           var minForceIndex = -1;
                           var minForceDiff = 0;
                           var minDirX = 0;
                           var minDirY = 0;
                           var minCurX = 0;
                           var minCurY = 0;

                           curPt.x -= 3 * stepX;
                           curPt.y -= 3 * stepY;

                           for (var pointIndex = 0; pointIndex < 7; pointIndex++, curPt.x += stepX, curPt.y += stepY) {
                               dirX = 0;
                               dirY = 0;

                               var forceSum = 0;
                               for (var j = 0; j < charges.length; j++) {
                                   var distX = curPt.x - charges[j].x;
                                   var distY = curPt.y - charges[j].y;
                                   var distanceSq = distX ** 2 + distY ** 2;
                                   var force = charges[j].charge / distanceSq;

                                   var distanceFactor = force / Math.sqrt(distanceSq);


                                   //Measure the initial force in order to match the equipotential surface points
                                   forceSum += force;
                                   dirX += distX * distanceFactor;
                                   dirY += distY * distanceFactor;
                               }

                               var forceDiff = Math.abs(forceSum - totalForce);

                               if (minForceIndex == -1 || forceDiff < minForceDiff) {
                                   minForceIndex = pointIndex;
                                   minForceDiff = forceDiff;
                                   minDirX = dirX;
                                   minDirY = dirY;
                                   minCurX = curPt.x;
                                   minCurY = curPt.y;
                               } else {
                                   break;
                               }
                           }

                           //Set the corrected equipotential point
                           curPt.x = minCurX;
                           curPt.y = minCurY;
                           dirX = minDirX;
                           dirY = minDirY;

                           //Mark the containing block as filled with a surface line.
                           var indI = parseInt(curPt.x / this.horizontalBlock);
                           var indJ = parseInt(curPt.y / this.verticalBlock);
                           if (indI >= 0 && indI < fieldFilled.length) {
                               if (indJ >= 0 && indJ < fieldFilled[indI].length) {
                                fieldFilled[indI][indJ] = true;
                               }
                            }

                           //Add the dot to the line (was commented out when I added the other log)
                           dots.push(curPt);

                           if (dots.length > 5) {
                               //If got to the begining, a full circle has been made, terminate further iterations
                               if (indI == i && indJ == jj) {
                                   distX = dots[0].x - curPt.x;
                                   distY = dots[0].y - curPt.y;
                                   if (distX * distX + distY * distY <= 49) {
                                       dots.push(new Point(dots[0].x, dots[0].y));
                                       times = 0;
                                       circleTimes = 3;
                                   }
                               }
                               //If got out of the area, terminate further iterations for this turn.
                               if (curPt.x < 0 || curPt.x > this.canvas.width || curPt.y < 0 || curPt.y > this.canvas.height) {
                                   times = 0;
                               }
                           }
                       }

                       calculatedFields.push([totalForce, dots]);
                       maxForce = Math.max(maxForce, Math.abs(totalForce));
                   }
               }
           }
        }

        console.log(calculatedFields);
        
        // draw the lines from the arrays of dots here...
}

The result of this code is an array that looks like this:

[
   [
      0.000007927962725256215,
      [
         // as you can see, these points are all the same
         {x: 114.16365557137308, y: 402.6147544331975},
         {x: 114.16365557137308, y: 402.6147544331975},
         {x: 114.16365557137308, y: 402.6147544331975},
         {x: 114.16365557137308, y: 402.6147544331975},
         // etc...
      ]
   ],
   [
       0.000006140401131528559,
       [
           {x: -1.0201768243546043, y: 323.28955989370445},
           {x: -1.0201768243546043, y: 323.28955989370445},
           {x: -1.0201768243546043, y: 323.28955989370445},
           {x: -1.0201768243546043, y: 323.28955989370445},
           // etc...
       ]
   ]
]

These points should be unique, however, it seems to just generate the same point over and over again. For some reason, it does decide to stop after a reasonable number of iterations, as if it is doing the calculations correctly but just putting the same point into the array anyway.

Why is this happening? How can I fix it?

Update: Here are the classes that I am using:

class Point {
   constructor(x, y) {
      this.x = x;
      this.y = y;
   }
}

class Charge {
   constructor(charge, x, y) {
      this.charge = charge;
      this.x = x;
      this.y = y;
   }
}

Also, the charges array is fine, because I use it in a similar method which does work correctly. An example for this would be:

[
   {charge: 6, x: 50, y: 50},
   {charge: -4, x: 70, y: 90.5},
   // etc...
]

Update 2:
I have tried adding the log line indicated in the above code, which prints out only unique values. However, even if I try pushing the point to the array here it still results in the same issue.

Update 3:
Added this runnable snippet:

const height = 400; // for example
const width = 600; // also for example

const horizontalBlock = width / 10;
const verticalBlock = height / 10;

const horizontalBlockHalf = horizontalBlock / 2;
const verticalBlockHalf = verticalBlock / 2;

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

function drawEqLines(charges) {
        // don't bother if there aren't any charges
        if (charges.length == 0) return;

        // the Charge class contains the charge of the charge as well as its x and y coordinates
        
        var fieldFilled = [];
        
        for (var i = 0; i < 10; i++) {
            fieldFilled.push([]);
            
            for (var j = 0; j < 10; j++) {
                fieldFilled[i].push(false);
            }
        }
        
        var calculatedFields = [];
        var maxForce = 0;

        for (var i = 0; i < fieldFilled.length; i++) {
            var direction = 1;
            for (var jj=0; jj < fieldFilled[i].length; jj++) {
               if (!fieldFilled[i][jj]) {
                   //create a path here

                   //Iterate at most 2 times in case the surface gets out of the area
                   for (var circleTimes = 0; circleTimes < 3; circleTimes+=2) {

                       //Define the center of the current block as a starting point of the surface
                       /* 
                       horizontalBlock and verticalBlock are the width and height of the canvas divided into 10 different sections.
                       _BlockHalf is half of one of the blocks
                       */
                       var curX = i * horizontalBlock + horizontalBlockHalf;
                       var curY = jj * verticalBlock + verticalBlockHalf;
                       // Point is a class that contains an x and y value
                       var curPt = new Point(curX, curY);

                       var direction = 1 - circleTimes;
                       var dots = [];
                       dots.push(curPt);

                       //Superposition the fields from all charges, and get the resulting force vector
                       var dirX = 0;
                       var dirY = 0;
                       var totalForce = 0;
                       for (var j = 0; j < charges.length; j++) {
                           var distX = curPt.x - charges[j].x;
                           var distY = curPt.y - charges[j].y;
                           var distanceSq = distX * distX + distY * distY;
                           var force = charges[j].charge / distanceSq;

                           var distanceFactor = force / Math.sqrt(distanceSq);

                           //Measure the initial force in order to match the equipotential surface points
                           totalForce += force;
                           dirX += distX * distanceFactor;
                           dirY += distY * distanceFactor;
                       }

                       //Maximum 2000 dots per surface line
                       var times = 2000;
                       while (times-- > 0) {

                           var dirTotal = Math.sqrt(dirX * dirX + dirY * dirY);
                           var stepX = dirX / dirTotal;
                           var stepY = dirY / dirTotal;
                           //The equipotential surface moves normal to the force vector
                           curPt.x = curPt.x + direction * 6 * stepY;
                           curPt.y = curPt.y - direction * 6 * stepX;

/*
 *
 * ***********************LOG LINE HERE***********************************
 *
*/
                           // this prints out unique values
                           console.log(curPt.x + ", " + curPt.y);

                           //Correct the exact point a bit to match the initial force as near it can
                           var minForceIndex = -1;
                           var minForceDiff = 0;
                           var minDirX = 0;
                           var minDirY = 0;
                           var minCurX = 0;
                           var minCurY = 0;

                           curPt.x -= 3 * stepX;
                           curPt.y -= 3 * stepY;

                           for (var pointIndex = 0; pointIndex < 7; pointIndex++, curPt.x += stepX, curPt.y += stepY) {
                               dirX = 0;
                               dirY = 0;

                               var forceSum = 0;
                               for (var j = 0; j < charges.length; j++) {
                                   var distX = curPt.x - charges[j].x;
                                   var distY = curPt.y - charges[j].y;
                                   var distanceSq = distX ** 2 + distY ** 2;
                                   var force = charges[j].charge / distanceSq;

                                   var distanceFactor = force / Math.sqrt(distanceSq);


                                   //Measure the initial force in order to match the equipotential surface points
                                   forceSum += force;
                                   dirX += distX * distanceFactor;
                                   dirY += distY * distanceFactor;
                               }

                               var forceDiff = Math.abs(forceSum - totalForce);

                               if (minForceIndex == -1 || forceDiff < minForceDiff) {
                                   minForceIndex = pointIndex;
                                   minForceDiff = forceDiff;
                                   minDirX = dirX;
                                   minDirY = dirY;
                                   minCurX = curPt.x;
                                   minCurY = curPt.y;
                               } else {
                                   break;
                               }
                           }

                           //Set the corrected equipotential point
                           curPt.x = minCurX;
                           curPt.y = minCurY;
                           dirX = minDirX;
                           dirY = minDirY;

                           //Mark the containing block as filled with a surface line.
                           var indI = parseInt(curPt.x / this.horizontalBlock);
                           var indJ = parseInt(curPt.y / this.verticalBlock);
                           if (indI >= 0 && indI < fieldFilled.length) {
                               if (indJ >= 0 && indJ < fieldFilled[indI].length) {
                                fieldFilled[indI][indJ] = true;
                               }
                            }

                           //Add the dot to the line (was commented out when I added the other log)
                           dots.push(curPt);

                           if (dots.length > 5) {
                               //If got to the begining, a full circle has been made, terminate further iterations
                               if (indI == i && indJ == jj) {
                                   distX = dots[0].x - curPt.x;
                                   distY = dots[0].y - curPt.y;
                                   if (distX * distX + distY * distY <= 49) {
                                       dots.push(new Point(dots[0].x, dots[0].y));
                                       times = 0;
                                       circleTimes = 3;
                                   }
                               }
                               //If got out of the area, terminate further iterations for this turn.
                               if (curPt.x < 0 || curPt.x > width || curPt.y < 0 || curPt.y > height) {
                                   times = 0;
                               }
                           }
                       }

                       calculatedFields.push([totalForce, dots]);
                       maxForce = Math.max(maxForce, Math.abs(totalForce));
                   }
               }
           }
        }

        console.log(calculatedFields);
        
        // draw the lines from the arrays of dots here...
}

var charges = [
  {charge: 6, x: 50, y: 75},
  {charge: -5, x: 60, y: 254.5}
]

drawEqLines(charges);

Leave a Comment