Asked 1 month ago by AstroNavigator664
Why Do Some p5.js Geometric Calculations Return NaN?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by AstroNavigator664
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
I'm new to coding and have been learning p5.js for a few weeks. I previously wrote a program that draws straight lines between evenly spaced points along the top and right edges of the canvas (producing a string art effect), but now I'm trying to create arcs instead of lines to introduce curves.
After refining the geometric calculations starting around line 37, I keep getting console warnings that two numerical variables are NaN. The warnings indicate issues with xInterceptOfNormal and circleCentreX. I suspect division-by-zero is causing these values to become NaN, especially in parts of the code where divisions occur (for example, with gradient and normalGradient calculations).
I’ve tried converting values using float(), as shown below, but without any success:
JAVASCRIPTxInterceptOfNormal = float(yInterceptOfNormal * -1 / normalGradient);
JAVASCRIPTarc(float(circleCentreX), circleCentreY, circleDiameter, circleDiameter, HALF_PI, PI, OPEN);
Here is the full code I'm working with:
JAVASCRIPTfunction setup() { //these are the variables that can be changed canvasWidth = 500; canvasHeight = 500; createCanvas(canvasWidth, canvasHeight); tileWidth = 500; tileHeight = 500; originX = 0; originY = 0; density1 = 100; //common factors of tileWidth and tileHeight only density2 = 100; //common factors of tileWidth and tileHeight only //stroke weight strokeWeight1 = 0.5; strokeWeight2 = 0.5; //background colours background1R = 255; background1G = 255; background1B = 255; background2R = 0; background2G = 0; background2B = 0; //stroke colours stroke1R = 0; stroke1G = 0; stroke1B = 0; stroke2R = 255; stroke2G = 255; stroke2B = 255; } function draw() { background(background1R, background1G, background1B); strokeWeight(strokeWeight1); stroke(stroke1R, stroke1G, stroke1B); noFill(); //tile 1 for (let topStartX = originX; topStartX < tileWidth; topStartX += density1) { for ( let rightEndY = originY; rightEndY <= tileHeight; rightEndY += density1 ) { //top points line(topStartX, originY, tileWidth, rightEndY); //right chordLength = sqrt( pow(tileWidth - topStartX, 2) + pow(rightEndY - originY, 2) ); //chord length tileHypotenuse = sqrt(pow(tileWidth, 2) + pow(tileHeight, 2)); gradient = (rightEndY - originY) / (tileWidth - topStartX); normalGradient = (1 / gradient) * -1; chordMidpointX = topStartX + (tileWidth - topStartX) / 2; chordMidpointY = originY + rightEndY / 2; yInterceptOfNormal = chordMidpointY - normalGradient * chordMidpointX; xInterceptOfNormal = (yInterceptOfNormal * -1 / normalGradient); A = sqrt(pow(tileWidth - topStartX, 2) + pow(chordLength / 2, 2)); line(0, yInterceptOfNormal, xInterceptOfNormal, 0); //normal to chord arcHeight = (chordLength / tileHypotenuse) * density1; //sagitta (height) of arc circleRadius = arcHeight / 2 + pow(chordLength, 2) / (8 * chordLength); //radius of arc ellipse circleDiameter = 2 * circleRadius; //diameter of arc ellipse t = arcHeight / A; arcCentreX = (1 - t) * chordMidpointX + t * (tileWidth - topStartX); arcCentreY = (1 - t) * chordMidpointY + t * rightEndY; circleCentreY = (topStartX * (pow(arcCentreX, 2) + pow(tileWidth, 2) - pow(arcCentreY, 2) + pow(rightEndY, 2)) + tileWidth * (pow(arcCentreY, 2) - pow(arcCentreX, 2) - pow(tileWidth, 2) - pow(rightEndY, 2))) / (2 * (topStartX - tileWidth) * (arcCentreY - rightEndY)); //y-coordinate of centre of arc ellipse circleCentreX = (pow(topStartX, 2) + pow(originY, 2) - 2 * circleCentreY * originY - pow(tileWidth, 2) - pow(rightEndY, 2) + 2 * circleCentreY * rightEndY) / (2 * (topStartX - tileWidth)); //x-coordinate of centre of arc ellipse //circle(circleCentreX, circleCentreY, circleDiameter); centralAngle = 2 * asin(chordLength / (2 * circleRadius)); //central angle subtending arc arc(circleCentreX, circleCentreY, circleDiameter, circleDiameter, HALF_PI, PI, OPEN); } } noLoop(); }
Any insights on how to prevent these division issues and avoid having NaN values in the calculations would be greatly appreciated!
Comments 0
•Answers 2
•Views 40
Answer by TychoAI Agent • 1 month ago
Below is one likely explanation and solution. In your nested loops the variables become NaN because of a division‐by‐zero case. For example, in this line:
JSgradient = (rightEndY - originY) / (tileWidth - topStartX); normalGradient = (1 / gradient) * -1;
if rightEndY is equal to originY then (rightEndY – originY) is 0. This makes gradient 0, and then 1/gradient is a division by zero. Later on similar divisions occur (such as in computing circleCentreY and circleCentreX) when a denominator becomes 0 (for example, because arcCentreY equals rightEndY). These divisions result in NaN that then propagate to functions like line() and arc().
You have two main choices:
Skip the problematic case:
If you do not really need to draw arcs for that particular configuration (when rightEndY equals originY) you can simply skip the loop iteration. For example:
JSfor (let topStartX = originX; topStartX < tileWidth; topStartX += density1) { for (let rightEndY = originY; rightEndY <= tileHeight; rightEndY += density1) { // Skip the case where the top and right points coincide at the corner if (rightEndY === originY) { continue; } // ... rest of your code ... } }
Adjust your starting point:
Instead of starting your inner loop at originY, you could start at originY + density1 so that you never have a zero numerator:
JSfor (let topStartX = originX; topStartX < tileWidth; topStartX += density1) { for (let rightEndY = originY + density1; rightEndY <= tileHeight; rightEndY += density1) { // ... rest of your code ... } }
Either approach prevents gradient from becoming 0. It’s also a good idea to include sanity checks before doing divisions. For example, you could write:
JSif (tileWidth - topStartX === 0) { continue; // or handle appropriately }
or
JSif (rightEndY - originY === 0) { continue; }
The error messages occur because you are dividing by zero in some iterations. By adjusting your loops (or checking the value before dividing) you can avoid computing a gradient of zero (or any other zero divisor) and thereby prevent the variables from becoming NaN.
I hope this helps you move forward with your string art project in p5.js!
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by LunarTracker070 • 1 month ago
Just before your second line()
call, add these lines:
JAVASCRIPTif( isNaN(yInterceptOfNormal) || isNaN(xInterceptOfNormal) || yInterceptOfNormal == Infinity || xInterceptOfNormal == Infinity ) { debugger }
You will see that at some point gradient
becomes 0, causing normalGradient
to be -Infinity
, causing xInterceptOfNormal
to become -Infinity
, and thus causing xInterceptOfNormal
to become NaN
From there you should be able to work back and figure out what in your code (algorithm) is causing the problem.
No comments yet.
No comments yet.