Page 1 of 1

Arcs and angles

Posted: Mon Aug 13, 2012 6:05 pm
by meoiswa
I'm trying to create an arc using mouse position.
The idea is that the arc begins where you start pressing the mouse button, and ends where the mouse is currently at
However I'm having some troubles because the angle is normalized or something,

Click then start dragging the mouse:
Image
Suddendly this happens:
Image

As you may see, the finish angle changes from a positive to a negative value :(

Code: Select all

function love.load()
	cx = love.graphics.getWidth()/2
	cy = love.graphics.getHeight()/2
	begin = 0
	finish = 0
end

function love.update(dt)
	mx = love.mouse.getX()
	my = love.mouse.getY()
	dx = mx-cx
	dy = my-cy
	angle = math.atan2(dy,dx)
	if love.mouse.isDown("l") then
		finish = angle
	end
end

function love.draw()

	love.graphics.arc("line",cx,cy,100,begin,finish)
	love.graphics.print("begin: "..begin.. " finish: "..finish,30,30)

end	

function love.mousepressed( x, y, button )
	mx = love.mouse.getX()
	my = love.mouse.getY()
	dx = mx-cx
	dy = my-cy
	angle = math.atan2(dy,dx)
	begin = angle
end

function love.mousereleased( x, y, button )
	begin = 0
	finish = 0
end

Re: Arcs and angles

Posted: Mon Aug 13, 2012 6:20 pm
by dreadkillz
Hello, math.atan2 returns the smallest angle. So if your arc is 270 degrees, it will return -90. What happens is that when you arc crosses the horizontal, it switches angle from negative to positive and vice versa; this will switch the orientation of the arc. You'll need to add some sort of check to determine which way your mouse is spinning.

Re: Arcs and angles

Posted: Mon Aug 13, 2012 6:22 pm
by Xgoff
meoiswa wrote:I'm trying to create an arc using mouse position.
The idea is that the arc begins where you start pressing the mouse button, and ends where the mouse is currently at
However I'm having some troubles because the angle is normalized or something,

Click then start dragging the mouse:
<image>
Suddendly this happens:
<image>

As you may see, the finish angle changes from a positive to a negative value :(

Code: Select all

function love.load()
	cx = love.graphics.getWidth()/2
	cy = love.graphics.getHeight()/2
	begin = 0
	finish = 0
end

function love.update(dt)
	mx = love.mouse.getX()
	my = love.mouse.getY()
	dx = mx-cx
	dy = my-cy
	angle = math.atan2(dy,dx)
	if love.mouse.isDown("l") then
		finish = angle
	end
end

function love.draw()

	love.graphics.arc("line",cx,cy,100,begin,finish)
	love.graphics.print("begin: "..begin.. " finish: "..finish,30,30)

end	

function love.mousepressed( x, y, button )
	mx = love.mouse.getX()
	my = love.mouse.getY()
	dx = mx-cx
	dy = my-cy
	angle = math.atan2(dy,dx)
	begin = angle
end

function love.mousereleased( x, y, button )
	begin = 0
	finish = 0
end
iirc love uses the absolute value of the difference between the two angles to determine which of the two arcs it should draw

dunno, i just found love.graphics.arc to be frustrating. maybe i was just being stupid but i had to fuck around with the values A LOT just to get the corners of a rounded box to work. i ended up just writing my own arc function (i needed the capability to leave off the two straight lines, which love.graphics.arc doesn't have an option for)

Re: Arcs and angles

Posted: Mon Aug 13, 2012 6:51 pm
by meoiswa
Can I get to see that custom arc function? I want to be able to draw this shape and I guess I'll have to create my own function for that:
Image

Re: Arcs and angles

Posted: Mon Aug 13, 2012 8:13 pm
by dreadkillz
Here's an example where you can use the dot and cross product so that the orientation of the arc remains constant while drawing it.

Code: Select all

function love.load()
   cx = love.graphics.getWidth()/2
   cy = love.graphics.getHeight()/2
   begin = 0
   finish = 0
end

function love.update(dt)
   mx = love.mouse.getX()
   my = love.mouse.getY()
   if love.mouse.isDown("l") then
	   x2,y2 = mx-cx,my-cy
	   dot = x1*x2+y1*y2 -- find delta angle by using dot product
	   lprod = math.sqrt((x1*x1+y1*y1)*(x2*x2+y2*y2))
	   angled = math.acos(dot/lprod)
	   crossK = x1*y2-y1*x2 -- fine direction of angle by cross product
	   if crossK < 0 then angled = -angled end
	   finish = finish+angled
	   x1,y1 = x2,y2
   end
end

function love.draw()
   love.graphics.arc("line",cx,cy,100,begin,finish)
   love.graphics.print("begin: "..begin.. " finish: "..finish,30,30)

end   

function love.mousepressed( x, y, button )
   x1,y1 = mx-cx,my-cy
   begin = math.atan2(y1,x1)
   finish = begin
end

function love.mousereleased( x, y, button )
   begin = 0
   finish = 0
end

Re: Arcs and angles

Posted: Mon Aug 13, 2012 9:43 pm
by meoiswa
Thank you very much, I guessed using dot product I could achieve what I wanted but I kept failing to do it :c

Re: Arcs and angles

Posted: Mon Aug 13, 2012 9:43 pm
by Xgoff
meoiswa wrote:Can I get to see that custom arc function? I want to be able to draw this shape and I guess I'll have to create my own function for that:
Image
this is what i used: positive sweep goes ccw, negative goes cw

Code: Select all

local function arc (mode, x, y, radius, start, sweep, segments, omitlines)
	local points = { }
	
	sweep = math.max(-math.pi * 2, math.min(sweep, math.pi * 2))
	
	local o = 0
	if mode == "fill" or not omitlines then
		o = 2
		points[1] = x
		points[2] = y
	end
	
	segments = (segments or 10) - 1
	
	for i = 0, segments do
		local dir = start + (i / segments) * sweep
		
		points[o+i*2+1] = math.cos(dir) * radius + x
		points[o+i*2+2] = -math.sin(dir) * radius + y
	end

	if mode == "fill" then
		love.graphics.polygon("fill", points)
	elseif mode == "line" then
		if not omitlines then
			points[#points+1] = x
			points[#points+1] = y
		end
		love.graphics.line(points)
	end
end
not extensively tested

EDIT: technically this by itself wouldn't draw the exact shape you want (it could just be used for the outline)

Re: Arcs and angles

Posted: Tue Aug 14, 2012 1:56 am
by Ref
Again Xgoff has outdone me but for what's it worth, heres my approach:

Code: Select all

function arc_seg()
    local acx, acy        = mask.width/2, mask.height/2	                -- arc center
    local rado, radi      = 1.5 * mask.size, mask.size                      -- outer & inner radius
    local arco, arci       = {}, {}                                                     -- tables of arc points
    local arcs, arce       = mask.angle, mask.angle + mask.circle	-- start & ending angle
    local idx                 = mask.size / 4			-- steps in arc
    local val                 = 1
    for i = arcs, arce,pi / idx do
        local xo             = rado * math.cos(i) + acx
        local yo             = rado * math.sin(i) + acy
        local xi              = radi * math.cos(i) + acx
        local yi              = radi * math.sin(i) + acy
        arco[val]           = { xo, yo }
        arci[val]            = { xi, yi }
        val                    = val + 1
        end
    for i = 1, #arco - 1 do		-- polygon can't handle all the points at once
        gr.polygon('fill',
        arco[i][1], arco[i][2], arco[i+1][1], arco[i+1][2],
        arci[i+1][1], arci[i+1][2], arci[i][1], arci[i][2])
        end
    end
Added code to my test script 'mask.love'.
<c><v> change the number of segments in arc
<q><w> change radius of arc
Polygon adds a hidden gotch-u because of its limits.

Re: Arcs and angles

Posted: Wed Aug 15, 2012 8:28 pm
by arundel
You can try to get the degrees between the origin and mouse pos ( 0 to 360 deg) along the unit circle with no negative value:

Code: Select all

math.deg(math.atan2(t1.y-t2.y,t1.x-t2.x))+180