Code Doodles!

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
lazershark3k
Prole
Posts: 27
Joined: Tue Apr 10, 2018 3:20 pm

Re: Code Doodles!

Post by lazershark3k »

Thanks a bunch! It works perfectly now!
*pew pew*
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

The A is a point;
Line B12 is a sector
dx dy is a direction (and length) of ray from point A

The result: the point A will be projected to the line B12.

Code: Select all

local function findIntersectionPoint(ax, ay, b1x, b1y, b2x, b2y, dx, dy)
  local segmentX = b2x - b1x
  local segmentY = b2y - b1y
  local determinant = dy * segmentX - dx * segmentY
  if determinant == 0 then
    return nil
  end
  local t = ((b1y - ay) * segmentX - (b1x - ax) * segmentY) / determinant
	if t < 0 then -- wrong side of the ray
		return nil
	elseif t > 1 then -- too far; the ray is too short
		-- do nothing; keep projecting
	else -- t is between 0 and 1
		-- do nothing
  end
	
  local u = ((ax - b1x) * dy - (ay - b1y) * dx) / determinant
  if u < 0 or u > 1 then
		-- out of segment
    return nil
  end

	dx = t*dx
	dy = t*dy
  local length = math.sqrt(dx*dx+dy*dy)

  return ax+dx, ay+dy, dx, dy, length
end
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3672
Joined: Sun Oct 18, 2015 2:58 pm

Re: Code Doodles!

Post by pgimeno »

darkfrei wrote: Wed May 31, 2023 7:32 am...
Hi darkfrei, Please read the first post, then look at the doodles that others have posted. Thanks.
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Sorry pgimeno! :cool:

The code handles the movement of a point along a line segment while taking collision into account.

The point is represented by its current position (x, y), target position (tx, ty), and speed. The line segment is defined by its endpoints (x1, y1) and (x2, y2).

This code demonstrates how to handle point-to-segment collision. It can be useful in various applications involving collision detection and movement along defined paths.

Code: Select all

point = {x=200, y=200, tx=100, ty=100, speed=200}
segment = {100, 400, 600, 100}

local function handlePointCollision(px, py, x1, y1, x2, y2, dx, dy)
  local segmentDX = x2 - x1
  local segmentDY = y2 - y1
  local segmentLength = math.sqrt(segmentDX * segmentDX + segmentDY * segmentDY)
  segmentDX = segmentDX / segmentLength
  segmentDY = segmentDY / segmentLength
  local dotProduct = (px - x1) * segmentDY - (py - y1) * segmentDX
  local dotProduct2 = (px + dx - x1) * segmentDY - (py + dy - y1) * segmentDX

	if not (dotProduct > -1/256 and dotProduct2 < 0) then
		-- not crossing segment from positive to negative side
		return dx, dy
	end
  
	local segmentDot = (px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)
	local t = segmentDot / (segmentLength * segmentLength)

	if t >= 0 and t <= 1 then
		-- collision with segment
		dx = (x1 + segmentLength*segmentDX * t)-px
		dy = (y1 + segmentLength*segmentDY * t)-py
		love.window.setTitle (dx..' '..dy)
		return dx, dy
	else
		-- no collision with segment
		return dx, dy
	end
end

function love.update(dt)
	local px, py = point.x, point.y
	local speed = point.speed
	local dx0, dy0 = point.tx-point.x, point.ty-point.y
	local angle = math.atan2 (dy0, dx0)
	
	local dx = dt*speed*math.cos (angle)
	local dy = dt*speed*math.sin (angle)
	
	if math.abs (dx0) < math.abs(dx) 
	or math.abs (dy0) < math.abs(dy) then
		dx = dx0
		dy = dy0
	end
	
	local x1, y1 = segment[1], segment[2]
	local x2, y2 = segment[3], segment[4]
	dx, dy = handlePointCollision(px, py, x1, y1, x2, y2, dx, dy)
	point.x, point.y = px+dx, py+dy
end

function love.draw()
	love.graphics.line (segment)
	love.graphics.circle ('fill', point.x, point.y, 5)
	love.graphics.circle ('line', point.tx, point.ty, 7)
	love.graphics.line (point.x, point.y, point.tx, point.ty)
end

function love.mousemoved( x, y)
	point.tx = x
	point.ty = y
end
Animation (68).gif
Animation (68).gif (289.67 KiB) Viewed 19674 times
Update:
sliding functions:

Code: Select all

point = {x=200, y=200, tx=100, ty=100, speed=200}
segment = {200, 200, 400, 100}

local function sticking (px, py, x1, y1, x2, y2, t)
	local segmentDX = x2 - x1
	local segmentDY = y2 - y1
	local dx = (x1 + segmentDX * t) - px
	local dy = (y1 + segmentDY * t) - py
	return dx, dy
end

local function sliding (segmentDX, segmentDY, dx, dy)
	local dotProduct = dx * segmentDX + dy * segmentDY
	dx  = segmentDX * dotProduct
	dy  = segmentDY * dotProduct
	return dx, dy
end

local function handlePointCollision(px, py, x1, y1, x2, y2, dx, dy)
  local segmentDX = x2 - x1
  local segmentDY = y2 - y1
  local segmentLength = math.sqrt(segmentDX * segmentDX + segmentDY * segmentDY)
  segmentDX = segmentDX / segmentLength
  segmentDY = segmentDY / segmentLength
  local dotProduct = (px - x1) * segmentDY - (py - y1) * segmentDX
  local dotProduct2 = (px + dx - x1) * segmentDY - (py + dy - y1) * segmentDX

	if not (dotProduct > -1/256 and dotProduct2 < 0) then
		-- not crossing segment from positive to negative side
		return dx, dy
	end
  
	local segmentDot = (px - x1) * (x2 - x1) + (py - y1) * (y2 - y1)
	local t = segmentDot / (segmentLength * segmentLength)

	
	if t >= 0 and t <= 1 then
		-- collision with segment
		local isSliding = true
		if isSliding then
			return sliding (segmentDX, segmentDY, dx, dy)
		else
			return sticking (px, py, x1, y1, x2, y2, t)
		end
	else
		-- no collision with segment
		return dx, dy
	end
end

function love.update(dt)
	local px, py = point.x, point.y
	local speed = point.speed
	local dx0, dy0 = point.tx-point.x, point.ty-point.y
	local angle = math.atan2 (dy0, dx0)
	
	local dx = dt*speed*math.cos (angle)
	local dy = dt*speed*math.sin (angle)
	
	if math.abs (dx0) < math.abs(dx) 
	or math.abs (dy0) < math.abs(dy) then
		dx = dx0
		dy = dy0
	end
	
	local x1, y1 = segment[1], segment[2]
	local x2, y2 = segment[3], segment[4]
	dx, dy = handlePointCollision(px, py, x1, y1, x2, y2, dx, dy)
	point.x, point.y = px+dx, py+dy
end

function love.draw()
	love.graphics.line (segment)
	love.graphics.circle ('fill', point.x, point.y, 5)
	love.graphics.circle ('line', point.tx, point.ty, 7)
	love.graphics.line (point.x, point.y, point.tx, point.ty)
end

function love.mousemoved( x, y)
	point.tx = x
	point.ty = y
end
Animation (69).gif
Animation (69).gif (434.86 KiB) Viewed 19646 times
Attachments
point-line-collision-02.love
(987 Bytes) Downloaded 381 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

The code can be useful for generating and visualizing slot car track layouts with different parameters:

Code: Select all

-- License CC0 (Creative Commons license) (c) darkfrei, 2023

love.window.setMode(1280, 800) -- Steam Deck resolution
love.window.setTitle("Slot Car Track")

local function setLastPoint (x, y, angle)
	LastPoint = {x=x, y=y, angle = math.rad (angle)}
end

local function addStraightRoad (length, logRoads)
	if logRoads then
		print ('Straight', 'length: ' .. length)
	end
	local x1, y1 = LastPoint.x, LastPoint.y
	local angle = LastPoint.angle
	local x2 = x1 + length*math.cos (angle)
	local y2 = y1 + length*math.sin (angle)
	if logRoads then
		x2 = math.floor(x2+0.5)
		y2 = math.floor(y2+0.5)
	end
	
	local road = {}
	-- line to render
	road.render = {}
	road.render.line = {x1, y1, x2, y2}
	road.render.circles = {{x1, y1}, {x2, y2}}
	
	LastPoint.x = x2
	LastPoint.y = y2
	LastPoint.angle = math.atan2 (y2-y1, x2-x1)
	table.insert (Track, road)
end

local function addCurvedRoad(radius, angle, logRoads)
	if logRoads then
		print ('Curved', 'radius: ' .. radius, 'angle: ' .. angle)
	end
	-- starting point
	local x1, y1 = LastPoint.x, LastPoint.y
	local angle1 = LastPoint.angle
	local angleSign = angle > 0 and 1 or -1
	angle = math.rad(angle)

	local angle2 = angle1 + angle

	-- Middle point
	local xc = x1 - angleSign * radius * math.sin(angle1)
	local yc = y1 + angleSign * radius * math.cos(angle1)

	-- end point
	local x2 = xc + angleSign * radius * math.sin(angle2)
	local y2 = yc - angleSign * radius * math.cos(angle2)
	if logRoads then
		x2 = math.floor(x2+0.5)
		y2 = math.floor(y2+0.5)
	end
	
-- control factor:
	local k = math.abs (4/3*math.tan(angle / 4))
--		print (v1)

	local cp1x = x1 + k * radius * math.cos(angle1)
	local cp1y = y1 + k * radius * math.sin(angle1)

	local cp2x = x2 - k * radius * math.cos(angle2)
	local cp2y = y2 - k * radius * math.sin(angle2)

	local road = {}
	road.render = {}
--	road.render.circles = {{xc, yc}, {x1, y1}, {x2, y2}}
	road.render.circles = {{x1, y1}}
--	road.render.line = {xc, yc, x1, y1, cp1x, cp1y, cp2x, cp2y, x2, y2, xc, yc}

	local curve = love.math.newBezierCurve( x1, y1,  cp1x, cp1y, cp2x, cp2y, x2, y2)

	road.render.line = curve:render()

	LastPoint.x = x2
	LastPoint.y = y2
	LastPoint.angle = angle2

	table.insert(Track, road)
end

local function createTrack (r0, logRoads)
	
	Track = {}

	setLastPoint (500, 700, 0)

	local r1, a1 = r0*2, 30
	local r2, a2 = r0*(2^0.5), 30
--	local r2, a2 = r0*1.4142, 30
--	local r2, a2 = r0*1.53, 30
	local r3, a3 =  r0, 60
	
	
	addStraightRoad (141, logRoads)
	addCurvedRoad (r1, -a1, logRoads)
	addCurvedRoad (r1, -a1, logRoads)
	addCurvedRoad (r1, -a1, logRoads)
	
	addCurvedRoad (r2, -a2, logRoads)
	addCurvedRoad (r2, -a2, logRoads)
	addCurvedRoad (r2, -a2, logRoads)
	addCurvedRoad (r2, -a2, logRoads)
	
	addCurvedRoad (r1,  a1, logRoads)
	
	addCurvedRoad (r3,  a3, logRoads)
	
	addCurvedRoad (r3,  a3, logRoads)
	
	addCurvedRoad (r2,  a2, logRoads)
	addCurvedRoad (r2,  a2, logRoads)
	addCurvedRoad (r1,  a1, logRoads)
	addStraightRoad (200, logRoads)
	
	addCurvedRoad (r2,  a2, logRoads)
	
	addCurvedRoad (r3,  a3, logRoads)
	addCurvedRoad (r3,  a3, logRoads)
	
	addStraightRoad (400, logRoads)
	
	addCurvedRoad (r3, -a3, logRoads)
	addCurvedRoad (r3, -a3, logRoads)
	addCurvedRoad (r3, -a3, logRoads)
	
	addStraightRoad (100, logRoads)
	
--	print (Track[1].render.line[1], Track[1].render.line[2])
--	print (LastPoint.x, LastPoint.y)
	local dy = Track[1].render.line[2] - LastPoint.y
	local dx = Track[1].render.line[1] - LastPoint.x
--	print ('dy:', dy)
	return dy, dx
end

local function findXByBisection(func, y, xMin, xMax, tolerance)
	local xMid = (xMin + xMax) / 2
	local yMid = func(xMid)
	local lastXMid = nil
	while math.abs(yMid - y) > tolerance do
		if (yMid - y) * (func(xMin) - y) > 0 then
			xMin = xMid
		else
			xMax = xMid
		end

		xMid = (xMin + xMax) / 2
		yMid = func(xMid)
		print (xMid, yMid)
		
		if lastXMid == xMid then
			return xMid
		end
		lastXMid = xMid
	end
	print ('error: ', math.abs(yMid - y), yMid, y)
--	return math.floor(xMid+0.5)
	return xMid
end

-- Пример использования


local targetY = 0
local xMin, xMax = 0, 600
local tolerance = 0.00001

--local radius = findXByBisection(createTrack, targetY, xMin, xMax, tolerance)
local radius = 113.85440826416

print(radius)  -- Вывод найденного значения x



function love.load()
	local xMin = 10
	local xMax = 300
	
	local dy, dx = createTrack (radius, true)
	print ('dx: ' .. dx, 'dy: ' .. dy)
end

 
function love.update(dt)
	
end

function love.draw()
	love.graphics.setColor (1,1,1)
	for _, road in ipairs (Track) do
		local r = road.render
		if r.line then
			love.graphics.line (r.line)
		end
		if r.circles then
			for _, point in ipairs (r.circles) do
				love.graphics.circle ('line', point[1], point[2], 4)
			end
		end
	end
	
	love.graphics.setColor (1,1,0)
	
	love.graphics.line (LastPoint.x, LastPoint.y, 
		LastPoint.x + 50*math.cos (LastPoint.angle), 
		LastPoint.y + 50*math.sin (LastPoint.angle))
	love.graphics.circle ('fill', LastPoint.x, LastPoint.y, 3)
	love.graphics.circle ('fill', LastPoint.x + 50*math.cos (LastPoint.angle), LastPoint.y + 50*math.sin (LastPoint.angle), 3)
end
2023-06-03T18_47_28-Slot Car Track.png
2023-06-03T18_47_28-Slot Car Track.png (29.32 KiB) Viewed 19597 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Tiled polygons, rethinked and optimized to the doodle:

Code: Select all

-- License CC0 (Creative Commons license) (c) darkfrei, 2023

-- tiled polygons v. 2023-07-12
love.window.setTitle ('Tiled Polygons 2023-07-12')

Tiles = {}

Size = 4

local v1, v2, v3, v4 = 1, 1+1*Size, 1+2*Size, 1+3*Size

for y = 0, 2*Size-1 do
	for x = 0, 2*Size-1 do
		local absDif = math.abs (y-x)
		if absDif < Size then
			if x == 0 and y == 0 then
				-- square
				local tile = {v1, v2, v3, v4}
				tile.x, tile.y = x, y
				table.insert (Tiles, tile)
			elseif y == 0 then
				-- rectangle
				local tile = {v1, v2-x, v3+x, v4}
				print (x, y, table.concat (tile, ','))
				tile.x, tile.y = x, y
				table.insert (Tiles, tile)
			elseif x == 0 then
				-- rectangle
				local tile = {v1, v2, v3-y, v4+y}
				print (x, y, table.concat (tile, ','))
				tile.x, tile.y = x, y
				table.insert (Tiles, tile)
			else
				local tile = {v1}
				local vx = v3-x
				local vy = v3+y
				if vx > v2 then
					table.insert (tile, v2)
				end				
				table.insert (tile, vx)
				table.insert (tile, vy)
				if vy < v4 then
					table.insert (tile, v4)
				end
				print (x, y, table.concat (tile, ','))
				tile.x, tile.y = x, y
				table.insert (Tiles, tile)
			end
		end
	end
end

Vertices = {}
for i = 1, Size do
	local t1 = (i - 1)/Size
	Vertices[i] = {x=t1, y=0}
	Vertices[i + Size] = {x=1, y=t1}
	Vertices[i + Size * 2] = {x=1-t1, y=1}
	Vertices[i + Size * 3] = {x=0, y=1-t1}
end

for i, v in ipairs (Vertices) do
	print (i, v.x, v.y)
end

Polygons = {}

for i, tile in ipairs (Tiles) do
	local x = 1.25*tile.x
	local y = 1.25*tile.y
	local vertices = {}
	print ('{'..table.concat (tile, ',')..'}, -- ' .. i)
	for j, vIndex in ipairs (tile) do
		local x1 = x + Vertices[vIndex].x
		local y1 = y + Vertices[vIndex].y
		table.insert (vertices, x1)
		table.insert (vertices, y1)
	end
	table.insert (Polygons, vertices)
end

	
function love.draw ()
	love.graphics.translate (10, 10)
	local scale = 58
	love.graphics.scale (scale)
	love.graphics.setLineWidth (2/scale)
	for i, vertices in ipairs (Polygons) do
		love.graphics.polygon ('line', vertices)
	end
end
Screenshot 2023-07-12 201740.png
Screenshot 2023-07-12 201740.png (25.91 KiB) Viewed 18645 times
Attachments
Screenshot 2023-07-12 215228.png
Screenshot 2023-07-12 215228.png (10.69 KiB) Viewed 18630 times
main.lua
(2.1 KiB) Downloaded 347 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Poisson Discs on Toroidal World:
Special for Craquelure viewtopic.php?p=255763#p255763

Code: Select all

-- cc0, 2023, darkfrei

local function poissonDiscs(gridWidth, gridHeight)
	-- poisson discs in toroidal grid
	local cellSize = 1
	local radius = math.sqrt(2)
	local distanceMin = radius
	local distanceMax = 1.5 * radius
	local samples = 32

	local lines = {}

	local grid = {} -- in format cell = grid[cy][cx] and cell = {cx=cx, cy=cy}
	for cy = 1, gridHeight do
		grid[cy] = {}
		for cx = 1, gridWidth do
			grid[cy][cx] = {} -- empty cell
		end
	end

	local activeCells = {} -- active cells
	local resultPoints = {} -- result points as {x1, y1, x2, y2 ...}

	local function getDistance(x1, y1, x2, y2)
		-- Calculate the toroidal distance between two points
		local dx = math.abs(x2 - x1)
		local dy = math.abs(y2 - y1)
		local distanceX = math.min(dx, gridWidth - dx)
		local distanceY = math.min(dy, gridHeight - dy)
		local distance = math.sqrt(distanceX ^ 2 + distanceY ^ 2)
--		print (math.floor (distance+0.5))
		return math.sqrt(distanceX ^ 2 + distanceY ^ 2)
	end

	local function insertPoint(x, y)
		-- Insert a new point into the grid and active cells
		local cx = (math.floor (x))%gridWidth+1
		local cy = (math.floor (y))%gridHeight+1
		if not grid[cy][cx].x then
			local cell = {x = x, y = y}
			grid[cy][cx] = cell
			table.insert(activeCells, cell)
			table.insert(resultPoints, x)
			table.insert(resultPoints, y)
		end
	end


	local function isPointValid(x, y)
		-- Check if a cell is valid for point placement
		local cx = math.floor(x) + 1
		local cy = math.floor(y) + 1
		local cell = grid[cy][cx]
		if cell.cx ~= nil and cell.cy ~= nil then
			return false
		end
		for dy = -2, 2 do
			for dx = -2, 2 do
				local neighborCX = (cx + dx - 1) % gridWidth + 1
				local neighborCY = (cy + dy - 1) % gridHeight + 1
				if not ((cx == neighborCX) and (cy == neighborCY)) then
					local neighbor = grid[neighborCY][neighborCX]
					if neighbor.x then
						local distance = getDistance(x, y, neighbor.x, neighbor.y)
--						print (distance, distanceMin)
						if distance < distanceMin then
							return false
						end
					end
				end
			end
		end
		return true
	end
	
	-- first point, if anywhere, why not 0,0?
	insertPoint(0, 0)

	while #activeCells > 0 do
		local randomIndex = math.random(#activeCells)
		local cell = table.remove(activeCells, randomIndex)
		local x, y = cell.x, cell.y
		local cx, cy = math.floor (x) + 1, math.floor (y) + 1

		for _ = 1, samples do
			local angle = 2 * math.pi * math.random()
			local distance = distanceMin + math.random() * (distanceMax - distanceMin)
			local offsetX = math.cos(angle) * distance
			local offsetY = math.sin(angle) * distance
			local newX = (x + offsetX) % gridWidth
			local newY = (y + offsetY) % gridHeight
			if isPointValid(newX, newY) then
				insertPoint(newX, newY)
				table.insert (lines, {x, y, (x + offsetX), (y + offsetY)})
			end
		end
	end

	print ('cells:', gridWidth, gridHeight, gridWidth * gridHeight)
	print ('resultPoints', #resultPoints/2)
	return resultPoints, lines
end

function love.load ()
	GridWidth, GridHeight = 30, 20
	Points, Lines = poissonDiscs(GridWidth, GridHeight)

	Scale = math.floor (math.min (love.graphics.getWidth()/GridWidth, love.graphics.getHeight()/GridHeight))/2
end


function love.draw()

	love.graphics.scale (Scale)
	love.graphics.setPointSize (3)
	love.graphics.setLineWidth (0.25/Scale)

	love.graphics.translate (GridWidth/2, GridHeight/2)

	for dy = -GridHeight, GridHeight, GridHeight do
		for dx = -GridWidth, GridWidth, GridWidth do
			love.graphics.push()
			love.graphics.translate (dx, dy)
			for y = 1, GridHeight do
				for x = 1, GridWidth do
					if (x+y)%2 == 0 then
						love.graphics.setColor (0.2,0.2,0.2)
					else
						love.graphics.setColor (0.3,0.3,0.3)
					end
					love.graphics.rectangle ('fill', x-1, y-1, 1,1)
				end
			end
			love.graphics.pop()
		end
	end

	for dy = -GridHeight, GridHeight, GridHeight do
		for dx = -GridWidth, GridWidth, GridWidth do
			love.graphics.push()
			love.graphics.translate (dx, dy)

			love.graphics.setColor (0.5,0.5,0.5)
			for y = -1, 1 do
				for x = -1, 1 do
					for i = 1, #Points-1, 2 do
						love.graphics.circle ('line', Points[i], Points[i+1], math.sqrt(2))
					end
				end
			end

			love.graphics.setColor (1,1,1)
			love.graphics.points (Points)
			love.graphics.pop()
		end
	end
end

function love.keypressed(key, scancode, isrepeat)
	if key == "escape" then
		love.event.quit()
	end
end


Example result:

Code: Select all

{0,0,29.421497428895,18.262284985482,1.9791994775338,0.71104989006247,28.936347589706,1.3874202099944,0.77918559894233,1.7119154545849,0.74872496156755,18.75908887808,2.4294796576936,18.621404096665,0.74629667130324,17.272948180996,27.224705013952,0.60592345728928,28.113281538712,2.7081013486532,27.286359005096,4.183978333816,29.758882374693,3.3617643405968,26.731307726236,2.3346689791489,2.1391061763197,2.3662886471186,26.11672261621,18.802623146342,25.427344998163,0.35620449316817,28.21890597267,19.192023390212,3.7517173300831,1.7900008652362,1.981748592693,3.7754927204595,3.6491112562124,19.761768053947,4.674214819273,2.9490230330072,5.6408681601946,0.93025608865254,25.153278935918,3.5477422539136,24.74775908144,1.7408658927981,3.6468147671778,17.686777140792,2.7256975440463,16.586500273227,27.353484813482,17.711706794635,3.5807610961327,15.227472542947,1.447531381856,15.587596556207,4.8298954808599,16.620574836613,0.31465693871064,14.276126652375,29.511215767343,15.609803506531,2.1962809166391,13.945271943441,3.2672962025191,4.6199685102339,1.4474853623782,5.5148168661481,29.694158401428,5.2731956805743,5.37416143966,18.912707009383,26.946086120639,5.9227939397719,4.6932753886167,14.330123415792,6.9782426673136,18.413258136099,6.3445081320094,17.066505830656,8.2903487194649,19.086285734748,7.0252711656188,0.3873973193782,8.4495737245075,17.180138859889,24.698151332349,18.85177868671,26.012341279164,16.96074196664,28.960775498939,13.336494835331,0.90739685240295,12.873455631666,22.917225458181,19.363868669458,24.275265008088,17.465685829653,23.929765725272,0.54500552563436,6.7168409399952,2.1326746080956,9.098337121903,0.33492806859019,28.205328998772,14.904968278816,28.647034910054,16.852242409054,23.432729781527,4.2211867275551,23.574917883008,2.7937404923595,24.581165813541,5.5119634572548,0.68237096898904,7.1810494623508,2.2801117761457,7.2564079804841,3.1735159901111,6.11318099228,4.8951935725097,5.7195046128446,4.2766502409951,7.1216422599576,28.389755385136,6.248663557283,27.812609649106,7.7795543089628,25.39745634073,6.7148584441762,25.946492069892,4.8971573573492,26.243061820043,9.2012615989797,28.92375476746,8.9997849663966,6.6697296925175,13.811078483549,5.5586046248046,12.823025353141,3.9743078751966,12.610703282608,6.098882769853,15.109111748691,22.002857044804,2.6583741071336,22.509223849567,5.8222648100415,21.879813738722,4.1833119344917,24.406180342051,8.4994367798685,23.634969557267,7.3137831643219,27.373594538849,16.05002538136,23.448567626534,16.111926027443,22.366804890887,17.568268526608,24.958511918221,15.851389585741,9.8301356791575,18.572545833927,8.0128961369235,15.667830174963,10.113043830961,16.380111796853,9.11275904049,14.720274645358,7.5952044091645,12.660629455291,6.5275294429725,11.165210286208,4.5163089839191,11.071709542587,20.908047017226,5.938537862401,19.903335463998,4.4204289956641,20.608301362255,3.0710626746245,21.67628922207,0.090076372672286,22.760776162152,1.3969603245843,20.182403809908,7.284104666209,19.025181940175,6.0634745760051,21.782208297784,7.0547801776248,18.224622922412,7.8673727956669,17.378466772205,5.8153715963749,18.350488480217,4.1961035468554,21.757523856438,8.5664149354302,27.445342424373,10.133788761031,26.249118878489,10.922312935011,24.495579459621,9.9124655327756,11.594327665859,17.521496729008,11.71943630784,15.251330921105,16.448616033666,8.0877722215436,18.357595870684,9.81539689341,19.692768502809,8.9494817952152,29.527524694761,10.363938169432,0.28983215537493,8.5450233694436,25.945401964827,14.654425062408,17.101329771224,11.063643512431,19.927578543818,10.421911618694,18.851751125117,11.648940994635,16.611875213448,9.575802384804,9.5716853301274,1.6922636139561,8.0456709977104,1.6256254828659,10.933816062008,0.21014898415188,6.288352782026,3.6513728765422,1.6422720181125,9.9966177685061,8.1382361210998,10.737822980767,5.5290028087227,9.5324793548481,21.952304906453,10.723848774477,20.438720270184,12.123753127681,7.8337603688152,3.1691685127183,26.971947966862,13.660304229387,25.532421620072,12.959410658719,23.090454090237,9.3014071791645,17.562995943229,12.714553353205,19.046232707164,13.622709477516,7.1093722630043,5.5013454945225,9.5204935705948,13.318247355303,7.4576655393904,9.491729111497,3.6229295308856,9.0564833977333,5.7374655643323,7.8175367520628,3.1381991278438,10.393587001011,28.415378082348,11.64111327503,2.4157351681502,11.969362611613,17.740948964424,14.31840251801,19.804486852267,14.977275712126,20.834973898727,13.923332868907,18.488724639474,15.891118140154,20.429027062187,16.315774547216,16.154560697578,15.53719982925,15.763623513407,13.958621458879,15.142017683596,10.93762742525,15.843302664241,12.459627475133,22.477959557257,12.332835964072,20.228447124499,17.868882186928,23.354199318503,10.982858873003,24.357392061813,14.346981952072,18.533816474532,17.333983176357,17.231068059174,16.653718869598,22.545180836352,13.80445153977,24.219511279903,12.409347950979,21.997175307694,15.425964150301,8.3087262441023,6.3480565201002,8.8575100984086,5.0097300937438,10.899056802057,13.898530555561,12.274479479612,19.262034919355,12.704951390281,16.60512218453,29.836798430671,11.787720640891,9.2089371408976,9.4885287092576,7.2104595679744,7.8762388661208,19.091432722399,19.075125715517,17.578865924359,18.734822481333,16.352095643637,4.4275630572268,16.218407341999,6.6252182312717,16.197114699429,18.226381716687,16.398094540103,0.40385638370952,18.424780602057,0.40052593299355,14.801651162531,7.2885585469282,14.851496994194,5.2812883188366,9.6224524959129,11.413270183692,10.269836063727,3.1054289539585,11.229618315583,1.904315570997,18.790728835961,2.2051187358729,20.45793004877,1.5154702996483,9.9590984656872,6.411048480504,9.3780411308426,7.7251876337595,17.355078777522,2.9477725246015,16.058958148107,2.1775126916243,13.495441006692,0.63444617856707,13.710411544669,19.073514273732,11.987598345817,12.522740119399,12.714561712883,13.771346576964,14.527503526623,15.481110912275,14.15206617202,13.585293679818,11.775463534839,3.8717322976241,10.734306208209,4.8958727594763,14.140403314808,4.0053235572412,13.294839577459,5.4871386626955,11.601551819105,7.1182108578403,14.841754251531,0.015467334964952,12.661314799025,2.0743564274027,14.414138324765,1.8894849415259,13.291412090197,11.806136545046,11.089181479155,10.754631116248,20.014056606141,0.14778712499941,14.305075087244,17.462993745175,13.347130078946,7.5990134344746,17.416700043619,1.4317843156503,14.902046026239,9.3182140611748,10.640726047943,8.6967980647733,12.428208554192,9.4288294683423,13.545283763669,10.375768060905}
Screenshot 2023-07-15 174956.png
Screenshot 2023-07-15 174956.png (190.25 KiB) Viewed 18466 times
Please find where the image repeating itself:
Attachments
Screenshot 2023-07-15 183516.png
Screenshot 2023-07-15 183516.png (13.38 KiB) Viewed 18459 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Voronoi Lines
my try to make voronoi regions in toroidal world, work in progress

Code: Select all

-- cc0, 2023, darkfrei

love.window.setTitle ('Voronoi Lines')
--love.window.setTitle ('Voronoi Lines on Toroidal World')

Points = {0,0,29.421497428895,18.262284985482,1.9791994775338,0.71104989006247,28.936347589706,1.3874202099944,0.77918559894233,1.7119154545849,0.74872496156755,18.75908887808,2.4294796576936,18.621404096665,0.74629667130324,17.272948180996,27.224705013952,0.60592345728928,28.113281538712,2.7081013486532,27.286359005096,4.183978333816,29.758882374693,3.3617643405968,26.731307726236,2.3346689791489,2.1391061763197,2.3662886471186,26.11672261621,18.802623146342,25.427344998163,0.35620449316817,28.21890597267,19.192023390212,3.7517173300831,1.7900008652362,1.981748592693,3.7754927204595,3.6491112562124,19.761768053947,4.674214819273,2.9490230330072,5.6408681601946,0.93025608865254,25.153278935918,3.5477422539136,24.74775908144,1.7408658927981,3.6468147671778,17.686777140792,2.7256975440463,16.586500273227,27.353484813482,17.711706794635,3.5807610961327,15.227472542947,1.447531381856,15.587596556207,4.8298954808599,16.620574836613,0.31465693871064,14.276126652375,29.511215767343,15.609803506531,2.1962809166391,13.945271943441,3.2672962025191,4.6199685102339,1.4474853623782,5.5148168661481,29.694158401428,5.2731956805743,5.37416143966,18.912707009383,26.946086120639,5.9227939397719,4.6932753886167,14.330123415792,6.9782426673136,18.413258136099,6.3445081320094,17.066505830656,8.2903487194649,19.086285734748,7.0252711656188,0.3873973193782,8.4495737245075,17.180138859889,24.698151332349,18.85177868671,26.012341279164,16.96074196664,28.960775498939,13.336494835331,0.90739685240295,12.873455631666,22.917225458181,19.363868669458,24.275265008088,17.465685829653,23.929765725272,0.54500552563436,6.7168409399952,2.1326746080956,9.098337121903,0.33492806859019,28.205328998772,14.904968278816,28.647034910054,16.852242409054,23.432729781527,4.2211867275551,23.574917883008,2.7937404923595,24.581165813541,5.5119634572548,0.68237096898904,7.1810494623508,2.2801117761457,7.2564079804841,3.1735159901111,6.11318099228,4.8951935725097,5.7195046128446,4.2766502409951,7.1216422599576,28.389755385136,6.248663557283,27.812609649106,7.7795543089628,25.39745634073,6.7148584441762,25.946492069892,4.8971573573492,26.243061820043,9.2012615989797,28.92375476746,8.9997849663966,6.6697296925175,13.811078483549,5.5586046248046,12.823025353141,3.9743078751966,12.610703282608,6.098882769853,15.109111748691,22.002857044804,2.6583741071336,22.509223849567,5.8222648100415,21.879813738722,4.1833119344917,24.406180342051,8.4994367798685,23.634969557267,7.3137831643219,27.373594538849,16.05002538136,23.448567626534,16.111926027443,22.366804890887,17.568268526608,24.958511918221,15.851389585741,9.8301356791575,18.572545833927,8.0128961369235,15.667830174963,10.113043830961,16.380111796853,9.11275904049,14.720274645358,7.5952044091645,12.660629455291,6.5275294429725,11.165210286208,4.5163089839191,11.071709542587,20.908047017226,5.938537862401,19.903335463998,4.4204289956641,20.608301362255,3.0710626746245,21.67628922207,0.090076372672286,22.760776162152,1.3969603245843,20.182403809908,7.284104666209,19.025181940175,6.0634745760051,21.782208297784,7.0547801776248,18.224622922412,7.8673727956669,17.378466772205,5.8153715963749,18.350488480217,4.1961035468554,21.757523856438,8.5664149354302,27.445342424373,10.133788761031,26.249118878489,10.922312935011,24.495579459621,9.9124655327756,11.594327665859,17.521496729008,11.71943630784,15.251330921105,16.448616033666,8.0877722215436,18.357595870684,9.81539689341,19.692768502809,8.9494817952152,29.527524694761,10.363938169432,0.28983215537493,8.5450233694436,25.945401964827,14.654425062408,17.101329771224,11.063643512431,19.927578543818,10.421911618694,18.851751125117,11.648940994635,16.611875213448,9.575802384804,9.5716853301274,1.6922636139561,8.0456709977104,1.6256254828659,10.933816062008,0.21014898415188,6.288352782026,3.6513728765422,1.6422720181125,9.9966177685061,8.1382361210998,10.737822980767,5.5290028087227,9.5324793548481,21.952304906453,10.723848774477,20.438720270184,12.123753127681,7.8337603688152,3.1691685127183,26.971947966862,13.660304229387,25.532421620072,12.959410658719,23.090454090237,9.3014071791645,17.562995943229,12.714553353205,19.046232707164,13.622709477516,7.1093722630043,5.5013454945225,9.5204935705948,13.318247355303,7.4576655393904,9.491729111497,3.6229295308856,9.0564833977333,5.7374655643323,7.8175367520628,3.1381991278438,10.393587001011,28.415378082348,11.64111327503,2.4157351681502,11.969362611613,17.740948964424,14.31840251801,19.804486852267,14.977275712126,20.834973898727,13.923332868907,18.488724639474,15.891118140154,20.429027062187,16.315774547216,16.154560697578,15.53719982925,15.763623513407,13.958621458879,15.142017683596,10.93762742525,15.843302664241,12.459627475133,22.477959557257,12.332835964072,20.228447124499,17.868882186928,23.354199318503,10.982858873003,24.357392061813,14.346981952072,18.533816474532,17.333983176357,17.231068059174,16.653718869598,22.545180836352,13.80445153977,24.219511279903,12.409347950979,21.997175307694,15.425964150301,8.3087262441023,6.3480565201002,8.8575100984086,5.0097300937438,10.899056802057,13.898530555561,12.274479479612,19.262034919355,12.704951390281,16.60512218453,29.836798430671,11.787720640891,9.2089371408976,9.4885287092576,7.2104595679744,7.8762388661208,19.091432722399,19.075125715517,17.578865924359,18.734822481333,16.352095643637,4.4275630572268,16.218407341999,6.6252182312717,16.197114699429,18.226381716687,16.398094540103,0.40385638370952,18.424780602057,0.40052593299355,14.801651162531,7.2885585469282,14.851496994194,5.2812883188366,9.6224524959129,11.413270183692,10.269836063727,3.1054289539585,11.229618315583,1.904315570997,18.790728835961,2.2051187358729,20.45793004877,1.5154702996483,9.9590984656872,6.411048480504,9.3780411308426,7.7251876337595,17.355078777522,2.9477725246015,16.058958148107,2.1775126916243,13.495441006692,0.63444617856707,13.710411544669,19.073514273732,11.987598345817,12.522740119399,12.714561712883,13.771346576964,14.527503526623,15.481110912275,14.15206617202,13.585293679818,11.775463534839,3.8717322976241,10.734306208209,4.8958727594763,14.140403314808,4.0053235572412,13.294839577459,5.4871386626955,11.601551819105,7.1182108578403,14.841754251531,0.015467334964952,12.661314799025,2.0743564274027,14.414138324765,1.8894849415259,13.291412090197,11.806136545046,11.089181479155,10.754631116248,20.014056606141,0.14778712499941,14.305075087244,17.462993745175,13.347130078946,7.5990134344746,17.416700043619,1.4317843156503,14.902046026239,9.3182140611748,10.640726047943,8.6967980647733,12.428208554192,9.4288294683423,13.545283763669,10.375768060905}

local function checkLineSegmentIntersection(segment, line)
	local x1, y1, x2, y2 = segment[1], segment[2], segment[3], segment[4]
	local x3, y3, x4, y4 = line[1], line[2], line[3], line[4]

	local denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
	if denominator == 0 then
		return false
	end

	local numerator1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
	local t1 = numerator1 / denominator
	return t1 >= 0 and t1 < 1
end


local function calculateVoronoiRegions(points, gridWidth, gridHeight)
	local regions = {}
	for i = 1, #points - 3, 2 do
		table.insert (regions, {x=points[i], y=points[i+1], lines={}})
	end
	-- Iterate over pairs of points

	for i, regionA in ipairs (regions) do
		local lines = regionA.lines
		local p1x, p1y = regionA.x, regionA.y

		for j, regionB in ipairs (regions) do
			local p2x, p2y = regionB.x, regionB.y
			if i == j then
				-- same region, do nothing
			else

				-- Calculate the midpoint between the points
				local midpointX = (p1x + p2x) / 2
				local midpointY = (p1y + p2y) / 2

				-- Calculate the direction vector from p1 to p2
				local directionX = p2x - p1x
				local directionY = p2y - p1y

				-- Normalize the direction vector
				local magnitude = math.sqrt(directionX^2 + directionY^2)
				directionX = directionX / magnitude
				directionY = directionY / magnitude

				local lineLength = 0.35

				-- Create the half-edge
				local line = {
					midpointX - directionY*lineLength,
					midpointY + directionX*lineLength,
					midpointX + directionY*lineLength,
					midpointY - directionX*lineLength,

					mx = midpointX,
					my = midpointY,
				}

				table.insert(lines, line)
			end

			for k, lineA in ipairs (lines) do
				local mx, my = lineA.mx, lineA.my
				local segment = {p1x, p1y, mx, my} -- red line
				for l, lineB in ipairs (lines) do -- yellow line
					if not (lineA == lineB) then
						if checkLineSegmentIntersection (segment, lineB) then
							lineA.valid = false
						end
					end
				end
			end

			for i = #lines, 1, -1 do
				local line = lines[i]
				if line.valid == false then
					table.remove (lines, i)
				end
			end

			local points = {}
			for i = 1, #lines do
				local j = (i)% #lines + 1
				local lineA = lines[i]
				local lineB = lines[j]

			end
		end
	end

	print ('#regions', #regions)
	return regions
end



function love.load ()
	GridWidth, GridHeight = 30, 20

	Scale = math.floor (math.min (love.graphics.getWidth()/GridWidth, love.graphics.getHeight()/GridHeight))

	local Width = GridWidth*Scale
	local Height = GridHeight*Scale
	love.window.setMode (Width, Height)

	Regions = calculateVoronoiRegions(Points, GridWidth, GridHeight)
end


function love.draw()

	love.graphics.scale (Scale)
	love.graphics.setPointSize (3)
	love.graphics.setLineWidth (0.25/Scale)

	love.graphics.setColor (0.5,0.5,0.5)
	for i, region in ipairs (Regions) do
		for j, line in ipairs (region.lines) do
			love.graphics.line (line)
		end
	end


	local index = 204
	local region = Regions[index]
	local x, y = region.x, region.y
	for j, line in ipairs (region.lines) do
		love.graphics.setColor (1,0,0)
		love.graphics.line ({x, y, line.mx, line.my})
		love.graphics.setColor (1,1,0)
		love.graphics.line (line)
		love.graphics.points (line.mx, line.my)
	end

	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.points (region.x, region.y)
	end

	love.graphics.scale (1/Scale)
	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.print (i, region.x*Scale-10, region.y*Scale+1)
	end
end
Screenshot 2023-07-16 223842.png
Screenshot 2023-07-16 223842.png (143.17 KiB) Viewed 18335 times
Attachments
Screenshot 2023-07-16 224433.png
Screenshot 2023-07-16 224433.png (86.63 KiB) Viewed 18334 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

It looks better, but the filter looks not right:

Code: Select all

-- License CC0 (Creative Commons license) (c) darkfrei, 2023

love.window.setMode(1024, 1024)

Width, Height = love.graphics.getDimensions( )


-- cc0, 2023, darkfrei

love.window.setTitle ('Voronoi Lines')
--love.window.setTitle ('Voronoi Lines on Toroidal World')

Points = {0,0,29.421497428895,18.262284985482,1.9791994775338,0.71104989006247,28.936347589706,1.3874202099944,0.77918559894233,1.7119154545849,0.74872496156755,18.75908887808,2.4294796576936,18.621404096665,0.74629667130324,17.272948180996,27.224705013952,0.60592345728928,28.113281538712,2.7081013486532,27.286359005096,4.183978333816,29.758882374693,3.3617643405968,26.731307726236,2.3346689791489,2.1391061763197,2.3662886471186,26.11672261621,18.802623146342,25.427344998163,0.35620449316817,28.21890597267,19.192023390212,3.7517173300831,1.7900008652362,1.981748592693,3.7754927204595,3.6491112562124,19.761768053947,4.674214819273,2.9490230330072,5.6408681601946,0.93025608865254,25.153278935918,3.5477422539136,24.74775908144,1.7408658927981,3.6468147671778,17.686777140792,2.7256975440463,16.586500273227,27.353484813482,17.711706794635,3.5807610961327,15.227472542947,1.447531381856,15.587596556207,4.8298954808599,16.620574836613,0.31465693871064,14.276126652375,29.511215767343,15.609803506531,2.1962809166391,13.945271943441,3.2672962025191,4.6199685102339,1.4474853623782,5.5148168661481,29.694158401428,5.2731956805743,5.37416143966,18.912707009383,26.946086120639,5.9227939397719,4.6932753886167,14.330123415792,6.9782426673136,18.413258136099,6.3445081320094,17.066505830656,8.2903487194649,19.086285734748,7.0252711656188,0.3873973193782,8.4495737245075,17.180138859889,24.698151332349,18.85177868671,26.012341279164,16.96074196664,28.960775498939,13.336494835331,0.90739685240295,12.873455631666,22.917225458181,19.363868669458,24.275265008088,17.465685829653,23.929765725272,0.54500552563436,6.7168409399952,2.1326746080956,9.098337121903,0.33492806859019,28.205328998772,14.904968278816,28.647034910054,16.852242409054,23.432729781527,4.2211867275551,23.574917883008,2.7937404923595,24.581165813541,5.5119634572548,0.68237096898904,7.1810494623508,2.2801117761457,7.2564079804841,3.1735159901111,6.11318099228,4.8951935725097,5.7195046128446,4.2766502409951,7.1216422599576,28.389755385136,6.248663557283,27.812609649106,7.7795543089628,25.39745634073,6.7148584441762,25.946492069892,4.8971573573492,26.243061820043,9.2012615989797,28.92375476746,8.9997849663966,6.6697296925175,13.811078483549,5.5586046248046,12.823025353141,3.9743078751966,12.610703282608,6.098882769853,15.109111748691,22.002857044804,2.6583741071336,22.509223849567,5.8222648100415,21.879813738722,4.1833119344917,24.406180342051,8.4994367798685,23.634969557267,7.3137831643219,27.373594538849,16.05002538136,23.448567626534,16.111926027443,22.366804890887,17.568268526608,24.958511918221,15.851389585741,9.8301356791575,18.572545833927,8.0128961369235,15.667830174963,10.113043830961,16.380111796853,9.11275904049,14.720274645358,7.5952044091645,12.660629455291,6.5275294429725,11.165210286208,4.5163089839191,11.071709542587,20.908047017226,5.938537862401,19.903335463998,4.4204289956641,20.608301362255,3.0710626746245,21.67628922207,0.090076372672286,22.760776162152,1.3969603245843,20.182403809908,7.284104666209,19.025181940175,6.0634745760051,21.782208297784,7.0547801776248,18.224622922412,7.8673727956669,17.378466772205,5.8153715963749,18.350488480217,4.1961035468554,21.757523856438,8.5664149354302,27.445342424373,10.133788761031,26.249118878489,10.922312935011,24.495579459621,9.9124655327756,11.594327665859,17.521496729008,11.71943630784,15.251330921105,16.448616033666,8.0877722215436,18.357595870684,9.81539689341,19.692768502809,8.9494817952152,29.527524694761,10.363938169432,0.28983215537493,8.5450233694436,25.945401964827,14.654425062408,17.101329771224,11.063643512431,19.927578543818,10.421911618694,18.851751125117,11.648940994635,16.611875213448,9.575802384804,9.5716853301274,1.6922636139561,8.0456709977104,1.6256254828659,10.933816062008,0.21014898415188,6.288352782026,3.6513728765422,1.6422720181125,9.9966177685061,8.1382361210998,10.737822980767,5.5290028087227,9.5324793548481,21.952304906453,10.723848774477,20.438720270184,12.123753127681,7.8337603688152,3.1691685127183,26.971947966862,13.660304229387,25.532421620072,12.959410658719,23.090454090237,9.3014071791645,17.562995943229,12.714553353205,19.046232707164,13.622709477516,7.1093722630043,5.5013454945225,9.5204935705948,13.318247355303,7.4576655393904,9.491729111497,3.6229295308856,9.0564833977333,5.7374655643323,7.8175367520628,3.1381991278438,10.393587001011,28.415378082348,11.64111327503,2.4157351681502,11.969362611613,17.740948964424,14.31840251801,19.804486852267,14.977275712126,20.834973898727,13.923332868907,18.488724639474,15.891118140154,20.429027062187,16.315774547216,16.154560697578,15.53719982925,15.763623513407,13.958621458879,15.142017683596,10.93762742525,15.843302664241,12.459627475133,22.477959557257,12.332835964072,20.228447124499,17.868882186928,23.354199318503,10.982858873003,24.357392061813,14.346981952072,18.533816474532,17.333983176357,17.231068059174,16.653718869598,22.545180836352,13.80445153977,24.219511279903,12.409347950979,21.997175307694,15.425964150301,8.3087262441023,6.3480565201002,8.8575100984086,5.0097300937438,10.899056802057,13.898530555561,12.274479479612,19.262034919355,12.704951390281,16.60512218453,29.836798430671,11.787720640891,9.2089371408976,9.4885287092576,7.2104595679744,7.8762388661208,19.091432722399,19.075125715517,17.578865924359,18.734822481333,16.352095643637,4.4275630572268,16.218407341999,6.6252182312717,16.197114699429,18.226381716687,16.398094540103,0.40385638370952,18.424780602057,0.40052593299355,14.801651162531,7.2885585469282,14.851496994194,5.2812883188366,9.6224524959129,11.413270183692,10.269836063727,3.1054289539585,11.229618315583,1.904315570997,18.790728835961,2.2051187358729,20.45793004877,1.5154702996483,9.9590984656872,6.411048480504,9.3780411308426,7.7251876337595,17.355078777522,2.9477725246015,16.058958148107,2.1775126916243,13.495441006692,0.63444617856707,13.710411544669,19.073514273732,11.987598345817,12.522740119399,12.714561712883,13.771346576964,14.527503526623,15.481110912275,14.15206617202,13.585293679818,11.775463534839,3.8717322976241,10.734306208209,4.8958727594763,14.140403314808,4.0053235572412,13.294839577459,5.4871386626955,11.601551819105,7.1182108578403,14.841754251531,0.015467334964952,12.661314799025,2.0743564274027,14.414138324765,1.8894849415259,13.291412090197,11.806136545046,11.089181479155,10.754631116248,20.014056606141,0.14778712499941,14.305075087244,17.462993745175,13.347130078946,7.5990134344746,17.416700043619,1.4317843156503,14.902046026239,9.3182140611748,10.640726047943,8.6967980647733,12.428208554192,9.4288294683423,13.545283763669,10.375768060905}


local function findRaysIntersection (x1,y1,x2,y2,  x3,y3,x4,y4)
	local denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
	if denominator == 0 then
		return nil
	end
	local dx1, dy1 = (x1 - x3), (y1 - y3)

	local t = (dx1 * (y3 - y4) - dy1 * (x3 - x4)) / denominator
	local u = (dx1 * (y1 - y2) - dy1 * (x1 - x2)) / denominator

	if t >= 0 and u >= 0 then
		local dx = t * (x2 - x1)
		local dy = t * (y2 - y1)
		local intersectionX = x1 + dx
		local intersectionY = y1 + dy
		local t1 = math.sqrt(dx*dx+dy*dy)
		local t2 = math.sqrt((intersectionX-x4)^2+(intersectionY-y4)^2)
		return intersectionX, intersectionY, t1, t2
	end

	return nil
end


local function checkLineSegmentIntersection(segment, line)
	local x1, y1, x2, y2 = segment[1], segment[2], segment[3], segment[4]
	local x3, y3, x4, y4 = line[1], line[2], line[3], line[4]

	local denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
	if denominator == 0 then
		return false
	end

	local numerator1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
	local t = numerator1 / denominator
	if t >= 0 and t < 1 then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		return intersectionX, intersectionY
	end
end


local function calculateVoronoiRegions(points, gridWidth, gridHeight)
	local regions = {}
	for i = 1, #points - 3, 2 do
		table.insert (regions, {
				x=points[i], 
				y=points[i+1], 
				lines={}, 
				points={},
			})
	end
	-- Iterate over pairs of points

	for i, regionA in ipairs (regions) do
		local lines = regionA.lines
		local points = regionA.points
		local p1x, p1y = regionA.x, regionA.y

		for j, regionB in ipairs (regions) do
			local p2x, p2y = regionB.x, regionB.y
			if i == j then
				-- same region, do nothing
			else

				-- Calculate the midpoint between the points
				local midpointX = (p1x + p2x) / 2
				local midpointY = (p1y + p2y) / 2

				-- Calculate the direction vector from p1 to p2
				local directionX = p2x - p1x
				local directionY = p2y - p1y

				-- Normalize the direction vector
				local magnitude = math.sqrt(directionX^2 + directionY^2)
				directionX = directionX / magnitude
				directionY = directionY / magnitude

				local lineLength = 1.41

				-- Create the half-edge
				local line = {
					midpointX - directionY*lineLength,
					midpointY + directionX*lineLength,
					midpointX + directionY*lineLength,
					midpointY - directionX*lineLength,

					mx = midpointX,
					my = midpointY,

					t1 = lineLength,
					t2 = lineLength,
					
					angle = math.atan2 (midpointY-p1y, midpointX-p1x),
				}

				table.insert(lines, line)
			end
		end
		
		table.sort (lines, function (a, b) return a.angle < b.angle end)

		for k, lineA in ipairs (lines) do
			local mx, my = lineA.mx, lineA.my
			local segment = {p1x, p1y, mx, my} -- red line
			for l, lineB in ipairs (lines) do -- yellow line
				if not (lineA == lineB) then
					if checkLineSegmentIntersection (segment, lineB) then
						lineA.valid = false
					end
				end
			end
		end

		for i = #lines, 1, -1 do
			local line = lines[i]
			if line.valid == false then
				table.remove (lines, i)
			end
		end
		
--		table.sort (lines, function (a, b) return a.angle < b.angle end)

		-- all regions B are done

		for i = 1, #lines do
			local j = (i)% #lines + 1
			local lineA = lines[i]
			local lineB = lines[j]

			local xa,ya = lineA.mx, lineA.my
			local xb,yb = lineB.mx, lineB.my

			local xa1,ya1, xa2,ya2 = lineA[1], lineA[2], lineA[3], lineA[4]
			local xb1,yb1, xb2,yb2 = lineB[1], lineB[2], lineB[3], lineB[4]

			local tx1, ty1, t11, t12 = findRaysIntersection (xa,ya,xa2,ya2,  xb,yb,xb1,yb1)
			if tx1 and (t11 < lineA.t2) and (t12 < lineB.t1) then
				print ('tx1')
				lineA[3], lineA[4] = tx1, ty1
				lineB[1], lineB[2] = tx1, ty1
				lineA.t2 = t11
				lineB.t1 = t12
			end

			local tx2, ty2, t21, t22 = findRaysIntersection (xa,ya,xa1,ya1,  xb,yb,xb2,yb2)
			if tx2 and (t21 < lineA.t1) and (t22 < lineB.t2) then
--				print ('tx2')
				lineA[1], lineA[2] = tx2, ty2
				lineB[3], lineB[4] = tx2, ty2
				lineA.t1 = t21
				lineB.t2 = t22
			end



		end
	end

	print ('#regions', #regions)
	return regions
end



function love.load ()
	GridWidth, GridHeight = 30, 20

	Scale = math.floor (math.min (love.graphics.getWidth()/GridWidth, love.graphics.getHeight()/GridHeight))

	local Width = GridWidth*Scale
	local Height = GridHeight*Scale
	love.window.setMode (Width, Height)

	Regions = calculateVoronoiRegions(Points, GridWidth, GridHeight)
end


function love.draw()

	love.graphics.scale (Scale)
	love.graphics.setPointSize (5)
	love.graphics.setLineWidth (0.25/Scale)

	love.graphics.setColor (0.5,0.5,0.5)
	for i, region in ipairs (Regions) do
		for j, line in ipairs (region.lines) do
			love.graphics.line (line)
		end

		--		if region.points then
		--			love.graphics.points (region.points)
		--		end
	end


	local index = 204
	local region = Regions[index]
	local x, y = region.x, region.y
	for j, line in ipairs (region.lines) do
		love.graphics.setColor (1,0,0)
		love.graphics.line ({x, y, line.mx, line.my})
		love.graphics.setColor (1,1,0)
		love.graphics.line (line)
		love.graphics.points (line.mx, line.my)
	end

	if region.points then
		love.graphics.setColor (0,1,0)
		love.graphics.points (region.points)
	end

	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.points (region.x, region.y)
	end

	love.graphics.scale (1/Scale)
	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.print (i, region.x*Scale-10, region.y*Scale+1)
	end
end

function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "escape" then
		love.event.quit()
	end
end
2023-07-18T08_33_05-Voronoi Lines.png
2023-07-18T08_33_05-Voronoi Lines.png (201.29 KiB) Viewed 18237 times

Code: Select all

-- License CC0 (Creative Commons license) (c) darkfrei, 2023

love.window.setMode(1200, 800)
Width, Height = love.graphics.getDimensions( )
love.window.setTitle ('Voronoi Lines')
--love.window.setTitle ('Voronoi Lines on Toroidal World')

Points = {0,0,29.421497428895,18.262284985482,1.9791994775338,0.71104989006247,28.936347589706,1.3874202099944,0.77918559894233,1.7119154545849,0.74872496156755,18.75908887808,2.4294796576936,18.621404096665,0.74629667130324,17.272948180996,27.224705013952,0.60592345728928,28.113281538712,2.7081013486532,27.286359005096,4.183978333816,29.758882374693,3.3617643405968,26.731307726236,2.3346689791489,2.1391061763197,2.3662886471186,26.11672261621,18.802623146342,25.427344998163,0.35620449316817,28.21890597267,19.192023390212,3.7517173300831,1.7900008652362,1.981748592693,3.7754927204595,3.6491112562124,19.761768053947,4.674214819273,2.9490230330072,5.6408681601946,0.93025608865254,25.153278935918,3.5477422539136,24.74775908144,1.7408658927981,3.6468147671778,17.686777140792,2.7256975440463,16.586500273227,27.353484813482,17.711706794635,3.5807610961327,15.227472542947,1.447531381856,15.587596556207,4.8298954808599,16.620574836613,0.31465693871064,14.276126652375,29.511215767343,15.609803506531,2.1962809166391,13.945271943441,3.2672962025191,4.6199685102339,1.4474853623782,5.5148168661481,29.694158401428,5.2731956805743,5.37416143966,18.912707009383,26.946086120639,5.9227939397719,4.6932753886167,14.330123415792,6.9782426673136,18.413258136099,6.3445081320094,17.066505830656,8.2903487194649,19.086285734748,7.0252711656188,0.3873973193782,8.4495737245075,17.180138859889,24.698151332349,18.85177868671,26.012341279164,16.96074196664,28.960775498939,13.336494835331,0.90739685240295,12.873455631666,22.917225458181,19.363868669458,24.275265008088,17.465685829653,23.929765725272,0.54500552563436,6.7168409399952,2.1326746080956,9.098337121903,0.33492806859019,28.205328998772,14.904968278816,28.647034910054,16.852242409054,23.432729781527,4.2211867275551,23.574917883008,2.7937404923595,24.581165813541,5.5119634572548,0.68237096898904,7.1810494623508,2.2801117761457,7.2564079804841,3.1735159901111,6.11318099228,4.8951935725097,5.7195046128446,4.2766502409951,7.1216422599576,28.389755385136,6.248663557283,27.812609649106,7.7795543089628,25.39745634073,6.7148584441762,25.946492069892,4.8971573573492,26.243061820043,9.2012615989797,28.92375476746,8.9997849663966,6.6697296925175,13.811078483549,5.5586046248046,12.823025353141,3.9743078751966,12.610703282608,6.098882769853,15.109111748691,22.002857044804,2.6583741071336,22.509223849567,5.8222648100415,21.879813738722,4.1833119344917,24.406180342051,8.4994367798685,23.634969557267,7.3137831643219,27.373594538849,16.05002538136,23.448567626534,16.111926027443,22.366804890887,17.568268526608,24.958511918221,15.851389585741,9.8301356791575,18.572545833927,8.0128961369235,15.667830174963,10.113043830961,16.380111796853,9.11275904049,14.720274645358,7.5952044091645,12.660629455291,6.5275294429725,11.165210286208,4.5163089839191,11.071709542587,20.908047017226,5.938537862401,19.903335463998,4.4204289956641,20.608301362255,3.0710626746245,21.67628922207,0.090076372672286,22.760776162152,1.3969603245843,20.182403809908,7.284104666209,19.025181940175,6.0634745760051,21.782208297784,7.0547801776248,18.224622922412,7.8673727956669,17.378466772205,5.8153715963749,18.350488480217,4.1961035468554,21.757523856438,8.5664149354302,27.445342424373,10.133788761031,26.249118878489,10.922312935011,24.495579459621,9.9124655327756,11.594327665859,17.521496729008,11.71943630784,15.251330921105,16.448616033666,8.0877722215436,18.357595870684,9.81539689341,19.692768502809,8.9494817952152,29.527524694761,10.363938169432,0.28983215537493,8.5450233694436,25.945401964827,14.654425062408,17.101329771224,11.063643512431,19.927578543818,10.421911618694,18.851751125117,11.648940994635,16.611875213448,9.575802384804,9.5716853301274,1.6922636139561,8.0456709977104,1.6256254828659,10.933816062008,0.21014898415188,6.288352782026,3.6513728765422,1.6422720181125,9.9966177685061,8.1382361210998,10.737822980767,5.5290028087227,9.5324793548481,21.952304906453,10.723848774477,20.438720270184,12.123753127681,7.8337603688152,3.1691685127183,26.971947966862,13.660304229387,25.532421620072,12.959410658719,23.090454090237,9.3014071791645,17.562995943229,12.714553353205,19.046232707164,13.622709477516,7.1093722630043,5.5013454945225,9.5204935705948,13.318247355303,7.4576655393904,9.491729111497,3.6229295308856,9.0564833977333,5.7374655643323,7.8175367520628,3.1381991278438,10.393587001011,28.415378082348,11.64111327503,2.4157351681502,11.969362611613,17.740948964424,14.31840251801,19.804486852267,14.977275712126,20.834973898727,13.923332868907,18.488724639474,15.891118140154,20.429027062187,16.315774547216,16.154560697578,15.53719982925,15.763623513407,13.958621458879,15.142017683596,10.93762742525,15.843302664241,12.459627475133,22.477959557257,12.332835964072,20.228447124499,17.868882186928,23.354199318503,10.982858873003,24.357392061813,14.346981952072,18.533816474532,17.333983176357,17.231068059174,16.653718869598,22.545180836352,13.80445153977,24.219511279903,12.409347950979,21.997175307694,15.425964150301,8.3087262441023,6.3480565201002,8.8575100984086,5.0097300937438,10.899056802057,13.898530555561,12.274479479612,19.262034919355,12.704951390281,16.60512218453,29.836798430671,11.787720640891,9.2089371408976,9.4885287092576,7.2104595679744,7.8762388661208,19.091432722399,19.075125715517,17.578865924359,18.734822481333,16.352095643637,4.4275630572268,16.218407341999,6.6252182312717,16.197114699429,18.226381716687,16.398094540103,0.40385638370952,18.424780602057,0.40052593299355,14.801651162531,7.2885585469282,14.851496994194,5.2812883188366,9.6224524959129,11.413270183692,10.269836063727,3.1054289539585,11.229618315583,1.904315570997,18.790728835961,2.2051187358729,20.45793004877,1.5154702996483,9.9590984656872,6.411048480504,9.3780411308426,7.7251876337595,17.355078777522,2.9477725246015,16.058958148107,2.1775126916243,13.495441006692,0.63444617856707,13.710411544669,19.073514273732,11.987598345817,12.522740119399,12.714561712883,13.771346576964,14.527503526623,15.481110912275,14.15206617202,13.585293679818,11.775463534839,3.8717322976241,10.734306208209,4.8958727594763,14.140403314808,4.0053235572412,13.294839577459,5.4871386626955,11.601551819105,7.1182108578403,14.841754251531,0.015467334964952,12.661314799025,2.0743564274027,14.414138324765,1.8894849415259,13.291412090197,11.806136545046,11.089181479155,10.754631116248,20.014056606141,0.14778712499941,14.305075087244,17.462993745175,13.347130078946,7.5990134344746,17.416700043619,1.4317843156503,14.902046026239,9.3182140611748,10.640726047943,8.6967980647733,12.428208554192,9.4288294683423,13.545283763669,10.375768060905}

local function findRaysIntersection (x1,y1,x2,y2,  x3,y3,x4,y4)
	local denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
	if denominator == 0 then
		return nil
	end
	local dx1, dy1 = (x1 - x3), (y1 - y3)

	local t = (dx1 * (y3 - y4) - dy1 * (x3 - x4)) / denominator
	local u = (dx1 * (y1 - y2) - dy1 * (x1 - x2)) / denominator

	if t >= 0 and u >= 0 then
		local dx = t * (x2 - x1)
		local dy = t * (y2 - y1)
		local intersectionX = x1 + dx
		local intersectionY = y1 + dy
		local t1 = math.sqrt(dx*dx+dy*dy)
		local t2 = math.sqrt((intersectionX-x4)^2+(intersectionY-y4)^2)
		return intersectionX, intersectionY, t1, t2
	end
	return nil
end

local function checkLineSegmentIntersection(segment, line)
	local x1, y1, x2, y2 = segment[1], segment[2], segment[3], segment[4]
	local x3, y3, x4, y4 = line[1], line[2], line[3], line[4]

	local denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
	if denominator == 0 then
		return false
	end

	local numerator1 = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
	local t = numerator1 / denominator
	if t >= 0 and t < 1 then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		return intersectionX, intersectionY
	end
end

local function calculateVoronoiRegions(points, gridWidth, gridHeight)
	local regions = {}
	for i = 1, #points - 3, 2 do
		table.insert (regions, {
				x=points[i], 
				y=points[i+1], 
				lines={}, 
				points={},
			})
	end
	-- Iterate over pairs of points

	for i, regionA in ipairs (regions) do
		local lines = regionA.lines
		local points = regionA.points
		local p1x, p1y = regionA.x, regionA.y

		for j, regionB in ipairs (regions) do
			local p2x, p2y = regionB.x, regionB.y
			local dx = p2x-p1x
			local dy = p2y-p1y
			if dx > gridWidth / 2 then
				dx = dx - gridWidth
			elseif dx < - gridWidth / 2 then
				dx = gridWidth + dx
			end
			if dy > gridHeight / 2 then
				dy = dy - gridHeight
			elseif dy < - gridHeight / 2 then
				dy = gridHeight + dy
			end

			p2x = p1x + dx
			p2y = p1y + dy

			if i == j then
				-- same region, do nothing
			else

				-- Calculate the midpoint between the points
				local midpointX = (p1x + p2x) / 2
				local midpointY = (p1y + p2y) / 2

				-- Calculate the direction vector from p1 to p2
				local directionX = p2x - p1x
				local directionY = p2y - p1y

				-- Normalize the direction vector
				local magnitude = math.sqrt(directionX^2 + directionY^2)
				directionX = directionX / magnitude
				directionY = directionY / magnitude

				local lineLength = 10

				-- Create the half-edge
				local line = {
					midpointX - directionY*lineLength,
					midpointY + directionX*lineLength,
					midpointX + directionY*lineLength,
					midpointY - directionX*lineLength,

					mx = midpointX,
					my = midpointY,

					t1 = lineLength,
					t2 = lineLength,

					angle = math.atan2 (midpointY-p1y, midpointX-p1x),
				}
				table.insert(lines, line)
			end
		end

		table.sort (lines, function (a, b) return a.angle < b.angle end)

		for k, lineA in ipairs (lines) do
			local mx, my = lineA.mx, lineA.my
			local segment = {p1x, p1y, mx, my} -- red line
			for l, lineB in ipairs (lines) do -- yellow line
				if not (lineA == lineB) then
					if checkLineSegmentIntersection (segment, lineB) then
						lineA.valid = false
					end
				end
			end
		end

		for i = #lines, 1, -1 do
			local line = lines[i]
			if line.valid == false then
				table.remove (lines, i)
			end
		end

--		table.sort (lines, function (a, b) return a.angle < b.angle end)

		-- all regions B are done

		for iLine = 1, #lines do
			local jLine = (iLine)% #lines + 1
			local lineA = lines[iLine]
			local lineB = lines[jLine]

			local xa,ya = lineA.mx, lineA.my
			local xb,yb = lineB.mx, lineB.my

			local xa1,ya1, xa2,ya2 = lineA[1], lineA[2], lineA[3], lineA[4]
			local xb1,yb1, xb2,yb2 = lineB[1], lineB[2], lineB[3], lineB[4]

			local tx2, ty2, t21, t22 = findRaysIntersection (xa,ya,xa1,ya1,  xb,yb,xb2,yb2)
			if tx2 and (t21 < lineA.t1) and (t22 < lineB.t2) then
				lineA[1], lineA[2] = tx2, ty2
				lineB[3], lineB[4] = tx2, ty2
				lineA.t1 = t21
				lineB.t2 = t22
			end
		end
	end
	print ('#regions', #regions)
	return regions
end

function love.load ()
	GridWidth, GridHeight = 30, 20

	Scale = math.floor (math.min (love.graphics.getWidth()/GridWidth, love.graphics.getHeight()/GridHeight))
	Scale = 32
	local Width = GridWidth*Scale
	local Height = GridHeight*Scale
--	love.window.setMode (Width, Height)

	Regions = calculateVoronoiRegions(Points, GridWidth, GridHeight)
end


function love.draw()
	love.graphics.scale (Scale)
	love.graphics.translate (3,2)
	love.graphics.setPointSize (5)
	love.graphics.setLineWidth (0.25/Scale)

	love.graphics.setColor (0.5,0.5,0.5)
	for i, region in ipairs (Regions) do
		for j, line in ipairs (region.lines) do
			love.graphics.line (line)
		end
	end

	local index = 204
	local region = Regions[index]
	local x, y = region.x, region.y
	for j, line in ipairs (region.lines) do
		love.graphics.setColor (1,0,0)
		love.graphics.line ({x, y, line.mx, line.my})
		love.graphics.setColor (1,1,0)
		love.graphics.line (line)
		love.graphics.points (line.mx, line.my)
	end

	if region.points then
		love.graphics.setColor (0,1,0)
		love.graphics.points (region.points)
	end

	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.points (region.x, region.y)
	end

	love.graphics.scale (1/Scale)
	love.graphics.setColor (1,1,1)
	for i, region in ipairs (Regions) do
		love.graphics.print (i, region.x*Scale-10, region.y*Scale+1)
	end
end

function love.keypressed(key, scancode, isrepeat)
	if false then
	elseif key == "escape" then
		love.event.quit()
	end
end
2023-07-18T09_09_47-Voronoi Lines.png
2023-07-18T09_09_47-Voronoi Lines.png (218.15 KiB) Viewed 18235 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
darkfrei
Party member
Posts: 1204
Joined: Sat Feb 08, 2020 11:09 pm

Re: Code Doodles!

Post by darkfrei »

Polygon cutter: how to cut the part of polygon with an infinite line (with direction).

A lot of optimizations is possible :x

Code: Select all


local function findIntersection(x1, y1, x2, y2, x3, y3, x4, y4)
	-- x1, y1, x2, y2 - segment
	-- x3, y3, x4, y4 - continuous line
	local dx1, dy1 = x2-x1, y2-y1
	local dx2, dy2 = x4-x3, y4-y3
	local denominator = dx1*dy2-dy1*dx2
	if denominator == 0 then
		return nil
	end

	local dx13, dy13 = (x1 - x3), (y1 - y3)

	local t = (dx13 * (y3 - y4) - dy13 * (x3 - x4)) / denominator
	local u = (dx13 * (y1 - y2) - dy13 * (x1 - x2)) / denominator

	if t >= 0 and t <= 1 and u >= 0 then
		local intersectionX = x1 + t * (x2 - x1)
		local intersectionY = y1 + t * (y2 - y1)
		return intersectionX, intersectionY
	end

	return nil
end

local function pseudoScalarProduct(x1, y1, x2, y2, x3, y3, x4, y4)
	local dx1, dy1 = x2-x1, y2-y1
	local dx2, dy2 = x4-x3, y4-y3
	-- positive - goes inside, clockwise
	return dx1 * dy2 - dx2 * dy1
end


local function cropPolygon(polygon, line)
	local x3, y3, x4, y4 = line[1], line[2], line[3], line[4]

	local segments = {}
	local goesInside = nil

	for i = 1, #polygon-1, 2 do
		local x1, y1 = polygon[i], polygon[i + 1]
		local j = (i + 1)%(#polygon)+1
		local x2, y2 = polygon[j], polygon[j + 1]
		local cx, cy = findIntersection(x1, y1, x2, y2, x3, y3, x4, y4)

		local segment = {x1=x1, y1=y1, x2=x2, y2=y2}

		if cx then
			segment.cx = cx
			segment.cy = cy
			goesInside = pseudoScalarProduct(x1, y1, x2, y2, x3, y3, x4, y4) > 0
			segment.goesInside = goesInside
		elseif goesInside ~= nil then
			segment.goesInside = goesInside
		end

		table.insert(segments, segment)
	end

	for i = 1, #segments do
		local segment = segments[i]
		if segment.goesInside == nil then
			segment.goesInside = goesInside
		else
			break
		end
	end

	local clippedPolygon = {}

--	print ('	', #segments)
	local isInside

	local firstSegment = segments[1]
	if not firstSegment.cx and not firstSegment.goesInside then
		table.insert (clippedPolygon, firstSegment.x1)
		table.insert (clippedPolygon, firstSegment.y1)
	elseif firstSegment.cx and firstSegment.goesInside then

		table.insert (clippedPolygon, firstSegment.x1)
		table.insert (clippedPolygon, firstSegment.y1)
	end

	local cx, cy
	for i = 1, #segments do
		local segment = segments[i]
		if segment.cx and segment.goesInside then
--			print (i, 'cx, ins')
			table.insert (clippedPolygon, segment.cx)
			table.insert (clippedPolygon, segment.cy)

			table.insert (clippedPolygon, cx)
			table.insert (clippedPolygon, cy)
		elseif segment.goesInside then
			--print (i, 'ins')
			-- do nothing
		elseif segment.cx and not segment.goesInside then
			--print (i, 'cx, not ins')
			table.insert (clippedPolygon, segment.cx)
			table.insert (clippedPolygon, segment.cy)

			if (not (i == #segments)) then
				table.insert (clippedPolygon, segment.x2)
				table.insert (clippedPolygon, segment.y2)
			end
			-- for not polygons: 
--			cx, cy = segment.cx, segment.cy
		elseif not segment.goesInside then
			--print (i, 'not ins')
			if (not (i == #segments)) then
				table.insert (clippedPolygon, segment.x2)
				table.insert (clippedPolygon, segment.y2)
			end
		else
			--print ('what')
		end
	end 


	return clippedPolygon
end


polygon1 = {300, 100, 600, 200, 500, 400, 200, 500}
--polygon1 = {300, 100, 800, 200, 900, 400}
cropperLine = {100,100, 600, 50}
polygon2 = cropPolygon (polygon1, cropperLine)

function love.load()

end


function love.update(dt)

end

function love.draw()
	love.graphics.setLineWidth (3)
	love.graphics.setColor (0.5,0.5,0.5)
	love.graphics.polygon ('line', polygon1)
	--	love.graphics.line (polygon1)

	love.graphics.setColor (0.8,0,0)
	love.graphics.line (cropperLine)

	if polygon2 and #polygon2 > 2 then
		love.graphics.setColor (0,0.8,0)
		love.graphics.polygon ('line', polygon2)
		--		love.graphics.line (polygon2)
	end
end


function love.mousepressed( x, y, button, istouch, presses )
	cropperLine[1] = x
	cropperLine[2] = y

	polygon2 = cropPolygon (polygon1, cropperLine)
end

function love.mousemoved( x, y, dx, dy, istouch )
	cropperLine[3] = x
	cropperLine[4] = y

	polygon2 = cropPolygon (polygon1, cropperLine)
end
2023-07-18T17_21_39-Untitled.png
2023-07-18T17_21_39-Untitled.png (7.32 KiB) Viewed 18210 times
2023-07-18T17_24_33-Untitled.png
2023-07-18T17_24_33-Untitled.png (8.8 KiB) Viewed 18210 times
Attachments
2023-07-18T17_21_58-Untitled.png
2023-07-18T17_21_58-Untitled.png (8.23 KiB) Viewed 18210 times
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 7 guests