Calculating percentage coordinates on an arc

Please forgive me, I'm not a math geek, I'm a Linux guy that's trying to do something cool. So straight out the gate, I do not understand advanced (or even what you might deem quite simple math). I graduated high school last millennium and barely passed math - so please bear with me.

What I'm doing is trying to get the x and y coordinates for a graph. Those coordinates need to be on an arc. Unfortunately, it goes a bit beyond that.

The graph has an origin in the very top-left. To make things interesting, we are also working with positive numbers going right and down (1,1 would be 1 to the right and 1 down from the origin).

• The arc is the top half of a circle.
• The circle's centre is at 200,190.
• the arc has a radius of 150.
• The "Start" of the arc (0%) is at 50,190. (and yes, it has to have a "start").
• From the "start", the half-circle then goes up and to the right, reaching the minimum y-value (50%) at 200,40.
• It then continues to the right and starts going down again to reach the end (100%) at 350,190.

What I need is to know the coordinates (x and y) for each percentage value along that arc.

Now, usually, I would include the things I have tried when it comes to other sites in stack exchange. However, to be honest, I do not even know where to start on this. So any help would be appreciated.

What I have done is ask ChatGPT and Gemini, but apparently this question foxes both of them and they give me values in the y axis of over 300 (which should not happen), and x values that just do not make any sense (the progression of 0% - 95% - 75% - 50% - 10% - 25% - 100% seems to make sense to them for some reason).

My apologies if this seems stupid, but it's been on my mind forever now and would just like to know how I can build a function (in JavaScript of all things) that can give me the coordinates for any percentage along that line.

I usually mess up where I put my first posts in a new stack site, so if this is the wrong one, please let me know the right one and I'll delete this post and move it if necessary.

Hoping this is the right site and someone can help me out.

Here's a visual of what I'm working with:

• Related wikipedia page Commented Jun 18 at 5:51
• There are 2 (or 3) ways to interpret 25%: (1) that 25% of the arc comes before this point, (2) that a line drawn from the center to the point cuts off 25% of the semi-circle (same point as (1) because math), or (3) that a line drawn from this point straight down to the horizontal line cuts off 25% of the semi-circle. It sounds like you want (1), can you confirm? Commented Jun 18 at 16:26

All you want is the angle along the line.

There is a straightforward linear relationship between arc length and subtended angle

$$s = R\theta$$

which is a linear relationship. That means $$z$$% of the arc length will be exactly $$z$$% of $$180^\circ$$, or $$\pi$$ (we must use radians for the above formula to be valid). In a regular coordinate system with $$+y$$ being up instead of down, we can think of this as the bottom half of a circle moving counter clockwise. For a given angle, my location on the arc of the bottom half of circle of radius $$R$$ centered at $$(a,b)$$ traversing it counter clockwise will be given by

$$(x,y) = (a - R\cos\theta,b-R\sin\theta)$$

Plugging in all of your givens, this results in a simple formula

$$(x,y) = \left(200-150\cos\left(\frac{\pi z}{100}\right),190-150\sin\left(\frac{\pi z}{100}\right)\right)$$

• That worked, thanks. and here's the Javascript if anyone is interested: Getting z as a percentage:  const z = (elapsedTime / dayDuration) * 100; then performing the function to get the X:  const x = 200 - 150 * Math.cos(Math.PI * z / 100); and finally the function to get the Y:  const y = 190 - 150 * Math.sin(Math.PI * z / 100);
– Jim
Commented Jun 18 at 19:29

Instead of thinking of it as percentages, just parameterize the curve using a parameter $$t \in [0, 1].$$

Any circle centered at $$(h, k)$$ with radius $$r$$ can be represented by $$x = h + r\cos t, \ y = k + r\sin t,$$ where the angles are measured in radians. Here, $$t \in [0, 2\pi)$$, enough for one full rotation going counterclockwise, which is the positive direction. (Many programming languages default to radians instead of degrees; consult the documentation.)

To change this for a semicircle, we instead change the parameter range to $$[0, \pi].$$ The parameterization is now $$x = h + r\cos t, \ y = k + r\sin t$$ for $$t \in [0, \pi].$$

We're almost to your task. Now, we want the parameter $$t$$ to be in the interval $$[0, 1]$$, and the semicircle should be traced clockwise starting from the "left." Here, our center is $$(h, k) = (200, 190)$$ and the radius is $$r = 150.$$ But how do we account for the specifics of our circle? We first scale the arguments of the sine and cosine accordingly and introduce a negative sign to the $$x$$ component so that it traces the path clockwise instead of counterclockwise. So, our desired parameterization is \begin{align*} x &= 200 + 150\cos(-\pi t) \\ y &= 190 - 150\sin(\pi t) \end{align*} for $$t \in [0, 1].$$ How can you check? Choose specific values of $$t$$ and plot them on the circle. You'll see that the direction of increasing $$t$$ is clockwise along the semicircle!

While I am no Javascript person, this is easy in Python:

import numpy as np
import matplotlib.pyplot as plt

# Create some grid of t values
t_grid = np.linspace(0, 1, 10)

# Two lambda functions to generate the x and y coordinates given t
x = lambda t: 200 + 150 * np.cos(-np.pi * t)
y = lambda t: 190 - 150 * np.sin(np.pi * t)

# Now plot these points
import numpy as np
import matplotlib.pyplot as plt

# Create some grid of t values
t_grid = np.linspace(0, 1, 10)

# Two lambda functions to generate the x and y coordinates given t
x = lambda t: 200 + 150 * np.cos(-np.pi * t)
y = lambda t: 190 - 150 * np.sin(np.pi * t)

# Now plot these points
plt.figure()
plt.scatter(x(t_grid), y(t_grid))
# This just verifies the path is traced in the
# correct direction. We use a finer grid for the
# parameter t here.
t_fine = np.linspace(0, 1, 100)
plt.plot(x(t_fine), y(t_fine), 'r-')
plt.arrow(200, 40, 10, 0, shape='full', lw=1, length_includes_head=True, head_width=5)
plt.show()


• The $y$ function has to go from $190$ down to $40$ and back up to $190$ (see the description of the reference frame), so just change the sign in front of the sine function Commented Jun 18 at 6:20
• In that case, the referenced photo in the OP does not follow the usual Cartestian coordinate directions. I've adjusted this. Commented Jun 18 at 6:22
• $(0,0)$ is in the upper left corner (typical for computer graphics) Commented Jun 18 at 6:42

The center of the circle is at $$x_c=200$$ and $$y_c=190$$, and the radius is $$R=150$$. I assume that the angle (say $$\alpha$$) is a linear function of the percentage, so $$\alpha=a\cdot p+b$$ If we write $$x=x_c+R\cos\alpha\\y=y_c+R\sin\alpha$$ we notice that the difference between $$p=100$$ and $$p=0$$ correspond to an angle of $$\pi$$ radians. As you go from $$p=0$$ to $$p=50$$ and $$p=100$$, you want $$\cos\alpha$$ to take values $$-1,0,1$$ and $$\sin\alpha$$ to be $$0,-1,0$$, or $$\alpha$$ varies from$$\pi$$ to $$2\pi$$. Therefore $$a=\pi/100$$ and $$b=\pi$$. You can then write your equations as $$x(p)=x_c+R\cos(\pi(p/100+1))\\y(p)=y_c+R\sin(\pi(p/100+1))$$