Skip to content

Commit

Permalink
Fix output cursor visualization
Browse files Browse the repository at this point in the history
  • Loading branch information
wqferr committed Feb 27, 2024
1 parent d422c16 commit de0d288
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 32 deletions.
57 changes: 31 additions & 26 deletions lua/app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require "constants"
---@field package func Expression
---@field package inputBounds Bounds
---@field package outputBounds Bounds
---@field package needsRedraw boolean
---@field package needsRerender boolean
---@field package userDrawing boolean
---@field package userLocked boolean
---@field package cursorTrackingEnabled boolean
Expand All @@ -27,6 +27,7 @@ require "constants"
---@field package maxTolerableDistanceForInterp number
---@field package lineWidthScalingFactor number
---@field package lastCursorPosition Complex
---@field package funcLastCursorPosition Complex
---@field package recalcThread any
---@field package recalcPause function
---@field package recalcFullInputSquiggleList ComplexPath[]
Expand Down Expand Up @@ -65,10 +66,10 @@ function App.new(args)
-- do i need this?
-- app:setInputResolution(tonumber(app.inputCanvas.width), tonumber(app.inputCanvas.height))
-- app:setOutputResolution(tonumber(app.outputCanvas.width), tonumber(app.outputCanvas.height))
app.needsRedraw = true
app.needsRerender = true
app.userDrawing = false
app.userLocked = false
app.cursorTrackingEnabled = false
app.cursorTrackingEnabled = true
app.inputSquiggles, app.outputSquiggles = {}, {}
return app
end
Expand All @@ -77,24 +78,28 @@ end
---@param point Complex
---@return Complex
---@return number
---@return number
---@return number?
local function calculateFunc(app, point, inputThickness)
local fc = app.func:evaluate(point) --[[@as Complex]]
local dz = app.func:derivative():evaluate(point)--[[@as Complex]]:abs()
local thickness = inputThickness * app.lineWidthScalingFactor * dz
return fc, dz, thickness
local outputThickness = nil
if inputThickness then
outputThickness = inputThickness * app.lineWidthScalingFactor * dz
end
return fc, dz, outputThickness
end

local function renderAxes(app)
app.inputAxes:draw()
app.outputAxes:draw()
end

---@param app App
local function renderOutputCursor(app)
if not app.cursorTrackingEnabled or tostring(app.lastCursorPosition) == "nan" then
if not app.cursorTrackingEnabled or not app.funcLastCursorPosition then
return
end
local x, y = app.outputBounds:complexToPixel(app.lastCursorPosition)
local x, y = app.outputBounds:complexToPixel(app.funcLastCursorPosition)
x, y = 0.5 + math.floor(x), 0.5 + math.floor(y)
app.outputCtx.strokeStyle = "#333"
app.outputCtx.lineWidth = 1
Expand Down Expand Up @@ -129,8 +134,11 @@ local function renderPrecomputedCanvasesToRealThings(app)
app.outputCtx:drawImage(app.outputPrecomputedCtx.canvas, 0, 0)
end

local function render(app, recalcOldPaths, forceRedraw)
if not app.needsRedraw and not forceRedraw then
---@param app App
---@param recalcOldPaths boolean
---@param forceRerender boolean
local function render(app, recalcOldPaths, forceRerender)
if not app.needsRerender and not forceRerender then
return
end
clearCtx(app.inputCtx)
Expand All @@ -143,12 +151,12 @@ local function render(app, recalcOldPaths, forceRedraw)
if app:isUserDrawing() then
app:lastInputSquiggle():drawVirtualSegment(app.inputCtx, app.inputBounds, app.lastCursorPosition)

local fLastCursorPosition = calculateFunc(app, app.lastCursorPosition, app:lastInputSquiggle():endThickness())
app:lastOutputSquiggle():drawVirtualSegment(app.outputCtx, app.outputBounds, fLastCursorPosition)
-- TODO: heuristically detect discontinuities before drawing output virtual segment
app:lastOutputSquiggle():drawVirtualSegment(app.outputCtx, app.outputBounds, app.funcLastCursorPosition)
else
renderOutputCursor(app)
end
app.needsRedraw = false
app.needsRerender = false
end

function App:render()
Expand All @@ -174,6 +182,7 @@ local function pushPointSimple(app, inputPoint, outputPoint, outputThickness, di
end
app:lastOutputSquiggle():pushPoint(outputPoint, outputThickness, discontinuity)
app:lastOutputSquiggle():drawLastSegment(app.outputPrecomputedCtx, app.outputBounds)
app.needsRerender = true
end

---Pushes as many points as necessary to make path smooth; detects discontinuities
Expand Down Expand Up @@ -240,7 +249,7 @@ end
function App:removeLastSquiggle()
table.remove(self.inputSquiggles)
table.remove(self.outputSquiggles)
self:scheduleRedraw()
self.needsRerender = true
render(self, true, true)
end

Expand All @@ -251,8 +260,6 @@ function App:startDrawing(color, penSize, canvasX, canvasY)
self.userDrawing = true
local startPoint = self.inputBounds:pixelToComplex(canvasX, canvasY)
startPath(self, color, penSize, startPoint)
-- push a new point so it becomes visible immediately and so we can manipulate the endpoint
-- pushPointSimple(self, startPoint)
end

function App:finishDrawing()
Expand Down Expand Up @@ -335,13 +342,15 @@ local function doSquiggleRecalc(app, onDone)
end
end

local function nop() end
---Spawn a thread that recalculates all paths
---@param app App
---@param onDone function
local function fullyRecalculate(app, onDone)
if not app.inputSquiggles[1] then
return
end
onDone = onDone or nop
if app:isRecalculating() then
-- current recalc in progress, stop it and start over
app.recalcPause()
Expand All @@ -350,7 +359,6 @@ local function fullyRecalculate(app, onDone)
app.recalcFullInputSquiggleList = app.inputSquiggles
end
app.inputSquiggles, app.outputSquiggles = {}, {}
-- TODO: loading animation maybe
app.recalcThread, app.recalcPause = thread(doSquiggleRecalc(app, onDone))
app.recalcThread()
end
Expand All @@ -367,6 +375,10 @@ function App:setFunc(sdExpression, onDoneRecalculating)
fullyRecalculate(self, onDoneRecalculating)
end

function App:getFunc()
return self.func
end

---@param app App
local function updateLineWidthScalingFactor(app)
if not app.inputBounds or not app.outputBounds then
Expand Down Expand Up @@ -397,20 +409,13 @@ function App:setOutputBounds(bounds)
self.maxTolerableDistanceForInterp = self.outputBounds:pixelsToMeasurement(MAX_PIXEL_DISTANCE_BEFORE_INTERP)
end

function App:setLineWidth(newValue)
self.lineWidth = newValue
end

function App:scheduleRedraw()
self.needsRedraw = true
end

function App:updateCursorPosition(canvasX, canvasY)
self.lastCursorPosition = self.inputBounds:pixelToComplex(canvasX, canvasY)
self.funcLastCursorPosition = calculateFunc(self, self.lastCursorPosition)
if self:isUserDrawing() and (self.lastCursorPosition - self:lastInputSquiggle():endPoint()):abs() > self.cursorMovePointPushThreshold then
recursivelyPushPointsIfNeeded(self, { self.lastCursorPosition })
end
self:scheduleRedraw()
self.needsRerender = true
end

function App:setCursorTrackingEnabled(enabled)
Expand Down
20 changes: 14 additions & 6 deletions lua/ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ local function loadFunc(text)
if not ok then
return nil, result
end
if tostring(result) == tostring(func) then
if tostring(result) == tostring(app:getFunc()) then
return nil, "Function did not change"
end
return result
Expand Down Expand Up @@ -166,7 +166,7 @@ js.global:setInterval(function()
end
end, 1000)

local periodOf60Hz = math.floor(1000 / 60)
local periodOf60Hz = 1000 / 60
local function renderApp()
app:render()
js.global:setTimeout(renderApp, periodOf60Hz)
Expand Down Expand Up @@ -243,12 +243,20 @@ end
inputCanvas:addEventListener("touchstart", userStartPath, {passive = false})
inputCanvas:addEventListener("mousedown", userStartPath)

local function userFinishPath(_, mouseEvent)
local function userFinishPath(enableTracking)
app:finishDrawing()
app:setCursorTrackingEnabled(enableTracking)
end
inputCanvas:addEventListener("mouseup", userFinishPath)
inputCanvas:addEventListener("touchend", function(_) userFinishPath(nil, nil) end)
inputCanvas:addEventListener("mouseout", userFinishPath)

inputCanvas:addEventListener("mouseup", function()
userFinishPath(true)
end)
inputCanvas:addEventListener("touchend", function()
userFinishPath(false)
end)
inputCanvas:addEventListener("mouseout", function()
userFinishPath(false)
end)

local function cursorMove(_, event)
local cx, cy = getEventCoords(event)
Expand Down

0 comments on commit de0d288

Please sign in to comment.