Skip to content

Commit

Permalink
add points and lines selection
Browse files Browse the repository at this point in the history
  • Loading branch information
mi-sts committed Apr 30, 2024
1 parent 3f9076a commit 31a2b70
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 28 deletions.
60 changes: 53 additions & 7 deletions src/main/kotlin/solve/rendering/canvas/SceneCanvas.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package solve.rendering.canvas

import org.joml.Vector2f
import org.joml.Vector2i
import solve.rendering.engine.core.input.LayerClickHandler
import solve.rendering.engine.core.input.LineLayerClickHandler
import solve.rendering.engine.core.input.PointLayerClickHandler
import solve.rendering.engine.core.renderers.FramesRenderer
import solve.rendering.engine.core.renderers.LinesLayerRenderer
import solve.rendering.engine.core.renderers.PlanesLayerRenderer
Expand All @@ -13,6 +16,7 @@ import solve.rendering.engine.utils.times
import solve.rendering.engine.utils.toFloatVector
import solve.rendering.engine.utils.toIntVector
import solve.scene.controller.SceneController
import solve.scene.model.Landmark
import solve.scene.model.Layer
import solve.scene.model.Scene
import solve.scene.model.VisualizationFrame
Expand All @@ -31,6 +35,8 @@ class SceneCanvas : OpenGLCanvas() {
private var leftUpperCornerCameraPosition = Vector2f()
private var rightLowerCornerCameraPosition = Vector2f()

private var lastLayersWithCommonSettings = listOf<Layer>()
private var lastFramesSelection = listOf<VisualizationFrame>()
private var framesSelectionSize = 0
private var framesSize = Vector2i()
private val framesRatio: Float
Expand All @@ -51,6 +57,9 @@ class SceneCanvas : OpenGLCanvas() {
(1 + Renderer.FramesSpacing)
)

private val pointLayerClickHandler = PointLayerClickHandler()
private val lineLayerClickHandler = LineLayerClickHandler()

init {
initializeCanvasEvents()
}
Expand Down Expand Up @@ -79,11 +88,12 @@ class SceneCanvas : OpenGLCanvas() {
engineScene?.landmarkRenderers?.forEach { renderer ->
val rendererLayerSettings =
engineScene?.landmarkLayerRendererLayers?.get(renderer)?.settings ?: return@forEach
val selectedFramesLayers =
lastLayersWithCommonSettings =
scene?.getLayersWithCommonSettings(rendererLayerSettings, framesSelection) ?: return@forEach
renderer.setFramesSelectionLayers(selectedFramesLayers)
renderer.setFramesSelectionLayers(lastLayersWithCommonSettings)
}
framesSelectionSize = framesSelection.count()
lastFramesSelection = framesSelection
}

fun setColumnsNumber(columnsNumber: Int) {
Expand Down Expand Up @@ -155,15 +165,51 @@ class SceneCanvas : OpenGLCanvas() {
}

private fun handleLandmarkInteraction(frameIndex: Int, frameInteractionPixel: Vector2i) {
val interactingVisualizationFrame = scene?.frames?.get(frameIndex) ?: return
if (frameIndex >= lastFramesSelection.count())
return

val interactingVisualizationFrame = lastFramesSelection[frameIndex]
var clickedLandmark: Landmark? = null

interactingVisualizationFrame.layers.forEach { layer ->
when (layer) {
is Layer.PointLayer -> TODO()
is Layer.LineLayer -> TODO()
is Layer.PlaneLayer -> TODO()
is Layer.PointLayer -> {
val pointLandmarks = layer.getLandmarks()
val landmarkIndex =
pointLayerClickHandler.indexOfClickedLandmark(
pointLandmarks,
frameInteractionPixel,
layer.settings.selectedRadius.toFloat() / window.camera.zoom
)

if (landmarkIndex == -1)
return@forEach

clickedLandmark = pointLandmarks[landmarkIndex]
}
is Layer.LineLayer -> {
val lineLandmarks = layer.getLandmarks()
val landmarkIndex =
lineLayerClickHandler.indexOfClickedLandmark(
lineLandmarks,
frameInteractionPixel,
layer.settings.selectedWidth.toFloat() / window.camera.zoom
)

if (landmarkIndex == -1)
return@forEach

clickedLandmark = lineLandmarks[landmarkIndex]
}
is Layer.PlaneLayer -> {}
}
}
frameInteractionPixel.toString()

val selectedLandmark = clickedLandmark ?: return
if (selectedLandmark.layerState.selectedLandmarksUIDs.contains(selectedLandmark.uid))
selectedLandmark.layerState.deselectLandmark(selectedLandmark.uid)
else
selectedLandmark.layerState.selectLandmark(selectedLandmark.uid)
}

private fun calculateWindowTopLeftCornerShaderPosition(): Vector2f {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ 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
// Otherwise, returns -1.
abstract fun indexOfClickedLandmark(landmarks: List<T>, clickedPixelCoordinate: Vector2i, landmarkSize: Float): Int
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ 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 {
override fun indexOfClickedLandmark(
landmarks: List<Line>,
clickedPixelCoordinate: Vector2i,
landmarkSize: Float
): Int {
var minLineDistanceIndex = -1
var minLineDistance = Float.MAX_VALUE

Expand All @@ -19,7 +23,7 @@ class LineLayerClickHandler : LayerClickHandler<Line>() {
lineStartCoordinate.toFloatVector(),
lineFinishCoordinate.toFloatVector()
)
if (lineDistance < ClickedLandmarkMaxAllowedDistance && lineDistance < minLineDistance) {
if (lineDistance < landmarkSize * HandledDistanceMultiplier && lineDistance < minLineDistance) {
minLineDistanceIndex = index
minLineDistance = lineDistance
}
Expand All @@ -29,6 +33,6 @@ class LineLayerClickHandler : LayerClickHandler<Line>() {
}

companion object {
private const val ClickedLandmarkMaxAllowedDistance = 3
private const val HandledDistanceMultiplier = 4f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ 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 {
override fun indexOfClickedLandmark(
landmarks: List<Keypoint>,
clickedPixelCoordinate: Vector2i,
landmarkSize: Float
): 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) {
if (keypointDistance < landmarkSize * HandledDistanceMultiplier &&
keypointDistance < minKeypointDistance) {
minKeypointDistanceIndex = index
minKeypointDistance = keypointDistance
}
Expand All @@ -23,6 +28,6 @@ class PointLayerClickHandler : LayerClickHandler<Keypoint>() {
}

companion object {
private const val ClickedLandmarkMaxAllowedDistance = 3
private const val HandledDistanceMultiplier = 1.5f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,12 @@ class LinesLayerRenderer(
val lineVector = lineFinishShaderPosition - lineStartShaderPosition
val normalVector = Vector2f(-lineVector.y, lineVector.x).normalize()
val linePoints = listOf(lineStartShaderPosition, lineFinishShaderPosition)
val selectionProgress = lineLandmark.layerState.getLandmarkHighlightingProgress(lineLandmark.uid)
val widthMultiplier = 1f + selectionProgress * (HighlightingWidthMultiplier - 1f)

linePoints.forEachIndexed { sideIndex, linePoint ->
val pointToVertexVector = Vector2f(normalVector) *
linesWidth / window.camera.zoom / DefaultLocalVerticesPositionsDivider
val pointToVertexVector = Vector2f(normalVector) * linesWidth * widthMultiplier /
window.camera.zoom / DefaultLocalVerticesPositionsDivider

val upperVertexPosition = linePoint + pointToVertexVector
val bottomVertexPosition = linePoint - pointToVertexVector
Expand Down Expand Up @@ -136,5 +138,6 @@ class LinesLayerRenderer(
private const val CommonColorUniformName = "uCommonColor"

private const val DefaultLocalVerticesPositionsDivider = 800f
private const val HighlightingWidthMultiplier = 2.5f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ class PointsLayerRenderer(
pointLandmark.coordinate.y.toFloat()
)
val pointShaderPosition = getFramePixelShaderPosition(pointsLayerIndex, pointLandmarkPosition)
val selectionProgress = pointLandmark.layerState.getLandmarkHighlightingProgress(pointLandmark.uid)
val radiusMultiplier = 1f + selectionProgress * (HighlightingRadiusMultiplier - 1f)

circleBoundsVerticesLocalPositions.forEach { vertexLocalPosition ->
val vertexPosition = pointShaderPosition + Vector2f(vertexLocalPosition) *
pointsRadius / window.camera.zoom / DefaultLocalVerticesPositionsDivider
pointsRadius * radiusMultiplier / window.camera.zoom / DefaultLocalVerticesPositionsDivider
batch.pushVector2f(vertexPosition)
batch.pushVector2f(vertexLocalPosition)
batch.pushFloat(pointLandmarkIndex.toFloat())
Expand Down Expand Up @@ -125,5 +127,6 @@ class PointsLayerRenderer(
)

private const val DefaultLocalVerticesPositionsDivider = 500f
private const val HighlightingRadiusMultiplier = 2f
}
}
31 changes: 22 additions & 9 deletions src/main/kotlin/solve/rendering/engine/utils/CalculationUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,33 @@ package solve.rendering.engine.utils

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

fun pointToSegmentDistance(
fun pointToSegmentDistanceSquared(
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)
)
val segmentLength = segmentStartPosition.distanceSquared(segmentEndPosition)
if (segmentLength == 0f)
return pointPosition.distanceSquared(segmentStartPosition)

var t = ((pointPosition.x - segmentStartPosition.x) * (segmentEndPosition.x - segmentStartPosition.x) +
(pointPosition.y - segmentStartPosition.y) * (segmentEndPosition.y - segmentStartPosition.y)) / segmentLength
t = max(0f, min(1f, t))
val a = Vector2f(segmentStartPosition.x + t * (segmentEndPosition.x - segmentStartPosition.x),
segmentStartPosition.y + t * (segmentEndPosition.y - segmentStartPosition.y))

return pointPosition.distanceSquared(a)
}

fun pointToSegmentDistance(
pointPosition: Vector2f,
segmentStartPosition: Vector2f,
segmentEndPosition: Vector2f
) : Float {
return sqrt(pointToSegmentDistanceSquared(pointPosition, segmentStartPosition, segmentEndPosition))
}
2 changes: 1 addition & 1 deletion src/main/kotlin/solve/scene/model/LayerState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,6 @@ class LayerState(val name: String) {
}

companion object {
private const val HighlightDurationMillis = 1000L
private const val HighlightDurationMillis = 300L
}
}

0 comments on commit 31a2b70

Please sign in to comment.