Parabola functions in Lua

Showcase your libraries, tools and other projects that help your fellow love users.
User avatar
darkfrei
Party member
Posts: 1209
Joined: Sat Feb 08, 2020 11:09 pm

Re: Parabola functions in Lua

Post by darkfrei »

The parabola is given by focus and directrix.
Finding the roots of parabola for given high y:

Code: Select all

function getFocusParabolaRoots (fx, fy, y) -- focus, horizontal line
	-- (directrix dirY is global)
	local h = fx -- x shift
	local p = -(dirY-fy)/2 -- always negative for voronoi
	local k = (fy - p) - y -- (fy-p) is vertex high
	local leftX = h - math.sqrt (-k*4*p)
	local rightX = h + math.sqrt (-k*4*p)
	return leftX, rightX
end
The parabola is given by focus and directrix.
Parabola curve is limited by points A (left) and B (right).
Finding control point C for quadratic Bezier curve for special case, where ay == by:
(based on the code of Mike 'Pomax' Kamermans)

Code: Select all

function getBezierControlPoint (fx, fy, ax, bx, dirY)
	local f = function (x)
		return (x*x-2*fx*x+fx*fx+fy*fy-dirY*dirY) / (2*(fy-dirY))
	end
	local function df(x)
		return (x-fx) / (fy-dirY)
	end
	if (fy == dirY) then return end -- not parabola
	local ay, by = f(ax), f(bx)
	if (ay == by) then -- special case: horizontal AB
		return fx, ay + 2*((fy + dirY) / 2-ay)
	else
		local ad = df(ax) -- tangent slope for A
		local dx = (bx-ax)/2
		return ax+dx, ay+ad*dx
	end
end
or just

Code: Select all

function getBezierControlPoint (fx, fy, ax, bx, dirY)
	local f = function (x) return (x*x-2*fx*x+fx*fx+fy*fy-dirY*dirY) / (2*(fy-dirY)) end
	local function df(x) return (x-fx) / (fy-dirY) end
	if (fy == dirY) then return end -- not parabola
	local ay, by = f(ax), f(bx)
	local ad, dx = df(ax), (bx-ax)/2
	return ax+dx, ay+ad*dx
end
Animation (83).gif
Animation (83).gif (436.42 KiB) Viewed 16662 times

Code: Select all

-- evaluate parabola for given focus and directrix, returns y-position for given x-position:
local function evaluateParabola(fx, fy, x, dirY)
    local numerator = fx*fx + fy*fy - dirY*dirY - x*(2*fx - x)
    local denominator = 2*(fy - dirY)
    return numerator / denominator
end
Attachments
voronoi-beachlines-01.love
(1.54 KiB) Downloaded 183 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1209
Joined: Sat Feb 08, 2020 11:09 pm

Re: Parabola functions in Lua

Post by darkfrei »

Two parabolas with common directrix have crossings on the same line:

The the function to get crossing for the given horizontal line is:

Code: Select all

function focusFocusLineYCrossing (p1x, p1y, p2x, p2y, y)
	local cx = (p1x+p2x)/2
	local cy = (p1y+p2y)/2
	local m = (p2y-p1y)/(p2x-p1x) -- slope
	local x = cx - m*(y-p1y) -- perpendicular to slope
	return x
end
main.lua:

Code: Select all

function newParabola (x, y)
	local parabola = {
		x=x, 
		y=y,
		minX = 0,
		maxX = love.graphics.getWidth(),
		minY = 0,
	}
	return parabola
end

local function getParabolaCrossPoint (p1x, p1y, p2x, p2y, dirY) -- focus 1, focus 2, directrix
-- Function to find the intersection point of two parabolas
	local f1 = math.abs(dirY-p1y)/2
	local f2 = math.abs(dirY-p2y)/2

	local a1 = -1/(4*f1)
	local a2 = -1/(4*f2)
	local b1 = -2*p1x*a1
	local b2 = -2*p2x*a2
	local c1 = p1x*p1x*a1 + p1y + f1
	local c2 = p2x*p2x*a2 + p2y + f2
	local a = a1-a2
	local b = b1-b2
	local c = c1-c2

	local d = b*b-4*a*c
	local x, y
	if d >=0 then
		x = (-b-math.sqrt (d))/(2*a)
		y = a1*x*x + b1*x + c1
	end
	return x, y
end

function getFocusParabolaRoots (fx, fy, y, dirY) -- focus, horizontal line
	local h = fx -- x shift
	local p = -(dirY-fy)/2 -- always negative for voronoi
	local k = (fy - p) - y -- (fy-p) is vertex high
	local leftX = h - math.sqrt (-k*4*p)
	local rightX = h + math.sqrt (-k*4*p)
	return leftX, rightX
end


function focusFocusLineYCrossing (p1x, p1y, p2x, p2y, y)
	local cx = (p1x+p2x)/2
	local cy = (p1y+p2y)/2
	local m = (p2y-p1y)/(p2x-p1x) -- slope
	local x = cx - m*(y-p1y) -- perpendicular to slope
	return x
end

function updateParabolas (p1, p2, dirY)
	local p1x, p1y = p1.x, p1.y
	local p2x, p2y = p2.x, p2.y
	local x, y = getParabolaCrossPoint (p1x, p1y, p2x, p2y, dirY)
	local x2 = focusFocusLineYCrossing (p1x, p1y, p2x, p2y, y)
--	print (x, x2, y)
	
	local pMinX1, pMaxX1 = getFocusParabolaRoots (p1x, p1y, frameMinY, dirY)
	local pMinX2, pMaxX2 = getFocusParabolaRoots (p2x, p2y, frameMinY, dirY)
	p1.minX = pMinX1
	p1.maxX = math.min (x, pMaxX1)
	p2.minX = math.max (x, pMinX2)
	p2.maxX = pMaxX2
	table.insert (points, x)
	table.insert (points, y)
	
--	table.insert (points2, x2)
--	table.insert (points2, y)
end


function love.load()
	frameMinY = 100
	
	parabola1 = newParabola (300, 250)
	parabola2 = newParabola (500, 300)

	points = {}
--	points2 = {}

	step = 0.25
	dirY = 302

	updateParabolas (parabola1, parabola2, dirY)

	love.window.setTitle ('press SPACE to start')
	pause = false
end

function love.update(dt)
	if pause then return end
	dirY = dirY + step^2
	step = step+0.02
	updateParabolas (parabola1, parabola2, dirY)
	if dirY > 800 then
		step = 0.25
		dirY = 302
		points = {}
	end
end

function getBezierControlPoint (fx, fy, ax, bx, dirY)
	local f = function (x) return (x*x-2*fx*x+fx*fx+fy*fy-dirY*dirY) / (2*(fy-dirY)) end
	local function df(x) return (x-fx) / (fy-dirY) end
	if (fy == dirY) then return end -- not parabola
	local ay, by = f(ax), f(bx)
	local ad, dx = df(ax), (bx-ax)/2
	return ax+dx, ay+ad*dx
end

function drawParabola (p, dirY)
	local fx = p.x
	local fy = p.y
	local ax, bx = p.minX, p.maxX
	local cx, cy = getBezierControlPoint (fx, fy, ax, bx, dirY)
	local ay = (ax*ax-2*fx*ax+fx*fx+fy*fy-dirY*dirY) / (2*(fy-dirY))
	local by = (bx*bx-2*fx*bx+fx*fx+fy*fy-dirY*dirY) / (2*(fy-dirY))
	local line = love.math.newBezierCurve (ax, ay, cx, cy, bx, by):render()
	love.graphics.line (line)
	
	love.graphics.circle ('fill', fx, fy, 2)
end

function love.draw()
	love.graphics.setColor (1,1,1)
	drawParabola (parabola1, dirY)
	drawParabola (parabola2, dirY)

	love.graphics.points (points)

	love.graphics.line (0, frameMinY, love.graphics.getWidth(), frameMinY)

	love.graphics.line (0, dirY, love.graphics.getWidth(), dirY)
	
--	love.graphics.setColor (1,1,0)
--	love.graphics.points (points2)
end

function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "space" then
		pause = not pause
	elseif key == "escape" then
		love.event.quit()
	end
end
Animation (92).gif
Animation (92).gif (295.39 KiB) Viewed 16516 times
:awesome: update

Easy Desmos Graph for parabola, given with focus and directrixY:
https://www.desmos.com/calculator/bh79htktms

Code: Select all

-- parabola as y=f(x):
y = ((x-fx)^2 + fy^ - dirY^2)/(2*fy*dirY)
Same, but with roots (left and right points with y = 0):
https://www.desmos.com/calculator/pjdwhme7op
https://www.desmos.com/calculator/eub7faugrn

Code: Select all

local dx = ((2*fy + dirY - fy)*(dy-fy))^0.5
-- left x:
x1 = fx - dx
-- right x: 
x2 = fx + dx
Attachments
two-parabolas-crossing-01.love
(1.43 KiB) Downloaded 238 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1209
Joined: Sat Feb 08, 2020 11:09 pm

Re: Parabola functions in Lua

Post by darkfrei »

This function calculates the intersection points between a parabola defined by its focus and directrix and an inclined line represented by the equation
y=kx+m.

Parameters:
fx: The x-coordinate of the focus of the parabola.
fy: The y-coordinate of the focus of the parabola.
k: The slope of the inclined line.
m: The y-intercept of the inclined line.
dirY: The y-coordinate of the directrix of the parabola.

See graph: https://www.desmos.com/calculator/kheraernz6

Code: Select all

local function getParabolaToInclinedLineIntersections (fx, fy, k, m, dirY)
--	https://www.desmos.com/calculator/kheraernz6
	-- fx, fy - focus
	-- dirY - direcrix Y
	-- k, m - factors for inclined line: y = kx+m
	
	local p = (fy-dirY)/2
	
	local a = 1 / (4*p)
	local b = -2*a*fx
	local c = a*fx*fx+fy-p
	
	-- graph y = a*x^2+(b-k)*x+(c-m)
	
	local dx = (b-k)*(b-k)-4*a*(c-m)
	if dx < 0 then
		error ('discriminant is less than 0')
	end
	dx = dx^0.5
	-- left:
	local x1 = (-(b-k)-dx)/(2*a)
	local y1 = k*x1+m
	-- right: 
	local x2 = (-(b-k)+dx)/(2*a)
	local y2 = k*x2+m
	return x1, y1, x2, y2
end
2024-10-03T20_23_09-Desmos _ Grafik-Rechner.png
2024-10-03T20_23_09-Desmos _ Grafik-Rechner.png (76.12 KiB) Viewed 9738 times
:x Circle event is not ready :x
https://github.com/darkfrei/love2d-lua- ... oi-polygon
voronoi-polygon-1.png
voronoi-polygon-1.png (30.07 KiB) Viewed 9722 times
Attachments
voronoi-polygon-1.love
(5.04 KiB) Downloaded 88 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1209
Joined: Sat Feb 08, 2020 11:09 pm

Re: Parabola functions in Lua

Post by darkfrei »

Updated version, not ready.

Must be added the polygon vertex event and circle event.
Attachments
voronoi-lua-2.love
(12.49 KiB) Downloaded 15 times
2024-12-31T16_37_00-Untitled.png
2024-12-31T16_37_00-Untitled.png (24.19 KiB) Viewed 521 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1209
Joined: Sat Feb 08, 2020 11:09 pm

Re: Parabola functions in Lua

Post by darkfrei »

The beachline!

It looks that all cases are covered.

Code: Select all

print (love.getVersion( ))

--print = function () end

love.window.setMode( 1920, 1080 )

local width = love.graphics.getWidth()
local height = love.graphics.getHeight() 

local minX = 10
local maxX = width-10


local globalEventY = 950

local site1 = {x=1310, y=590}

local sites = {site1}

table.insert (sites, {x=400, y=400})
table.insert (sites, {x=1200, y=400})
table.insert (sites, {x=800, y=600})
--table.insert (sites, {x=1200, y=300})

local beachCurvesArray = {} -- array of arrays for lines to draw beachlines

local lines = {}

local renderingArcs = {}

local testEdges = {}

local function evaluateArc (arc, x, eventY)
	local y = (x - arc.x)^2 / (2 * (arc.y - eventY)) + (arc.y + eventY) / 2
	return y
end


local function getEventY(arc1, arc2, x)
	-- for removing out of border arcs
	-- not tested
	-- not used
	-- [coefficients for quadratic equation in eventY]
	local A1 = arc1.y
	local A2 = arc2.y
	local B1 = arc1.x
	local B2 = arc2.x

	local a = 1 / (2 * (A1 - x)) - 1 / (2 * (A2 - x))
	local b = (A1 + x) / (2 * (A1 - x)) - (A2 + x) / (2 * (A2 - x))
	local c = ((x - B1)^2 / (2 * (A1 - x))) - ((x - B2)^2 / (2 * (A2 - x)))

	-- [quadratic equation: a * eventY^2 + b * eventY + c = 0]
	local discriminant = b * b - 4 * a * c

	if discriminant < 0 then
		return nil -- no solution
	end

	-- [find the two possible roots for eventY]
	local sqrtDiscriminant = math.sqrt(discriminant)
	local eventY1 = (-b + sqrtDiscriminant) / (2 * a)
	local eventY2 = (-b - sqrtDiscriminant) / (2 * a)

	-- [return the largest valid eventY, since the sweep line moves downwards]
	return math.max(eventY1, eventY2)
end




local function getCircumcircle (x1, y1, x2, y2, x3, y3)
	local d = 2 * (x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2))
	if math.abs(d) < 0.000000000001 then return end
	local t1, t2, t3 = x1*x1+y1*y1, x2*x2+y2*y2, x3*x3+y3*y3
	local x = (t1 * (y2 - y3) + t2 * (y3 - y1) + t3 * (y1 - y2)) / d
	local y = (t1 * (x3 - x2) + t2 * (x1 - x3) + t3 * (x2 - x1)) / d
	local radius = math.sqrt((x1-x)^2 + (y1-y)^2)
	
	return x, y, radius
end

local function calculateCircle (p1, p2, p3)
	return getCircumcircle (p1.x, p1.y, p2.x, p2.y, p3.x, p3.y)
end

local function processCircleEvent (event, beachline, events)
	local currentIndex
	for index, arc in ipairs (beachline) do
		if arc == event.arc then
			currentIndex = index
			break
		end
	end
	if not currentIndex then return end

	local pervArc = beachline[currentIndex-1]
	local currentArc = beachline[currentIndex]
	local nextArc = beachline[currentIndex+1]

	print ('processCircleEvent', 'beachline before:')
	for i, arc in ipairs (beachline) do
		print (i, 'arc', arc.minX, arc.maxX)
	end

	local x = event.x -- x coordinate of circle
	if currentArc and currentArc.removingEvent 
	and event == event.arc.removingEvent then
		pervArc.maxX = x
		nextArc.minX = x
		table.remove (beachline, currentIndex)
		print ('processCircleEvent', 'arc removed', currentIndex)
	end

--	for index, arc in ipairs (beachline) do
--		arc.index = index
--	end

	print ('processCircleEvent', 'beachline after:')
	for i, arc in ipairs (beachline) do
		print (i, 'arc', arc.minX, arc.maxX)

	end

	print ('processCircleEvent', 'end')

end

local function addCircleEvent(currentArc, beachline, events)
	-- reindex beachline

	for index, arc in ipairs (beachline) do
		arc.index = index
	end



	local currentIndex
	for index, arc in ipairs (beachline) do
		if arc == currentArc then
			currentIndex = index
			break
		end
	end

	local leftArc = beachline[currentIndex - 1]
	local rightArc = beachline[currentIndex + 1]

	if not leftArc then

		return
	end
	if not rightArc then

		return
	end

	if leftArc.site == rightArc.site then
		error ('same sites!')
	end

	local circleX, circleY, radius = calculateCircle(
		leftArc.site, currentArc.site, rightArc.site
	)

	-- lower than site
	if circleY and (circleY+radius) > currentArc.site.y then
--		love.graphics.arc( drawmode, x, y, radius, angle1, angle2, segments )
		local renderArc = {
			drawmode = 'line',
			x = circleX,
			y = circleY,
			radius = radius,
			angle1 = math.atan2 (leftArc.y-circleY, leftArc.x-circleX),
			angle2 = math.atan2 (rightArc.y-circleY, rightArc.x-circleX),
		}
		table.insert (renderingArcs, renderArc)

		local circleEvent = {
			x = circleX,
			y = circleY + radius,
			circleY = circleY,
			arc = currentArc, -- arc to removing

--			event.process(event, beachline, events)
			process = processCircleEvent,
		}
		if currentArc.removingEvent then
			if currentArc.removingEvent.y > circleEvent.y then
				print ('removingEvent y:', currentArc.removingEvent.y, circleEvent.y)
				currentArc.removingEvent = circleEvent
			end
		else
			currentArc.removingEvent = circleEvent
		end

		table.insert (events, circleEvent)
		print ('circle event added:', #events)

	end

end


local function processSiteEvent(event, beachline, events)
	local site = event.site
	local x, y = site.x, site.y

	if #beachline == 0 then 
		-- first one
		local arc = {
			site = site, -- focus
			x=x, y=y,  -- focus
			minX = minX, maxX = maxX,
		}
		table.insert (beachline, arc)

	else -- not first


		local currentIndex = #beachline
		local sameX = false
		local sameY = false
		local isArcLast = false

		for index, arc in ipairs (beachline) do
			if x <= arc.maxX then
				currentIndex = index
				break
			end
		end

		local prevtArc = beachline[currentIndex-1]
		local currentArc = beachline[currentIndex]
		local nextArc = beachline[currentIndex+1]

		if currentIndex == #beachline then isArcLast = true end
		if currentArc.y == y then sameY = true end
		if currentArc.maxX == x then sameX = true end

		local arc = {
			site = site, -- focus
			x=x, y=y,  -- focus
			minX = x, maxX = x,
		}


		if isArcLast and sameY then
			print ('case 1')
			-- last arc: insert after all
			-- special case to insert vertical line after vertical line
			local mx = (currentArc.x + arc.x)/2
			arc.maxX = currentArc.maxX
			currentArc.maxX = mx
			arc.minX = mx
			table.insert (beachline, arc)

			addCircleEvent(currentArc, beachline, events)

		elseif sameX and sameY then
			print ('case 2')
			-- special case to insert vertical line after vertical line
			local mx = (currentArc.x + arc.x)/2
			arc.maxX = currentArc.maxX
			currentArc.maxX = mx
			arc.minX = mx
			table.insert (beachline, currentIndex+1, arc)
			-- wip:  sameY - insert vertical edge
		elseif sameY and not sameX then
			print ('case 3')
			-- special case to insert vertical line after vertical line
			local mx = (currentArc.x + arc.x)/2
			arc.maxX = currentArc.maxX
			currentArc.maxX = mx
			arc.minX = mx
			table.insert (beachline, currentIndex+1, arc)

			print ('special case sameY and not sameX, events before:', #events)
			addCircleEvent(currentArc, beachline, events)
			print ('special case sameY and not sameX, events after:', #events)
			-- wip: sameY - insert vertical edge
		elseif not sameY and sameX then
			print ('case 4')
			-- special case to insert vertical line after current arc
			table.insert (beachline, currentIndex+1, arc)
			-- wip:  sameY - insert vertical edge
			addCircleEvent(currentArc, beachline, events)
			addCircleEvent(nextArc, beachline, events)
			
		elseif not sameY and not sameX then
			print ('case 5')

			-----------------------------
			-----------------------------
			-- standard case: 
--			print ('standard case:', x, y)
			local my = evaluateArc (currentArc, x, y)
			local nextArc = {
				x = currentArc.x,
				y = currentArc.y,
				site = currentArc.site,
				minX = x, 
				maxX = currentArc.maxX,
				removingEvent = currentArc.removingEvent,
			}
			currentArc.maxX = x
			table.insert (beachline, currentIndex+1, arc)
			table.insert (beachline, currentIndex+2, nextArc)

			print ('common case, events before:', #events)
			addCircleEvent(currentArc, beachline, events)
			print ('common case, events after 1:', #events)
			addCircleEvent(nextArc, beachline, events)
			print ('common case, events after 2:', #events)

			for i, arc in ipairs (beachline) do
				print (i, 'arc', arc.minX, arc.maxX)
			end
		end
	end


end


local function getParabolaCrossPoint (p1x, p1y, p2x, p2y, dirY) -- focus 1, focus 2, directrix
-- Function to find the intersection point of two parabolas
	local f1 = math.abs(dirY-p1y)/2
	local f2 = math.abs(dirY-p2y)/2

	local a1 = -1/(4*f1)
	local a2 = -1/(4*f2)
	local b1 = -2*p1x*a1
	local b2 = -2*p2x*a2
	local c1 = p1x*p1x*a1 + p1y + f1
	local c2 = p2x*p2x*a2 + p2y + f2
	local a = a1-a2
	local b = b1-b2
	local c = c1-c2

	local d = b*b-4*a*c
	local x, y
	if d >=0 then
		x = (-b-math.sqrt (d))/(2*a)
		y = a1*x*x + b1*x + c1
	end
	return x, y
end

local function findIntersection(arc1, arc2, eventY)
--	local a1, a2 = arc1.y - eventY, arc2.y - eventY
--	local b1 = arc1.x - arc2.x
--	return (b1 * a2) / (a1 - a2)
	local x, y = getParabolaCrossPoint (arc1.x, arc1.y, arc2.x, arc2.y, eventY)
	return x
end

local function clamp(low, n, high) 
	return math.min(math.max(n, low), high) 
end


local function updateLimits(beachline, eventY)
	if #beachline > 1 then
		for i = 1, #beachline-1 do
			local arc1 = beachline[i]
			local arc2 = beachline[i+1]
			if arc1.y == arc2.y then
				-- do nothing or
				local mx = (arc1.x + arc2.x)/2
				mx = clamp (minX, mx, maxX)
				arc1.maxX = mx
				arc2.minX = mx
			else
				local mx = findIntersection (arc1, arc2, eventY)
				if mx then
					mx = clamp (minX, mx, maxX)
					arc1.maxX = mx
					arc2.minX = mx
				end
			end
		end
	end

end

local function generateBeachlineCurve (beachline, eventY)
	local lines = {}
	local steps = 64
	for i, arc in pairs (beachline) do
		local line = {}
		local dx = arc.maxX - arc.minX
		if dx == 0 and i > 1 then
			local prevArc = beachline[i-1]
			local x = arc.x
			local y = (x - prevArc.x)^2 / (2 * (prevArc.y - eventY)) + (prevArc.y + eventY) / 2
			table.insert (line, arc.x)
			table.insert (line, arc.y)
			table.insert (line, x)
			table.insert (line, y)

--			print ('y, arc.y', y, arc.y)
		else
			if dx/steps > 5 then
				steps = math.ceil (dx/5)
				--			print (steps, 1/steps)
			end
			for i = 0, steps do
				local x = arc.minX + i/steps * dx
				local y = (x - arc.x)^2 / (2 * (arc.y - eventY)) + (arc.y + eventY) / 2
				table.insert (line, x)
				table.insert (line, y)
			end
		end
		table.insert (lines, line)
	end

	return lines
end

local function clearConsole()
	io.write("\027[2J\027[H\n")
end

local function updateBeachline ()
--	clearConsole()

	beachCurvesArray = {}
	renderingArcs = {}
	testEdges = {}

	local events = {
		{x=0,
			y=globalEventY,
			process = function () end
		}
	}
	for i, site in ipairs (sites) do
		local event = {
			x=site.x, 
			y=site.y, 
			site = site,
			process = processSiteEvent -- must be function
		}
		table.insert (events, event)

	end



	local beachline = {}

	local lastEventY

	local nEvent = 0
	while #events > 0 do
		nEvent = nEvent + 1
		print ('----------', 'nEvent: '..nEvent)
		table.sort(events, function(a, b)
				return a.y == b.y and a.x < b.x or a.y < b.y
			end)

		local event = table.remove (events, 1)
		local eventY = event.y


		updateLimits(beachline, eventY)
		event.process(event, beachline, events)
		updateLimits(beachline, eventY)

		local beachCurves = generateBeachlineCurve (beachline, eventY)
		local line = {event.x-100, eventY, event.x+100, eventY}

		table.insert (beachCurves, line)

		if lastEventY == eventY then
			table.remove (beachCurvesArray)
		end
		lastEventY = eventY
		table.insert (beachCurvesArray, beachCurves)
	end

	updateLimits (beachline, globalEventY) -- update global value
	lines = generateBeachlineCurve (beachline, globalEventY)


	for i, site1 in ipairs (sites) do
		for j, site2 in ipairs (sites) do
			if not (i == j) then
				local mx = (site1.x+site2.x)/2
				local my = (site1.y+site2.y)/2
				local dx = site2.x-site1.x
				local dy = site2.y-site1.y
				local edge = {mx+dy,my-dx, mx, my}
				table.insert (testEdges, edge)
			end
		end
	end


end



function love.mousemoved (x, y)
	site1.x = x
	site1.y = y

	updateBeachline ()
end

function love.load ()
	updateBeachline ()
end

function love.update ()
	local key = love.keyboard.isDown ('down') and 'down' 
	or love.keyboard.isDown ('up') and 'up'
	if key == 'down' then
		eventY = eventY + 1
		updateBeachline ()
	elseif key == 'up' then
		eventY = eventY - 1
		updateBeachline ()
	end
end

local function rainbowRGB(t, a)
	local r = math.min(math.max(3 * math.abs(((360*t     ) / 180) % 2 - 1) - 1, 0), 1)
	local g = math.min(math.max(3 * math.abs(((360*t - 120) / 180) % 2 - 1) - 1, 0), 1)
	local b = math.min(math.max(3 * math.abs(((360*t + 120) / 180) % 2 - 1) - 1, 0), 1)

	return r, g, b, a
end

function love.draw ()
	love.graphics.setColor (1,1,1)
	love.graphics.line (0,globalEventY, width,globalEventY)
	love.graphics.print (globalEventY, 0, globalEventY)

	love.graphics.setColor (1,1,1)
	-- sites
	for i, site in ipairs (sites) do
		love.graphics.circle ('fill', site.x, site.y, 5)
		love.graphics.print (i..' '..site.x ..' '..site.y, site.x-15, site.y+25)
	end




	love.graphics.setColor (1,1,1)
	for i, beachCurves in ipairs (beachCurvesArray) do
		local a = 0.3 + 0.7 * i/#beachCurvesArray
		for j, line in ipairs (beachCurves) do
--			print (#beachCurves, #line)
			local t = 0.75*(j-1)/#beachCurves
			love.graphics.setColor (rainbowRGB(t, a))
			love.graphics.line (line)

			love.graphics.print (i..' '..j, line[1], line[2])
		end
	end

--	for i, line in ipairs (lines) do
--		local t = 0.75*(i-1)/#lines
--		love.graphics.setColor (rainbowRGB(t, a))
--		love.graphics.line (line)
--	end

	local c = 0.5
	love.graphics.setColor (c, c, c)
	for i, r in ipairs (renderingArcs) do
		love.graphics.arc( r.drawmode, r.x, r.y, r.radius, r.angle1, r.angle2)
		love.graphics.circle( r.drawmode, r.x, r.y, r.radius)
		love.graphics.line (r.x-20, r.y+r.radius, r.x+20, r.y+r.radius)
	end

--	love.graphics.setColor (1,1,1)
	for i, edge in ipairs (testEdges) do
		love.graphics.line (edge)
	end
end

function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "escape" then
		love.event.quit()
	end
end
beachline-01.png
beachline-01.png (166.12 KiB) Viewed 395 times
Animation (96).gif
Animation (96).gif (184.73 KiB) Viewed 275 times
Attachments
beachline-01.love
(3.82 KiB) Downloaded 12 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot] and 1 guest