drawArc(arc) ignores the direction of the arc

playdate.graphics.drawArc(arc) draws every arc as if it is clockwise. I’m using SDK 1.12.0 on macOS 12.4, but the issue occurs on device as well (OS 1.12.0).

Unless I’m misunderstanding the documentation for how to create an arc, I would expect the following two pieces of Lua code to produce different results:

import "CoreLibs/graphics"

local clockwiseArc = playdate.geometry.arc.new(100, 100, 50, 1, 45, true)
playdate.graphics.drawArc(clockwiseArc)

(which I would expect to look like the edge of a pie slice)

vs:

import "CoreLibs/graphics"

local counterClockwiseArc = playdate.geometry.arc.new(100, 100, 50, 1, 45, false)
playdate.graphics.drawArc(counterClockwiseArc)

(which I would expect to look like the rest of the pie minus the slice)

However, both of these draw the same thing, a clockwise arc from 1° to 45°, i.e. the small pie slice, like in this screenshot:

looks like drawArc isn't checking the clockwise flag. Here's a version with that fixed:

local lineWidthNag = true
function playdate.graphics.drawArc(x, ...)

	local y, radius, startAngle, endAngle
	local tempLineWidth = nil
	
	if (type(x) == "userdata") then
		if x.clockwise then 
			startAngle = x.startAngle
			endAngle = x.endAngle
		else
			startAngle = x.endAngle
			endAngle = x.startAngle
		end
		x, y, radius = x.x, x.y, x.radius
		tempLineWidth = select(1, ...)
	else
		y, radius, startAngle, endAngle, tempLineWidth = select(1, ...)
	end
	
	if lineWidthNag == true and tempLineWidth ~= nil then
		print("Warning: playdate.graphics.drawRoundRect no longer accepts a lineWidth argument, please set the line width using playdate.graphics.setLineWidth() instead")
		lineWidthNag = false
	end

	local d = radius * 2
	g.drawEllipseInRect(x-radius, y-radius, d, d, startAngle, endAngle)	
	
end

I'll file it, thanks!

1 Like

I'm no Lua expert, but at a glance is that version not considering the case where clockwise == nil? The API documentation states that if the argument is absent, the winding is determined from the angles automatically. Without checking for nil explicitly, I feel like it gets dumped into the else clause and gets processed as counter-clockwise.

arc.new sets the flag with

int clockwise = (startAngle < endAngle) ? 1 : 0;

so there shouldn't be a case where it's not set. Also arc is implemented in C so clockwise won't ever be nil, unlike in Lua :slight_smile:

Ah yes, Arc is an object. My C brain has certain forms of autopilot.

Does this account for situations where the angles are not in the [0, 360) range, or where they "wrap" around 360? I feel like start=350 end=10 should be drawn in a clockwise direction unless specified, but I can see a case to be made either way. Inside Playdate doesn't specify how the direction is determined.

If the direction is specified and the spread angle is at or above 360 degrees, does it switch to drawing only one full circle?


Also, because I'm a pedantic stinker, I'm obligated to point out that the < operator in C explicitly yields the integer value 0 or 1. And that < has higher precedence than ?: so those parentheses aren't necessary. (-:

If the direction is specified and the spread angle is at or above 360 degrees, does it switch to drawing only one full circle?

I don't know. Try it and find out! :smiley:

Hm, I'm not sure how I could test it. If the arc exceeds 360 degrees, it would just retrace over existing pixels and I wouldn't be able to gauge any difference.

Unless you're suggesting there's some kind of exception case that happens when you attempt it. In that case, disregard!

Okay, I tried it. Drawing from 1 to 405 degrees gives the same result as drawing from 1 to 45. When I glanced at the source I didn't see any checking against 360 degrees, just sin and cos to convert angles to coordinates, so that's what I expected.

I guess I'll file that as a bug so we have it in the system, but it's so low priority I don't expect we'll ever change that behavior

2 Likes

Ran into this today too, this little snippet seemed to do the trick for me, but it's not rigorously tested:

local origDrawArc = playdate.graphics.drawArc
function playdate.graphics.drawArc(arc)
  if arc:isClockwise() then
    origDrawArc(arc.x, arc.y, arc.radius, arc.startAngle, arc.endAngle)
  else
    origDrawArc(arc.x, arc.y, arc.radius, arc.endAngle, arc.startAngle)
  end
end
1 Like