Skip to content

Commit

Permalink
add layer click handlers and coordinates convertion logic
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-sts committed Apr 17, 2024
1 parent 00f392b commit 5b7321e
Show file tree
Hide file tree
Showing 10 changed files with 161 additions and 12 deletions.
5 changes: 0 additions & 5 deletions src/main/kotlin/solve/rendering/canvas/OpenGLCanvas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ abstract class OpenGLCanvas {
}

private fun render(event: GLRenderEvent) {
/*glEnable(GL_BLEND)
glEnable(GL_DEPTH_TEST)
glEnable(GL_MULTISAMPLE)
glDepthFunc(GL_LEQUAL)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)*/
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)

onDraw(event.delta.toFloat())
Expand Down
47 changes: 45 additions & 2 deletions src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import solve.rendering.engine.core.renderers.FramesRenderer
import solve.rendering.engine.core.renderers.LinesLayerRenderer
import solve.rendering.engine.core.renderers.PlanesLayerRenderer
import solve.rendering.engine.core.renderers.PointsLayerRenderer
import solve.rendering.engine.core.renderers.Renderer
import solve.rendering.engine.utils.minus
import solve.rendering.engine.utils.plus
import solve.rendering.engine.utils.times
import solve.rendering.engine.utils.toFloatVector
import solve.scene.controller.SceneController
Expand All @@ -30,6 +32,8 @@ class SceneCanvas : OpenGLCanvas() {

private var framesSelectionSize = 0
private var framesSize = Vector2i()
private val framesRatio: Float
get() = framesSize.x.toFloat() / framesSize.y
private var columnsNumber = 0
private val rowsNumber: Int
get() = (framesSelectionSize.toFloat() / columnsNumber.toFloat()).ceilToInt()
Expand Down Expand Up @@ -99,6 +103,16 @@ class SceneCanvas : OpenGLCanvas() {
isDraggingScene = false
}

fun interactWithLandmark(screenPoint: Vector2i) {
val frameCoordinate = shaderToFrameVector(calculateWindowTopLeftCornerShaderPosition()) + screenToFrameVector(screenPoint)
//val frameIndex = frameCoordinate.toIntVector()
// Frame local coordinate including spacing area.
val frameLocalCoordinate = Vector2f(frameCoordinate.x % 1, frameCoordinate.y % 1)
// Frame local coordinate excluding spacing area.
frameLocalCoordinate.y *= (1 + Renderer.FramesSpacing)
frameLocalCoordinate.x *= (framesSize.x + Renderer.getSpacingWidth(framesSize)) / framesSize.x
}

fun zoomToPoint(screenPoint: Vector2i, newZoom: Float) {
val cameraPoint = fromScreenToCameraPoint(screenPoint)
window.camera.zoomToPoint(cameraPoint, newZoom)
Expand All @@ -125,6 +139,33 @@ class SceneCanvas : OpenGLCanvas() {
canvasScene?.update()
}

private fun calculateWindowTopLeftCornerShaderPosition() : Vector2f {
return window.camera.position - screenToShaderVector(Vector2i(window.size) / 2f)
}

// Converts screen vector to shader coordinates.
// One frame excluding spacing area corresponds to a (1, framesRatio) vector.
private fun screenToShaderVector(screenVector: Vector2i) : Vector2f {
return Vector2f(screenVector) / window.camera.scaledZoom
}

// Converts screen vector to frame coordinates.
// One frame including spacing area corresponds to a (1, 1) vector.
private fun screenToFrameVector(screenVector: Vector2i) : Vector2f {
val shaderVector = screenToShaderVector(screenVector)
val frameVector = shaderToFrameVector(shaderVector)

return frameVector
}

private fun shaderToFrameVector(shaderVector: Vector2f) : Vector2f {
val frameVector = Vector2f(shaderVector)
frameVector.x /= (framesSize.x + Renderer.getSpacingWidth(framesSize)) / framesSize.y
frameVector.y /= (1 + Renderer.FramesSpacing)

return frameVector
}

private fun checkRenderersInitialization() {
if (needToReinitializeRenderers) {
reinitializeRenderers()
Expand Down Expand Up @@ -167,8 +208,10 @@ class SceneCanvas : OpenGLCanvas() {
val halfScreenSize = (Vector2f(window.width.toFloat(), window.height.toFloat()) / 2f) / window.camera.scaledZoom
leftUpperCornerCameraPosition = halfScreenSize

val framesSelectionSize =
Vector2i(columnsNumber * framesSize.x, rowsNumber * framesSize.y).toFloatVector()
val framesSelectionSize = Vector2f(
columnsNumber * framesSize.x + (columnsNumber - 1) * Renderer.getSpacingWidth(framesSize),
rowsNumber * framesSize.y + (rowsNumber - 1) * Renderer.getSpacingWidth(framesSize)
)
val framesSelectionScreenSize =
framesSelectionSize * window.camera.zoom / IdentityFramesSizeScale / window.camera.scaledZoom

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package solve.rendering.engine.core.input

import org.joml.Vector2i
import solve.scene.model.Landmark

abstract class LayerClickHandler<T: Landmark> {
// Returns the index of the clicked landmark, if there is one.
// Otherwise returns -1.
abstract fun indexOfClickedLandmark(landmarks: List<T>, clickedPixelCoordinate: Vector2i): Int
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package solve.rendering.engine.core.input

import org.joml.Vector2i
import solve.rendering.engine.utils.pointToSegmentDistance
import solve.rendering.engine.utils.toFloatVector
import solve.rendering.engine.utils.toVector2i
import solve.scene.model.Landmark.Line

class LineLayerClickHandler : LayerClickHandler<Line>() {
override fun indexOfClickedLandmark(landmarks: List<Line>, clickedPixelCoordinate: Vector2i): Int {
var minLineDistanceIndex = -1
var minLineDistance = Float.MAX_VALUE

landmarks.forEachIndexed { index, line ->
val lineStartCoordinate = line.startCoordinate.toVector2i()
val lineFinishCoordinate = line.finishCoordinate.toVector2i()
val lineDistance = pointToSegmentDistance(
clickedPixelCoordinate.toFloatVector(),
lineStartCoordinate.toFloatVector(),
lineFinishCoordinate.toFloatVector()
)
if (lineDistance < ClickedLandmarkMaxAllowedDistance && lineDistance < minLineDistance) {
minLineDistanceIndex = index
minLineDistance = lineDistance
}
}

return minLineDistanceIndex
}

companion object {
private const val ClickedLandmarkMaxAllowedDistance = 3
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package solve.rendering.engine.core.input

object MouseInputHandler {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package solve.rendering.engine.core.input

import org.joml.Vector2i
import solve.rendering.engine.utils.minus
import solve.rendering.engine.utils.toVector2i
import solve.scene.model.Landmark.Keypoint

class PointLayerClickHandler : LayerClickHandler<Keypoint>() {
override fun indexOfClickedLandmark(landmarks: List<Keypoint>, clickedPixelCoordinate: Vector2i): Int {
var minKeypointDistanceIndex = -1
var minKeypointDistance = Double.MAX_VALUE

landmarks.forEachIndexed { index, keypoint ->
val keypointCoordinate = keypoint.coordinate.toVector2i()
val keypointDistance = (keypointCoordinate - clickedPixelCoordinate).length()
if (keypointDistance < ClickedLandmarkMaxAllowedDistance && keypointDistance < minKeypointDistance) {
minKeypointDistanceIndex = index
minKeypointDistance = keypointDistance
}
}

return minKeypointDistanceIndex
}

companion object {
private const val ClickedLandmarkMaxAllowedDistance = 3
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package solve.rendering.engine.core.renderers

import org.joml.Vector2f
import org.joml.Vector2i
import org.lwjgl.opengl.GL11.GL_UNSIGNED_INT
import org.lwjgl.opengl.GL11.glDrawElements
import solve.rendering.engine.Window
Expand Down Expand Up @@ -161,6 +162,8 @@ abstract class Renderer(protected val window: Window) : Comparable<Renderer> {
const val FramesSpacingUniformName = "uFramesSpacing"

const val DefaultGridWidth = 10
const val FramesSpacing = 0.02f
const val FramesSpacing = 0.25f

fun getSpacingWidth(framesSize: Vector2i) = framesSize.y * FramesSpacing
}
}
17 changes: 17 additions & 0 deletions src/main/kotlin/solve/rendering/engine/utils/CalculationUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package solve.rendering.engine.utils

import org.joml.Vector2f
import kotlin.math.abs
import kotlin.math.pow
import kotlin.math.sqrt

fun pointToSegmentDistance(
pointPosition: Vector2f,
segmentStartPosition: Vector2f,
segmentEndPosition: Vector2f
) : Float {
return abs((segmentEndPosition.x - segmentStartPosition.x) * (pointPosition.y - segmentStartPosition.y) -
(pointPosition.x - segmentStartPosition.x) * (segmentEndPosition.y - segmentStartPosition.y)) /
sqrt((segmentEndPosition.x - segmentStartPosition.x).pow(2) +
(segmentEndPosition.y - segmentStartPosition.y).pow(2))
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.joml.Vector3f
import org.joml.Vector3i
import org.joml.Vector4f
import org.joml.Vector4i
import solve.scene.model.Point

operator fun Vector2f.plus(otherVector: Vector2f): Vector2f = Vector2f(this).add(otherVector)
operator fun Vector3f.plus(otherVector: Vector3f): Vector3f = Vector3f(this).add(otherVector)
Expand Down Expand Up @@ -74,3 +75,5 @@ fun Vector2f.toList() = listOf(x, y)
fun Vector3f.toList() = listOf(x, y, z)

fun Vector4f.toList() = listOf(x, y, z, w)

fun Point.toVector2i() = Vector2i(x.toInt(), y.toInt())
19 changes: 15 additions & 4 deletions src/main/kotlin/solve/scene/view/SceneView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class SceneView : View() {

private var mouseScreenPoint = Vector2i()

private var wasMouseDragging = false

var currentAssociationsManager: AssociationsManager<VisualizationFrame, Landmark.Keypoint>? = null
private set

Expand Down Expand Up @@ -79,24 +81,33 @@ class SceneView : View() {
mouseScreenPoint = extrudeEventMousePosition(event)
}
root.setOnMouseDragged { event ->
if (event.button != MouseDragButton) {
if (event.button != MouseInteractButton) {
return@setOnMouseDragged
}
wasMouseDragging = true
mouseScreenPoint = extrudeEventMousePosition(event)
canvas.dragTo(mouseScreenPoint)
}
root.setOnMousePressed { event ->
if (event.button != MouseDragButton) {
if (event.button != MouseInteractButton) {
return@setOnMousePressed
}
canvas.startDragging(mouseScreenPoint)
}
root.setOnMouseReleased { event ->
if (event.button != MouseDragButton) {
if (event.button != MouseInteractButton) {
return@setOnMouseReleased
}
canvas.stopDragging()
}
root.setOnMouseClicked { event ->
if (event.button != MouseInteractButton) {
return@setOnMouseClicked
}
if (!wasMouseDragging)
canvas.interactWithLandmark(mouseScreenPoint)
wasMouseDragging = false
}
root.setOnScroll { event ->
val scrollDelta = event.deltaY
if (scrollDelta > 0) {
Expand All @@ -108,7 +119,7 @@ class SceneView : View() {
}

companion object {
private val MouseDragButton = MouseButton.MIDDLE
private val MouseInteractButton = MouseButton.PRIMARY

const val framesMargin = 0.0
const val scrollSpeed = 20.0
Expand Down

0 comments on commit 5b7321e

Please sign in to comment.