Update Kotlin and gradle plugins (#957)

This commit is contained in:
Uriel
2024-03-14 17:00:38 -03:00
committed by GitHub
parent d53de4a793
commit a8557474cb
63 changed files with 742 additions and 877 deletions

View File

@@ -1,3 +1,3 @@
plugins {
id("org.ajoberstar.grgit") version "5.2.0"
id("org.ajoberstar.grgit")
}

View File

@@ -13,7 +13,8 @@ android.useAndroidX=true
android.nonTransitiveRClass=true
org.gradle.unsafe.configuration-cache=false
kotlinVersion=1.9.0-RC
spotlessVersion=6.12.0
kotlinVersion=1.9.23
spotlessVersion=6.25.0
shadowJarVersion=8.1.1
buildconfigVersion=3.1.0
buildconfigVersion=5.3.5
grgitVersion=5.2.2

View File

@@ -84,36 +84,26 @@ dependencies {
implementation("com.github.mik3y:usb-serial-for-android:3.7.0")
}
/**
* The android block is where you configure all your Android-specific
* build options.
*/
// The android block is where you configure all your Android-specific build options.
extra.apply {
set("gitVersionCode", grgit.tag.list().size)
set("gitVersionName", grgit.describe(mapOf("tags" to true, "always" to true)))
}
android {
/**
* The app's namespace. Used primarily to access app resources.
*/
// The app's namespace. Used primarily to access app resources.
namespace = "dev.slimevr.android"
/**
* compileSdk specifies the Android API level Gradle should use to
* compile your app. This means your app can use the API features included in
* this API level and lower.
*/
/* compileSdk specifies the Android API level Gradle should use to
compile your app. This means your app can use the API features included in
this API level and lower. */
compileSdk = 33
/**
* The defaultConfig block encapsulates default settings and entries for all
* build variants and can override some attributes in main/AndroidManifest.xml
* dynamically from the build system. You can configure product flavors to override
* these values for different versions of your app.
*/
/* The defaultConfig block encapsulates default settings and entries for all
build variants and can override some attributes in main/AndroidManifest.xml
dynamically from the build system. You can configure product flavors to override
these values for different versions of your app. */
packaging {
resources.excludes.add("META-INF/*")
@@ -139,26 +129,22 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
/**
* The buildTypes block is where you can configure multiple build types.
* By default, the build system defines two build types: debug and release. The
* debug build type is not explicitly shown in the default build configuration,
* but it includes debugging tools and is signed with the debug key. The release
* build type applies ProGuard settings and is not signed by default.
*/
/* The buildTypes block is where you can configure multiple build types.
By default, the build system defines two build types: debug and release. The
debug build type is not explicitly shown in the default build configuration,
but it includes debugging tools and is signed with the debug key. The release
build type applies ProGuard settings and is not signed by default. */
buildTypes {
/**
* By default, Android Studio configures the release build type to enable code
* shrinking, using minifyEnabled, and specifies the default ProGuard rules file.
*/
/* By default, Android Studio configures the release build type to enable code
shrinking, using minifyEnabled, and specifies the default ProGuard rules file. */
getByName("release") {
isMinifyEnabled = true // Enables code shrinking for the release build type.
proguardFiles(
getDefaultProguardFile("proguard-android.txt"),
"proguard-rules.pro"
"proguard-rules.pro",
)
}
}

View File

@@ -49,7 +49,7 @@ fun main(activity: AppCompatActivity) {
try {
vrServer = VRServer(
configPath = File(activity.filesDir, "vrconfig.yml").absolutePath,
serialHandlerProvider = { _ -> AndroidSerialHandler(activity) }
serialHandlerProvider = { _ -> AndroidSerialHandler(activity) },
)
vrServer.start()
Keybinding(vrServer)

View File

@@ -64,9 +64,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
startWatchingNewDevices()
}
private fun getPorts(): List<UsbSerialDriver> {
return UsbSerialProber.getDefaultProber().findAllDrivers(manager)
}
private fun getPorts(): List<UsbSerialDriver> = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
private fun startWatchingNewDevices() {
if (watchingNewDevices) return
@@ -78,13 +76,13 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
} catch (t: Throwable) {
LogManager.severe(
"[SerialHandler] Error while watching for new devices, cancelling the \"getDevicesTimer\".",
t
t,
)
getDevicesTimer.cancel()
}
},
0,
3000
3000,
)
}
@@ -116,7 +114,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
if (newPort == null) {
LogManager.info(
"[SerialHandler] No serial ports found to connect to (${lastKnownPorts.size}) total ports"
"[SerialHandler] No serial ports found to connect to (${lastKnownPorts.size}) total ports",
)
return false
}
@@ -126,7 +124,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
if (newPort != port) {
LogManager.info(
"[SerialHandler] Closing current serial port " +
port.descriptivePortName
port.descriptivePortName,
)
closeSerial()
} else {
@@ -138,7 +136,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
LogManager.info(
"[SerialHandler] Trying to connect to new serial port " +
newPort.descriptivePortName
newPort.descriptivePortName,
)
if (!manager.hasPermission(newPort.port.device)) {
@@ -147,7 +145,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
activity,
0,
Intent(ACTION_USB_PERMISSION),
flags
flags,
)
if (requestingPermission != newPort.portLocation) {
println("Requesting permission for ${newPort.portLocation}")
@@ -155,7 +153,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
requestingPermission = newPort.portLocation
}
LogManager.warning(
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, invalid permissions"
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, invalid permissions",
)
return false
}
@@ -163,7 +161,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
val connection = manager.openDevice(newPort.port.device)
if (connection == null) {
LogManager.warning(
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, connection failed"
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, connection failed",
)
return false
@@ -215,7 +213,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
}
listeners.forEach { it.onSerialDisconnected() }
LogManager.info(
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay"
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay",
)
usbIoManager?.stop()
usbIoManager = null
@@ -223,7 +221,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
} catch (e: Exception) {
LogManager.warning(
"[SerialHandler] Error closing port ${currentPort?.descriptivePortName}",
e
e,
)
}
}

View File

@@ -27,30 +27,26 @@ configure<com.diffplug.gradle.spotless.SpotlessExtension> {
// indentWithSpaces(2) // YAML cannot contain tabs: https://yaml.org/faq.html
// }
// .editorconfig doesn't work so, manual override
// https://github.com/diffplug/spotless/issues/142
val editorConfig =
mapOf(
"indent_size" to 4,
"indent_style" to "tab",
// "max_line_length" to 88,
"max_line_length" to "off",
"ktlint_experimental" to "enabled",
"ktlint_standard_condition-wrapping" to "disabled",
"ktlint_standard_property-naming" to "disabled",
"ij_kotlin_packages_to_use_import_on_demand" to
"java.util.*,kotlin.math.*,dev.slimevr.autobone.errors.*,io.github.axisangles.ktmath.*,kotlinx.atomicfu.*",
"ij_kotlin_allow_trailing_comma" to true
"ij_kotlin_allow_trailing_comma" to true,
)
val ktlintVersion = "0.47.1"
val ktlintVersion = "1.2.1"
kotlinGradle {
target("**/*.gradle.kts") // default target for kotlinGradle
ktlint(ktlintVersion)
.setUseExperimental(true)
.editorConfigOverride(editorConfig)
}
kotlin {
target("**/*.kt")
targetExclude("**/build/**/**.kt")
targetExclude("**/build/**/**.kt", "bin/")
ktlint(ktlintVersion)
.setUseExperimental(true)
.editorConfigOverride(editorConfig)
}
java {

View File

@@ -65,7 +65,7 @@ dependencies {
implementation("com.illposed.osc:javaosc-core:0.8")
implementation("org.java-websocket:Java-WebSocket:1.+")
implementation("com.melloware:jintellitype:1.+")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
implementation("it.unimi.dsi:fastutil:8.5.12")
testImplementation(kotlin("test"))

View File

@@ -117,7 +117,7 @@ class VRServer @JvmOverloads constructor(
LogManager.info("Starting the tracker server on port $trackerPort...")
trackersServer = TrackersUDPServer(
trackerPort,
"Sensors UDP server"
"Sensors UDP server",
) { tracker: Tracker -> registerTracker(tracker) }
// Start bridges for SteamVR and Feeder
@@ -143,13 +143,13 @@ class VRServer @JvmOverloads constructor(
humanPoseManager,
driverBridge,
configManager.vrConfig.vrcOSC,
computedTrackers
computedTrackers,
)
vMCHandler = VMCHandler(
this,
humanPoseManager,
configManager.vrConfig.vmc,
computedTrackers
computedTrackers,
)
// Initialize OSC router
@@ -279,7 +279,7 @@ class VRServer @JvmOverloads constructor(
fun updateSkeletonModel() {
queueTask { humanPoseManager.updateSkeletonModelFromServer() }
vrcOSCHandler.setHeadTracker(
TrackerUtils.getTrackerForSkeleton(trackers, TrackerPosition.HEAD)
TrackerUtils.getTrackerForSkeleton(trackers, TrackerPosition.HEAD),
)
}
@@ -398,9 +398,7 @@ class VRServer @JvmOverloads constructor(
get() = ::instance.isInitialized
@JvmStatic
fun getNextLocalTrackerId(): Int {
return nextLocalTrackerId.incrementAndGet()
}
fun getNextLocalTrackerId(): Int = nextLocalTrackerId.incrementAndGet()
@JvmStatic
val currentLocalTrackerId: Int

View File

@@ -25,7 +25,7 @@ import java.util.function.Function
class AutoBone(server: VRServer) {
// This is filled by loadConfigValues()
val offsets = EnumMap<SkeletonConfigOffsets, Float>(
SkeletonConfigOffsets::class.java
SkeletonConfigOffsets::class.java,
)
val adjustOffsets = FastList(
arrayOf(
@@ -39,8 +39,8 @@ class AutoBone(server: VRServer) {
// best still, but it is somewhat functional
SkeletonConfigOffsets.HIPS_WIDTH,
SkeletonConfigOffsets.UPPER_LEG,
SkeletonConfigOffsets.LOWER_LEG
)
SkeletonConfigOffsets.LOWER_LEG,
),
)
var estimatedHeight: Float = 1f
@@ -109,6 +109,7 @@ class AutoBone(server: VRServer) {
SkeletonConfigOffsets.LOWER_LEG, SkeletonConfigOffsets.FOOT_LENGTH,
->
if (rightSide) configOffset.affectedOffsets[1] else configOffset.affectedOffsets[0]
else -> configOffset.affectedOffsets[0]
}
return skeleton.getBone(boneType).getGlobalRotation().toRotationVector()
@@ -160,7 +161,7 @@ class AutoBone(server: VRServer) {
targetHeight = humanPoseManager.userHeightFromConfig
LogManager
.warning(
"[AutoBone] Target height loaded from skeleton (Make sure you reset before running!): $targetHeight"
"[AutoBone] Target height loaded from skeleton (Make sure you reset before running!): $targetHeight",
)
} else {
// Otherwise if there is no skeleton available, attempt to get the
@@ -169,7 +170,7 @@ class AutoBone(server: VRServer) {
if (hmdHeight <= 0.4f) {
LogManager
.warning(
"[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): $hmdHeight"
"[AutoBone] Max headset height detected (Value seems too low, did you not stand up straight while measuring?): $hmdHeight",
)
} else {
LogManager.info("[AutoBone] Max headset height detected: $hmdHeight")
@@ -217,7 +218,7 @@ class AutoBone(server: VRServer) {
targetFullHeight = targetFullHeight,
frames = frames,
epochCallback = epochCallback,
serverConfig = server.configManager
serverConfig = server.configManager,
)
// Initialize the frame order randomizer with a repeatable seed
@@ -252,7 +253,7 @@ class AutoBone(server: VRServer) {
trainingStep.setCursors(
i,
j,
updatePlayerCursors = true
updatePlayerCursors = true,
)
frameStats.addValue(getErrorDeriv(trainingStep))
@@ -287,7 +288,7 @@ class AutoBone(server: VRServer) {
trainingStep.setCursors(
i,
j,
updatePlayerCursors = true
updatePlayerCursors = true,
)
frameStats.addValue(getErrorDeriv(trainingStep))
@@ -313,14 +314,14 @@ class AutoBone(server: VRServer) {
LogManager
.info(
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Final height: $estimatedHeight"
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Final height: $estimatedHeight",
)
return AutoBoneResults(
estimatedHeight,
trainingStep.targetHmdHeight,
trainingStep.errorStats,
offsets
offsets,
)
}
@@ -367,13 +368,13 @@ class AutoBone(server: VRServer) {
.setCursors(
randomFrameIndices[frameCursor],
randomFrameIndices[frameCursor2],
updatePlayerCursors = true
updatePlayerCursors = true,
)
} else {
trainingStep.setCursors(
frameCursor,
frameCursor2,
updatePlayerCursors = true
updatePlayerCursors = true,
)
}
@@ -390,11 +391,11 @@ class AutoBone(server: VRServer) {
if (epoch <= 0 || epoch >= config.numEpochs - 1 || (epoch + 1) % config.printEveryNumEpochs == 0) {
LogManager
.info(
"[AutoBone] Epoch: ${epoch + 1}, Mean error: ${errorStats.mean} (SD ${errorStats.standardDeviation}), Adjust rate: ${trainingStep.curAdjustRate}"
"[AutoBone] Epoch: ${epoch + 1}, Mean error: ${errorStats.mean} (SD ${errorStats.standardDeviation}), Adjust rate: ${trainingStep.curAdjustRate}",
)
LogManager
.info(
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Estimated height: $estimatedHeight"
"[AutoBone] Target height: ${trainingStep.targetHmdHeight}, Estimated height: $estimatedHeight",
)
}
@@ -459,7 +460,7 @@ class AutoBone(server: VRServer) {
// Extinguish
LogManager
.warning(
"[AutoBone] Error value is invalid, resetting variables to recover"
"[AutoBone] Error value is invalid, resetting variables to recover",
)
// Reset adjustable config values
loadConfigValues()
@@ -502,14 +503,14 @@ class AutoBone(server: VRServer) {
skeleton2,
entry.key,
false,
slideLeft
slideLeft,
)
val rightDotProduct = getDotProductDiff(
skeleton1,
skeleton2,
entry.key,
true,
slideRight
slideRight,
)
// Calculate the total effect of the bone based on change in rotation
@@ -675,18 +676,18 @@ class AutoBone(server: VRServer) {
if (PoseFrameIO.tryWriteToFile(recordingFile, frames)) {
LogManager
.info(
"[AutoBone] Done exporting! Recording can be found at \"${recordingFile.path}\"."
"[AutoBone] Done exporting! Recording can be found at \"${recordingFile.path}\".",
)
} else {
LogManager
.severe(
"[AutoBone] Failed to export the recording to \"${recordingFile.path}\"."
"[AutoBone] Failed to export the recording to \"${recordingFile.path}\".",
)
}
} else {
LogManager
.severe(
"[AutoBone] Failed to create the recording directory \"${saveDir.path}\"."
"[AutoBone] Failed to create the recording directory \"${saveDir.path}\".",
)
}
}
@@ -713,7 +714,7 @@ class AutoBone(server: VRServer) {
LogManager
.info(
"[AutoBone] Detected recording at \"${file.path}\", loading frames..."
"[AutoBone] Detected recording at \"${file.path}\", loading frames...",
)
val frames = PoseFrameIO.tryReadFromFile(file)
if (frames == null) {
@@ -731,9 +732,7 @@ class AutoBone(server: VRServer) {
val epochError: StatsCalculator,
val configValues: EnumMap<SkeletonConfigOffsets, Float>,
) {
override fun toString(): String {
return "Epoch: $epoch, Epoch error: $epochError"
}
override fun toString(): String = "Epoch: $epoch, Epoch error: $epochError"
}
inner class AutoBoneResults(
@@ -753,22 +752,18 @@ class AutoBone(server: VRServer) {
// FIXME: Won't work on iOS and Android, maybe fix resolveConfigDirectory more than this
val saveDir = File(
OperatingSystem.resolveConfigDirectory(SLIMEVR_IDENTIFIER)?.resolve(
AUTOBONE_FOLDER
)?.toString() ?: AUTOBONE_FOLDER
AUTOBONE_FOLDER,
)?.toString() ?: AUTOBONE_FOLDER,
)
val loadDir = File(
OperatingSystem.resolveConfigDirectory(SLIMEVR_IDENTIFIER)?.resolve(
LOADAUTOBONE_FOLDER
)?.toString() ?: LOADAUTOBONE_FOLDER
LOADAUTOBONE_FOLDER,
)?.toString() ?: LOADAUTOBONE_FOLDER,
)
// Mean square error function
private fun errorFunc(errorDeriv: Float): Float {
return 0.5f * (errorDeriv * errorDeriv)
}
private fun errorFunc(errorDeriv: Float): Float = 0.5f * (errorDeriv * errorDeriv)
private fun decayFunc(initialAdjustRate: Float, adjustRateDecay: Float, epoch: Int): Float {
return if (epoch >= 0) initialAdjustRate / (1 + (adjustRateDecay * epoch)) else 0.0f
}
private fun decayFunc(initialAdjustRate: Float, adjustRateDecay: Float, epoch: Int): Float = if (epoch >= 0) initialAdjustRate / (1 + (adjustRateDecay * epoch)) else 0.0f
}
}

View File

@@ -59,24 +59,25 @@ class AutoBoneHandler(private val server: VRServer) {
total,
eta,
completed,
success
success,
)
}
}
@Throws(AutoBoneException::class)
private fun processFrames(frames: PoseFrames): AutoBoneResults {
return autoBone
.processFrames(frames) { epoch ->
listeners.forEach { listener -> listener.onAutoBoneEpoch(epoch) }
}
}
private fun processFrames(frames: PoseFrames): AutoBoneResults = autoBone
.processFrames(frames) { epoch ->
listeners.forEach { listener -> listener.onAutoBoneEpoch(epoch) }
}
fun startProcessByType(processType: AutoBoneProcessType?): Boolean {
when (processType) {
AutoBoneProcessType.RECORD -> startRecording()
AutoBoneProcessType.SAVE -> saveRecording()
AutoBoneProcessType.PROCESS -> processRecording()
else -> {
return false
}
@@ -108,13 +109,13 @@ class AutoBoneHandler(private val server: VRServer) {
val framesFuture = poseRecorder
.startFrameRecording(
sampleCount,
sampleRate
sampleRate,
) { progress: RecordingProgress ->
announceProcessStatus(
AutoBoneProcessType.RECORD,
current = progress.frame.toLong(),
total = progress.totalFrames.toLong(),
eta = totalTime - (progress.frame * totalTime / progress.totalFrames)
eta = totalTime - (progress.frame * totalTime / progress.totalFrames),
)
}
val frames = framesFuture.get()
@@ -126,7 +127,7 @@ class AutoBoneHandler(private val server: VRServer) {
if (autoBone.globalConfig.saveRecordings) {
announceProcessStatus(
AutoBoneProcessType.RECORD,
"Saving recording (from config option)..."
"Saving recording (from config option)...",
)
autoBone.saveRecording(frames)
}
@@ -135,14 +136,14 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.RECORD,
"Done recording!",
completed = true,
success = true
success = true,
)
} else {
announceProcessStatus(
AutoBoneProcessType.RECORD,
"The server is not ready to record",
completed = true,
success = false
success = false,
)
LogManager.severe("[AutoBone] Unable to record...")
return
@@ -152,7 +153,7 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.RECORD,
String.format("Recording failed: %s", e.message),
completed = true,
success = false
success = false,
)
LogManager.severe("[AutoBone] Failed recording!", e)
} finally {
@@ -196,14 +197,14 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.SAVE,
"Recording saved!",
completed = true,
success = true
success = true,
)
} else {
announceProcessStatus(
AutoBoneProcessType.SAVE,
"No recording found",
completed = true,
success = false
success = false,
)
LogManager.severe("[AutoBone] Unable to save, no recording was done...")
return
@@ -213,7 +214,7 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.SAVE,
String.format("Failed to save recording: %s", e.message),
completed = true,
success = false
success = false,
)
LogManager.severe("[AutoBone] Failed to save recording!", e)
} finally {
@@ -250,11 +251,11 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.PROCESS,
"No recordings found...",
completed = true,
success = false
success = false,
)
LogManager
.severe(
"[AutoBone] No recordings found in \"${loadDir.path}\" and no recording was done..."
"[AutoBone] No recordings found in \"${loadDir.path}\" and no recording was done...",
)
return
}
@@ -263,7 +264,7 @@ class AutoBoneHandler(private val server: VRServer) {
LogManager.info("[AutoBone] Processing frames...")
val errorStats = StatsCalculator()
val offsetStats = EnumMap<SkeletonConfigOffsets, StatsCalculator>(
SkeletonConfigOffsets::class.java
SkeletonConfigOffsets::class.java,
)
val skeletonConfigManagerBuffer = SkeletonConfigManager(false)
for ((key, value) in frameRecordings) {
@@ -314,8 +315,8 @@ class AutoBoneHandler(private val server: VRServer) {
LogManager
.info(
"[AutoBone] Average height error: ${
StringUtils.prettyNumber(errorStats.mean, 6)
} (SD ${StringUtils.prettyNumber(errorStats.standardDeviation, 6)})"
StringUtils.prettyNumber(errorStats.mean, 6)
} (SD ${StringUtils.prettyNumber(errorStats.standardDeviation, 6)})",
)
// #endregion
listeners.forEach { listener: AutoBoneListener -> listener.onAutoBoneEnd(autoBone.offsets) }
@@ -323,14 +324,14 @@ class AutoBoneHandler(private val server: VRServer) {
AutoBoneProcessType.PROCESS,
"Done processing!",
completed = true,
success = true
success = true,
)
} catch (e: Exception) {
announceProcessStatus(
AutoBoneProcessType.PROCESS,
String.format("Processing failed: %s", e.message),
completed = true,
success = false
success = false,
)
LogManager.severe("[AutoBone] Failed adjustment!", e)
} finally {
@@ -394,12 +395,12 @@ class AutoBoneHandler(private val server: VRServer) {
LogManager.info(
"[AutoBone] Ratios: [{Neck-Torso: ${
StringUtils.prettyNumber(neckTorso)}}, {Chest-Torso: ${
StringUtils.prettyNumber(chestTorso)}}, {Torso-Waist: ${
StringUtils.prettyNumber(torsoWaist)}}, {Leg-Torso: ${
StringUtils.prettyNumber(legTorso)}}, {Leg-Body: ${
StringUtils.prettyNumber(legBody)}}, {Knee-Leg: ${
StringUtils.prettyNumber(kneeLeg)}}]"
StringUtils.prettyNumber(neckTorso)}}, {Chest-Torso: ${
StringUtils.prettyNumber(chestTorso)}}, {Torso-Waist: ${
StringUtils.prettyNumber(torsoWaist)}}, {Leg-Torso: ${
StringUtils.prettyNumber(legTorso)}}, {Leg-Body: ${
StringUtils.prettyNumber(legBody)}}, {Knee-Leg: ${
StringUtils.prettyNumber(kneeLeg)}}]",
)
}

View File

@@ -1,7 +1,11 @@
package dev.slimevr.autobone
enum class AutoBoneProcessType(val id: Int) {
NONE(0), RECORD(1), SAVE(2), PROCESS(3);
NONE(0),
RECORD(1),
SAVE(2),
PROCESS(3),
;
companion object {
fun getById(id: Int): AutoBoneProcessType? = byId[id]

View File

@@ -27,9 +27,17 @@ class StatsCalculator {
}
val variance: Float
get() = if (count < 1) { Float.NaN } else { m2 / count }
get() = if (count < 1) {
Float.NaN
} else {
m2 / count
}
val sampleVariance: Float
get() = if (count < 2) { Float.NaN } else { m2 / (count - 1) }
get() = if (count < 2) {
Float.NaN
} else {
m2 / (count - 1)
}
val standardDeviation: Float
get() = FastMath.sqrt(variance)
}

View File

@@ -10,13 +10,11 @@ import dev.slimevr.tracking.processor.config.SkeletonConfigOffsets
// The distance from average human proportions
class BodyProportionError : IAutoBoneError {
@Throws(AutoBoneException::class)
override fun getStepError(trainingStep: AutoBoneStep): Float {
return getBodyProportionError(
trainingStep.skeleton1,
// Skeletons are now normalized to reduce bias, so height is always 1
1f
)
}
override fun getStepError(trainingStep: AutoBoneStep): Float = getBodyProportionError(
trainingStep.skeleton1,
// Skeletons are now normalized to reduce bias, so height is always 1
1f,
)
fun getBodyProportionError(humanPoseManager: HumanPoseManager, fullHeight: Float): Float {
var sum = 0f
@@ -54,7 +52,7 @@ class BodyProportionError : IAutoBoneError {
RangeProportionLimiter(
0.059f,
SkeletonConfigOffsets.HEAD,
0.01f
0.01f,
),
// Neck
// Expected: 0.052
@@ -62,35 +60,35 @@ class BodyProportionError : IAutoBoneError {
RangeProportionLimiter(
0.054f,
SkeletonConfigOffsets.NECK,
0.0015f
0.0015f,
),
// Upper Chest
// Experimental: 0.0945
RangeProportionLimiter(
0.0945f,
SkeletonConfigOffsets.UPPER_CHEST,
0.01f
0.01f,
),
// Chest
// Experimental: 0.0945
RangeProportionLimiter(
0.0945f,
SkeletonConfigOffsets.CHEST,
0.01f
0.01f,
),
// Waist
// Experimental: 0.118
RangeProportionLimiter(
0.118f,
SkeletonConfigOffsets.WAIST,
0.05f
0.05f,
),
// Hip
// Experimental: 0.0237
RangeProportionLimiter(
0.0237f,
SkeletonConfigOffsets.HIP,
0.01f
0.01f,
),
// Hip Width
// Expected: 0.191
@@ -98,14 +96,14 @@ class BodyProportionError : IAutoBoneError {
RangeProportionLimiter(
0.184f,
SkeletonConfigOffsets.HIPS_WIDTH,
0.04f
0.04f,
),
// Upper Leg
// Expected: 0.245
RangeProportionLimiter(
0.245f,
SkeletonConfigOffsets.UPPER_LEG,
0.015f
0.015f,
),
// Lower Leg
// Expected: 0.246 (0.285 including below ankle, could use a separate
@@ -113,8 +111,8 @@ class BodyProportionError : IAutoBoneError {
RangeProportionLimiter(
0.285f,
SkeletonConfigOffsets.LOWER_LEG,
0.02f
)
0.02f,
),
)
@JvmStatic

View File

@@ -9,12 +9,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
// The offset between the height both feet at one instant and over time
class FootHeightOffsetError : IAutoBoneError {
@Throws(AutoBoneException::class)
override fun getStepError(trainingStep: AutoBoneStep): Float {
return getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton
)
}
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton,
)
companion object {
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {

View File

@@ -6,14 +6,10 @@ import dev.slimevr.autobone.AutoBoneStep
// The difference from the current height to the target height
class HeightError : IAutoBoneError {
@Throws(AutoBoneException::class)
override fun getStepError(trainingStep: AutoBoneStep): Float {
return getHeightError(
trainingStep.currentHmdHeight,
trainingStep.targetHmdHeight
)
}
override fun getStepError(trainingStep: AutoBoneStep): Float = getHeightError(
trainingStep.currentHmdHeight,
trainingStep.targetHmdHeight,
)
fun getHeightError(currentHeight: Float, targetHeight: Float): Float {
return FastMath.abs(targetHeight - currentHeight)
}
fun getHeightError(currentHeight: Float, targetHeight: Float): Float = FastMath.abs(targetHeight - currentHeight)
}

View File

@@ -9,12 +9,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
// The change in distance between both of the ankles over time
class OffsetSlideError : IAutoBoneError {
@Throws(AutoBoneException::class)
override fun getStepError(trainingStep: AutoBoneStep): Float {
return getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton
)
}
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton,
)
companion object {
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {

View File

@@ -14,12 +14,12 @@ class PositionError : IAutoBoneError {
getPositionError(
trackers,
trainingStep.cursor1,
trainingStep.skeleton1.skeleton
trainingStep.skeleton1.skeleton,
) +
getPositionError(
trackers,
trainingStep.cursor2,
trainingStep.skeleton2.skeleton
trainingStep.skeleton2.skeleton,
)
) /
2f

View File

@@ -15,7 +15,7 @@ class PositionOffsetError : IAutoBoneError {
trainingStep.cursor1,
trainingStep.cursor2,
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton
trainingStep.skeleton2.skeleton,
)
}

View File

@@ -8,12 +8,10 @@ import dev.slimevr.tracking.trackers.TrackerRole
// The change in position of the ankle over time
class SlideError : IAutoBoneError {
@Throws(AutoBoneException::class)
override fun getStepError(trainingStep: AutoBoneStep): Float {
return getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton
)
}
override fun getStepError(trainingStep: AutoBoneStep): Float = getSlideError(
trainingStep.skeleton1.skeleton,
trainingStep.skeleton2.skeleton,
)
companion object {
fun getSlideError(skeleton1: HumanSkeleton, skeleton2: HumanSkeleton): Float {
@@ -32,7 +30,7 @@ class SlideError : IAutoBoneError {
// Calculate and average between both feet
return getSlideError(
skeleton1.getComputedTracker(trackerRole),
skeleton2.getComputedTracker(trackerRole)
skeleton2.getComputedTracker(trackerRole),
)
}

View File

@@ -14,9 +14,7 @@ class VRCOSCConfig : OSCConfig() {
@JsonSerialize(keyUsing = StdKeySerializers.StringKeySerializer::class)
var trackers: MutableMap<String, Boolean> = HashMap()
fun getOSCTrackerRole(role: TrackerRole, def: Boolean): Boolean {
return trackers.getOrDefault(role.name.lowercase(Locale.getDefault()), def)
}
fun getOSCTrackerRole(role: TrackerRole, def: Boolean): Boolean = trackers.getOrDefault(role.name.lowercase(Locale.getDefault()), def)
fun setOSCTrackerRole(role: TrackerRole, `val`: Boolean) {
trackers[role.name.lowercase(Locale.getDefault())] = `val`

View File

@@ -29,8 +29,6 @@ enum class TrackerFilters(val id: Int, val configKey: String) {
}
@JvmStatic
fun getByConfigkey(configKey: String?): TrackerFilters? {
return if (configKey == null) null else byConfigkey[configKey.lowercase(Locale.getDefault())]
}
fun getByConfigkey(configKey: String?): TrackerFilters? = if (configKey == null) null else byConfigkey[configKey.lowercase(Locale.getDefault())]
}
}

View File

@@ -170,33 +170,31 @@ class UnityArmature(localRot: Boolean) {
}
}
fun getHeadNodeOfBone(unityBone: UnityBone?): TransformNode? {
return if (unityBone == null) {
null
} else {
when (unityBone) {
UnityBone.HEAD -> neckTailNode
UnityBone.NECK -> neckHeadNode
UnityBone.UPPER_CHEST -> chestNode
UnityBone.CHEST -> spineTailNode
UnityBone.SPINE -> spineHeadNode
UnityBone.HIPS -> hipsNode
UnityBone.LEFT_UPPER_LEG -> leftHipNode
UnityBone.RIGHT_UPPER_LEG -> rightHipNode
UnityBone.LEFT_LOWER_LEG -> leftKneeNode
UnityBone.RIGHT_LOWER_LEG -> rightKneeNode
UnityBone.LEFT_FOOT -> leftAnkleNode
UnityBone.RIGHT_FOOT -> rightAnkleNode
UnityBone.LEFT_SHOULDER -> leftShoulderHeadNode
UnityBone.RIGHT_SHOULDER -> rightShoulderHeadNode
UnityBone.LEFT_UPPER_ARM -> leftShoulderTailNode
UnityBone.RIGHT_UPPER_ARM -> rightShoulderTailNode
UnityBone.LEFT_LOWER_ARM -> leftElbowNode
UnityBone.RIGHT_LOWER_ARM -> rightElbowNode
UnityBone.LEFT_HAND -> leftWristNode
UnityBone.RIGHT_HAND -> rightWristNode
else -> null
}
fun getHeadNodeOfBone(unityBone: UnityBone?): TransformNode? = if (unityBone == null) {
null
} else {
when (unityBone) {
UnityBone.HEAD -> neckTailNode
UnityBone.NECK -> neckHeadNode
UnityBone.UPPER_CHEST -> chestNode
UnityBone.CHEST -> spineTailNode
UnityBone.SPINE -> spineHeadNode
UnityBone.HIPS -> hipsNode
UnityBone.LEFT_UPPER_LEG -> leftHipNode
UnityBone.RIGHT_UPPER_LEG -> rightHipNode
UnityBone.LEFT_LOWER_LEG -> leftKneeNode
UnityBone.RIGHT_LOWER_LEG -> rightKneeNode
UnityBone.LEFT_FOOT -> leftAnkleNode
UnityBone.RIGHT_FOOT -> rightAnkleNode
UnityBone.LEFT_SHOULDER -> leftShoulderHeadNode
UnityBone.RIGHT_SHOULDER -> rightShoulderHeadNode
UnityBone.LEFT_UPPER_ARM -> leftShoulderTailNode
UnityBone.RIGHT_UPPER_ARM -> rightShoulderTailNode
UnityBone.LEFT_LOWER_ARM -> leftElbowNode
UnityBone.RIGHT_LOWER_ARM -> rightElbowNode
UnityBone.LEFT_HAND -> leftWristNode
UnityBone.RIGHT_HAND -> rightWristNode
else -> null
}
}

View File

@@ -75,7 +75,7 @@ class VRCOSCHandler(
trackersEnabled[i] = config
.getOSCTrackerRole(
computedTrackers[i].trackerPosition!!.trackerRole!!,
false
false,
)
} else {
trackersEnabled[i] = false
@@ -110,7 +110,7 @@ class VRCOSCHandler(
"[VRCOSCHandler] Error listening to the port " +
config.portIn +
": " +
e
e,
)
}
@@ -118,13 +118,13 @@ class VRCOSCHandler(
if (oscReceiver != null) {
val listener = OSCMessageListener { event: OSCMessageEvent -> handleReceivedMessage(event) }
val vrcSelector: MessageSelector = OSCPatternAddressMessageSelector(
"/avatar/parameters/Upright"
"/avatar/parameters/Upright",
)
val trackersPositionSelector: MessageSelector = OSCPatternAddressMessageSelector(
"/tracking/trackers/*/position"
"/tracking/trackers/*/position",
)
val trackersRotationSelector: MessageSelector = OSCPatternAddressMessageSelector(
"/tracking/trackers/*/rotation"
"/tracking/trackers/*/rotation",
)
oscReceiver!!.dispatcher.addListener(vrcSelector, listener)
oscReceiver!!.dispatcher.addListener(trackersPositionSelector, listener)
@@ -140,13 +140,13 @@ class VRCOSCHandler(
val address = InetAddress.getByName(config.address)
val port = config.portOut
oscSender = OSCPortOut(InetSocketAddress(address, port))
if (lastPortOut != port && lastAddress !== address || !wasConnected) {
if ((lastPortOut != port && lastAddress !== address) || !wasConnected) {
LogManager
.info(
"[VRCOSCHandler] Sending to port " +
port +
" at address " +
address.toString()
address.toString(),
)
}
lastPortOut = port
@@ -160,7 +160,7 @@ class VRCOSCHandler(
" at the address " +
config.address +
": " +
e
e,
)
}
}
@@ -194,7 +194,7 @@ class VRCOSCHandler(
hasPosition = true,
userEditable = false,
isComputed = true,
usesTimeout = true
usesTimeout = true,
)
vrcDevice.trackers[0] = vrcHmd!!
server.registerTracker(vrcHmd!!)
@@ -211,7 +211,7 @@ class VRCOSCHandler(
event
.message
.arguments[0] as Float * humanPoseManager.userHeightFromConfig,
0f
0f,
)
vrcHmd!!.dataTick()
}
@@ -233,7 +233,7 @@ class VRCOSCHandler(
receivingPositionOffset = Vector3(
event.message.arguments[0] as Float,
event.message.arguments[1] as Float,
-(event.message.arguments[2] as Float)
-(event.message.arguments[2] as Float),
)
if (slimeHead != null && slimeHead.hasPosition) {
@@ -276,7 +276,7 @@ class VRCOSCHandler(
userEditable = true,
isComputed = true,
needsReset = true,
usesTimeout = true
usesTimeout = true,
)
oscTrackersDevice!!.trackers[trackerId] = tracker
server.registerTracker(tracker)
@@ -290,8 +290,8 @@ class VRCOSCHandler(
Vector3(
event.message.arguments[0] as Float,
event.message.arguments[1] as Float,
-(event.message.arguments[2] as Float)
) - receivingPositionOffset
-(event.message.arguments[2] as Float),
) - receivingPositionOffset,
) + postReceivingPositionOffset
} else {
val (w, x, y, z) = EulerAngles(EulerOrder.YXZ, event.message.arguments[0] as Float * FastMath.DEG_TO_RAD, event.message.arguments[1] as Float * FastMath.DEG_TO_RAD, event.message.arguments[2] as Float * FastMath.DEG_TO_RAD).toQuaternion()
@@ -334,8 +334,8 @@ class VRCOSCHandler(
bundle.addPacket(
OSCMessage(
"/tracking/trackers/${getVRCOSCTrackersId(computedTrackers[i].trackerPosition)}/position",
oscArgs.clone()
)
oscArgs.clone(),
),
)
// Send regular trackers' rotations
@@ -351,7 +351,7 @@ class VRCOSCHandler(
w,
-x1,
-y1,
z1
z1,
).toEulerAngles(EulerOrder.YXZ)
oscArgs.clear()
oscArgs.add(x2 * FastMath.RAD_TO_DEG)
@@ -360,8 +360,8 @@ class VRCOSCHandler(
bundle.addPacket(
OSCMessage(
"/tracking/trackers/${getVRCOSCTrackersId(computedTrackers[i].trackerPosition)}/rotation",
oscArgs.clone()
)
oscArgs.clone(),
),
)
}
if (computedTrackers[i].trackerPosition === TrackerPosition.HEAD) {
@@ -374,8 +374,8 @@ class VRCOSCHandler(
bundle.addPacket(
OSCMessage(
"/tracking/trackers/head/position",
oscArgs.clone()
)
oscArgs.clone(),
),
)
}
}
@@ -431,7 +431,7 @@ class VRCOSCHandler(
oscArgs.add(0f)
oscMessage = OSCMessage(
"/tracking/trackers/head/rotation",
oscArgs
oscArgs,
)
try {
oscSender!!.send(oscMessage)
@@ -445,23 +445,13 @@ class VRCOSCHandler(
}
}
override fun getOscSender(): OSCPortOut {
return oscSender!!
}
override fun getOscSender(): OSCPortOut = oscSender!!
override fun getPortOut(): Int {
return lastPortOut
}
override fun getPortOut(): Int = lastPortOut
override fun getAddress(): InetAddress {
return lastAddress!!
}
override fun getAddress(): InetAddress = lastAddress!!
override fun getOscReceiver(): OSCPortIn {
return oscReceiver!!
}
override fun getOscReceiver(): OSCPortIn = oscReceiver!!
override fun getPortIn(): Int {
return lastPortIn
}
override fun getPortIn(): Int = lastPortIn
}

View File

@@ -85,7 +85,7 @@ object PoseFrameIO {
fun writeToFile(file: File, frames: PoseFrames) {
DataOutputStream(
BufferedOutputStream(FileOutputStream(file))
BufferedOutputStream(FileOutputStream(file)),
).use { outputStream -> writeFrames(outputStream, frames) }
}
@@ -100,13 +100,11 @@ object PoseFrameIO {
}
@Throws(IOException::class)
private fun readVector3f(inputStream: DataInputStream): Vector3 {
return Vector3(
inputStream.readFloat(),
inputStream.readFloat(),
inputStream.readFloat()
)
}
private fun readVector3f(inputStream: DataInputStream): Vector3 = Vector3(
inputStream.readFloat(),
inputStream.readFloat(),
inputStream.readFloat(),
)
@Throws(IOException::class)
private fun readQuaternion(inputStream: DataInputStream): Quaternion {
@@ -125,7 +123,7 @@ object PoseFrameIO {
val name = inputStream.readUTF()
val trackerFrameCount = inputStream.readInt()
val trackerFrames = FastList<TrackerFrame?>(
trackerFrameCount
trackerFrameCount,
)
for (j in 0 until trackerFrameCount) {
val dataFlags = inputStream.readInt()
@@ -159,8 +157,8 @@ object PoseFrameIO {
rotation,
position,
acceleration,
rawRotation
)
rawRotation,
),
)
}
trackers.add(TrackerFrames(name, trackerFrames))
@@ -177,16 +175,14 @@ object PoseFrameIO {
}
}
fun readFromFile(file: File): PoseFrames {
return readFrames(
DataInputStream(BufferedInputStream(FileInputStream(file)))
)
}
fun readFromFile(file: File): PoseFrames = readFrames(
DataInputStream(BufferedInputStream(FileInputStream(file))),
)
fun tryReadFromFile(file: File): PoseFrames? {
return try {
return readFrames(
DataInputStream(BufferedInputStream(FileInputStream(file)))
DataInputStream(BufferedInputStream(FileInputStream(file))),
)
} catch (e: Exception) {
LogManager.severe("Error reading frames from file", e)

View File

@@ -34,8 +34,9 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
* index [index].
*/
fun getTrackerForPosition(position: TrackerPosition, index: Int = 0): TrackerFrames? {
for (tracker in frameHolders)
for (tracker in frameHolders) {
if (tracker.tryGetFrame(index)?.trackerPosition == position) return tracker
}
return null
}
@@ -51,7 +52,7 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
get() {
return getMaxHeight(
getTrackerForPosition(TrackerPosition.HEAD)
?: return 0f
?: return 0f,
)
}
@@ -74,13 +75,13 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
}
// endregion
/**
* @return The maximum number of [TrackerFrame]s contained within each
* [TrackerFrames] in the internal [TrackerFrames] list.
* @see [TrackerFrames.frames]
* @see [List.size]
*/
val maxFrameCount: Int
/**
* @return The maximum number of [TrackerFrame]s contained within each
* [TrackerFrames] in the internal [TrackerFrames] list.
* @see [TrackerFrames.frames]
* @see [List.size]
*/
get() {
return frameHolders.maxOfOrNull { tracker -> tracker.frames.size } ?: 0
}
@@ -137,18 +138,14 @@ class PoseFrames : Iterable<Array<TrackerFrame?>> {
return trackerFrames
}
override fun iterator(): Iterator<Array<TrackerFrame?>> {
return PoseFrameIterator(this)
}
override fun iterator(): Iterator<Array<TrackerFrame?>> = PoseFrameIterator(this)
inner class PoseFrameIterator(private val poseFrame: PoseFrames) : Iterator<Array<TrackerFrame?>> {
private val trackerFrameBuffer: Array<TrackerFrame?> = arrayOfNulls(poseFrame.frameHolders.size)
private val maxCursor = poseFrame.maxFrameCount
private var cursor = 0
override fun hasNext(): Boolean {
return frameHolders.isNotEmpty() && cursor < maxCursor
}
override fun hasNext(): Boolean = frameHolders.isNotEmpty() && cursor < maxCursor
override fun next(): Array<TrackerFrame?> {
if (!hasNext()) {

View File

@@ -113,7 +113,7 @@ class PoseRecorder(private val server: VRServer) {
LogManager
.info(
"[PoseRecorder] Recording $numFrames samples at a $intervalMs ms frame interval"
"[PoseRecorder] Recording $numFrames samples at a $intervalMs ms frame interval",
)
currentFrameCallback = frameCallback
@@ -161,9 +161,7 @@ class PoseRecorder(private val server: VRServer) {
get() = numFrames > frameCursor
@Synchronized
fun hasRecording(): Boolean {
return currentRecording != null
}
fun hasRecording(): Boolean = currentRecording != null
@get:Synchronized
val framesAsync: Future<PoseFrames>?

View File

@@ -10,20 +10,20 @@ class TrackerFramesPlayer(vararg val frameHolders: TrackerFrames) {
val playerTrackers: Array<PlayerTracker> = frameHolders.map { trackerFrames ->
PlayerTracker(
trackerFrames,
trackerFrames.toTracker()
trackerFrames.toTracker(),
)
}.toTypedArray()
val trackers: Array<Tracker> =
playerTrackers.map { playerTracker -> playerTracker.tracker }.toTypedArray()
/**
* @return The maximum number of [TrackerFrame]s contained within each
* [TrackerFrames] in the internal [TrackerFrames] array.
* @see [TrackerFrames.frames]
* @see [List.size]
*/
val maxFrameCount: Int
/**
* @return The maximum number of [TrackerFrame]s contained within each
* [TrackerFrames] in the internal [TrackerFrames] array.
* @see [TrackerFrames.frames]
* @see [List.size]
*/
get() {
return frameHolders.maxOfOrNull { tracker -> tracker.frames.size } ?: 0
}

View File

@@ -40,62 +40,44 @@ data class TrackerFrame(
dataFlags = initDataFlags
}
fun hasData(flag: TrackerFrameData): Boolean {
return flag.check(dataFlags)
}
fun hasData(flag: TrackerFrameData): Boolean = flag.check(dataFlags)
// region Tracker Try Getters
fun tryGetTrackerPosition(): TrackerPosition? {
return if (hasData(TrackerFrameData.TRACKER_POSITION_ENUM) || hasData(TrackerFrameData.DESIGNATION_STRING)) {
trackerPosition
} else {
null
}
fun tryGetTrackerPosition(): TrackerPosition? = if (hasData(TrackerFrameData.TRACKER_POSITION_ENUM) || hasData(TrackerFrameData.DESIGNATION_STRING)) {
trackerPosition
} else {
null
}
fun tryGetRotation(): Quaternion? {
return if (hasData(TrackerFrameData.ROTATION)) {
rotation
} else {
null
}
fun tryGetRotation(): Quaternion? = if (hasData(TrackerFrameData.ROTATION)) {
rotation
} else {
null
}
fun tryGetRawRotation(): Quaternion? {
return if (hasData(TrackerFrameData.RAW_ROTATION)) {
rawRotation
} else {
null
}
fun tryGetRawRotation(): Quaternion? = if (hasData(TrackerFrameData.RAW_ROTATION)) {
rawRotation
} else {
null
}
fun tryGetPosition(): Vector3? {
return if (hasData(TrackerFrameData.POSITION)) {
position
} else {
null
}
fun tryGetPosition(): Vector3? = if (hasData(TrackerFrameData.POSITION)) {
position
} else {
null
}
fun tryGetAcceleration(): Vector3? {
return if (hasData(TrackerFrameData.ACCELERATION)) {
acceleration
} else {
null
}
fun tryGetAcceleration(): Vector3? = if (hasData(TrackerFrameData.ACCELERATION)) {
acceleration
} else {
null
}
fun hasRotation(): Boolean {
return hasData(TrackerFrameData.ROTATION)
}
fun hasRotation(): Boolean = hasData(TrackerFrameData.ROTATION)
fun hasPosition(): Boolean {
return hasData(TrackerFrameData.POSITION)
}
fun hasPosition(): Boolean = hasData(TrackerFrameData.POSITION)
fun hasAcceleration(): Boolean {
return hasData(TrackerFrameData.ACCELERATION)
}
fun hasAcceleration(): Boolean = hasData(TrackerFrameData.ACCELERATION)
// endregion
companion object {
@@ -128,7 +110,7 @@ data class TrackerFrame(
rotation,
position,
acceleration,
rawRotation
rawRotation,
)
}
}

View File

@@ -1,7 +1,13 @@
package dev.slimevr.poseframeformat.trackerdata
enum class TrackerFrameData(id: Int) {
DESIGNATION_STRING(0), ROTATION(1), POSITION(2), TRACKER_POSITION_ENUM(3), ACCELERATION(4), RAW_ROTATION(5);
DESIGNATION_STRING(0),
ROTATION(1),
POSITION(2),
TRACKER_POSITION_ENUM(3),
ACCELERATION(4),
RAW_ROTATION(5),
;
val flag: Int
@@ -13,15 +19,9 @@ enum class TrackerFrameData(id: Int) {
* Inline is fine for these, there's no negative to inlining them as they'll never
* change, so any warning about it can be safely ignored
*/
inline fun check(dataFlags: Int): Boolean {
return dataFlags and flag != 0
}
inline fun check(dataFlags: Int): Boolean = dataFlags and flag != 0
inline fun add(dataFlags: Int): Int {
return dataFlags or flag
}
inline fun add(dataFlags: Int): Int = dataFlags or flag
inline fun remove(dataFlags: Int): Int {
return dataFlags xor flag
}
inline fun remove(dataFlags: Int): Int = dataFlags xor flag
}

View File

@@ -24,13 +24,9 @@ data class TrackerFrames(val name: String = "", val frames: FastList<TrackerFram
return trackerFrame
}
fun tryGetFrame(index: Int): TrackerFrame? {
return if (index < 0 || index >= frames.size) null else frames[index]
}
fun tryGetFrame(index: Int): TrackerFrame? = if (index < 0 || index >= frames.size) null else frames[index]
fun tryGetFirstNotNullFrame(): TrackerFrame? {
return frames.firstOrNull { frame -> frame != null }
}
fun tryGetFirstNotNullFrame(): TrackerFrame? = frames.firstOrNull { frame -> frame != null }
fun toTracker(): Tracker {
val firstFrame = tryGetFirstNotNullFrame() ?: TrackerFrame.empty
@@ -44,7 +40,7 @@ data class TrackerFrames(val name: String = "", val frames: FastList<TrackerFram
hasAcceleration = firstFrame.hasAcceleration(),
// Make sure this is false!! Otherwise HumanSkeleton ignores it
isInternal = false,
isComputed = true
isComputed = true,
)
tracker.status = TrackerStatus.OK

View File

@@ -26,19 +26,19 @@ class RPCAutoBoneHandler(
init {
rpcHandler.registerPacketListener(
RpcMessage.AutoBoneProcessRequest,
::onAutoBoneProcessRequest
::onAutoBoneProcessRequest,
)
rpcHandler.registerPacketListener(
RpcMessage.AutoBoneApplyRequest,
::onAutoBoneApplyRequest
::onAutoBoneApplyRequest,
)
rpcHandler.registerPacketListener(
RpcMessage.AutoBoneStopRecordingRequest,
::onAutoBoneStopRecordingRequest
::onAutoBoneStopRecordingRequest,
)
rpcHandler.registerPacketListener(
RpcMessage.AutoBoneCancelRecordingRequest,
::onAutoBoneCancelRecordingRequest
::onAutoBoneCancelRecordingRequest,
)
this.api.server.autoBoneHandler.addListener(this)
@@ -76,7 +76,7 @@ class RPCAutoBoneHandler(
AutoBoneProcessStatusResponse.startAutoBoneProcessStatusResponse(fbb)
AutoBoneProcessStatusResponse.addProcessType(
fbb,
processType.id
processType.id,
)
AutoBoneProcessStatusResponse.addCurrent(fbb, current)
@@ -90,7 +90,7 @@ class RPCAutoBoneHandler(
val outbound: Int = rpcHandler.createRPCMessage(
fbb,
RpcMessage.AutoBoneProcessStatusResponse,
update
update,
)
fbb.finish(outbound)
conn.send(fbb.dataBuffer())
@@ -117,7 +117,7 @@ class RPCAutoBoneHandler(
fbb,
epoch.configValues.map { (key, value) ->
SkeletonPart.createSkeletonPart(fbb, key.id, value)
}.toIntArray()
}.toIntArray(),
)
val update = AutoBoneEpochResponse
.createAutoBoneEpochResponse(
@@ -125,12 +125,12 @@ class RPCAutoBoneHandler(
epoch.epoch.toLong(),
epoch.totalEpochs.toLong(),
epoch.epochError.mean,
skeletonPartsOffset
skeletonPartsOffset,
)
val outbound: Int = rpcHandler.createRPCMessage(
fbb,
RpcMessage.AutoBoneEpochResponse,
update
update,
)
fbb.finish(outbound)
conn.send(fbb.dataBuffer())
@@ -153,7 +153,7 @@ class RPCAutoBoneHandler(
val outbound = rpcHandler.createRPCMessage(
fbb,
RpcMessage.SkeletonConfigResponse,
RPCBuilder.createSkeletonConfig(fbb, api.server.humanPoseManager)
RPCBuilder.createSkeletonConfig(fbb, api.server.humanPoseManager),
)
fbb.finish(outbound)
conn.send(fbb.dataBuffer())

View File

@@ -13,8 +13,7 @@ import solarxr_protocol.rpc.TapDetectionSetupNotification
class RPCTapSetupHandler(
private val rpcHandler: RPCHandler,
val api: ProtocolAPI,
) :
TapSetupListener {
) : TapSetupListener {
init {
this.api.server.tapSetupHandler.addListener(this)
}
@@ -29,7 +28,7 @@ class RPCTapSetupHandler(
forAllListeners {
it.send(
fbb.dataBuffer()
fbb.dataBuffer(),
)
}
}

View File

@@ -42,7 +42,7 @@ class RPCStatusHandler(
val outbound = this.rpcHandler.createRPCMessage(
fbb,
RpcMessage.StatusSystemUpdate,
update
update,
)
fbb.finish(outbound)
@@ -61,7 +61,7 @@ class RPCStatusHandler(
val outbound = this.rpcHandler.createRPCMessage(
fbb,
RpcMessage.StatusSystemFixed,
update
update,
)
fbb.finish(outbound)

View File

@@ -18,7 +18,7 @@ class RPCTrackingPause(private val rpcHandler: RPCHandler, private val api: Prot
init {
rpcHandler.registerPacketListener(
RpcMessage.TrackingPauseStateRequest,
::onTrackingPauseStateRequest
::onTrackingPauseStateRequest,
)
// HumanPoseManager might not be immediately available, so queue the server

View File

@@ -38,14 +38,14 @@ abstract class SerialHandler {
// FT232RL/Q, FT245RL/Q
// VNC1L with VDPS Firmware
// VNC2 with FT232Slave
Pair(0x0403, 0x6001)
Pair(0x0403, 0x6001),
)
fun isKnownBoard(port: SerialPort): Boolean =
supportedSerial.contains(Pair(port.vendorId, port.productId))
}
}
class SerialHandlerStub() : SerialHandler() {
class SerialHandlerStub : SerialHandler() {
override val isConnected: Boolean = false
override val knownPorts: Stream<out SerialPort> = Stream.empty()
@@ -53,9 +53,7 @@ class SerialHandlerStub() : SerialHandler() {
override fun removeListener(channel: SerialListener) {}
override fun openSerial(portLocation: String?, auto: Boolean): Boolean {
return false
}
override fun openSerial(portLocation: String?, auto: Boolean): Boolean = false
override fun rebootRequest() {}

View File

@@ -61,16 +61,12 @@ class Bone(val boneType: BoneType) {
/**
* Returns the world-aligned rotation of the bone
*/
fun getGlobalRotation(): Quaternion {
return headNode.worldTransform.rotation
}
fun getGlobalRotation(): Quaternion = headNode.worldTransform.rotation
/**
* Returns the rotation of the bone relative to its parent
*/
fun getLocalRotation(): Quaternion {
return headNode.localTransform.rotation
}
fun getLocalRotation(): Quaternion = headNode.localTransform.rotation
/**
* Sets the global rotation of the bone
@@ -82,16 +78,12 @@ class Bone(val boneType: BoneType) {
/**
* Returns the global position of the head of the bone
*/
fun getPosition(): Vector3 {
return headNode.worldTransform.translation
}
fun getPosition(): Vector3 = headNode.worldTransform.translation
/**
* Returns the global position of the tail of the bone
*/
fun getTailPosition(): Vector3 {
return tailNode.worldTransform.translation
}
fun getTailPosition(): Vector3 = tailNode.worldTransform.translation
/**
* Sets the global position of the head of the bone.

View File

@@ -160,7 +160,7 @@ class HumanSkeleton(
server.configManager.vrConfig.tapDetection,
server.resetHandler,
server.tapSetupHandler,
server.allTrackers
server.allTrackers,
)
legTweaks.setConfig(server.configManager.vrConfig.legTweaks)
localizer.setEnabled(humanPoseManager.getToggle(SkeletonConfigToggles.SELF_LOCALIZATION))
@@ -336,21 +336,19 @@ class HumanSkeleton(
/**
* Get output tracker from TrackerRole
*/
fun getComputedTracker(trackerRole: TrackerRole): Tracker {
return when (trackerRole) {
TrackerRole.HEAD -> computedHeadTracker!!
TrackerRole.CHEST -> computedChestTracker!!
TrackerRole.WAIST -> computedHipTracker!!
TrackerRole.LEFT_KNEE -> computedLeftKneeTracker!!
TrackerRole.LEFT_FOOT -> computedLeftFootTracker!!
TrackerRole.RIGHT_KNEE -> computedRightKneeTracker!!
TrackerRole.RIGHT_FOOT -> computedRightFootTracker!!
TrackerRole.LEFT_ELBOW -> computedLeftElbowTracker!!
TrackerRole.RIGHT_ELBOW -> computedRightElbowTracker!!
TrackerRole.LEFT_HAND -> computedLeftHandTracker!!
TrackerRole.RIGHT_HAND -> computedRightHandTracker!!
else -> throw IllegalArgumentException("Unsupported computed tracker's TrackerRole in HumanSkeleton")
}
fun getComputedTracker(trackerRole: TrackerRole): Tracker = when (trackerRole) {
TrackerRole.HEAD -> computedHeadTracker!!
TrackerRole.CHEST -> computedChestTracker!!
TrackerRole.WAIST -> computedHipTracker!!
TrackerRole.LEFT_KNEE -> computedLeftKneeTracker!!
TrackerRole.LEFT_FOOT -> computedLeftFootTracker!!
TrackerRole.RIGHT_KNEE -> computedRightKneeTracker!!
TrackerRole.RIGHT_FOOT -> computedRightFootTracker!!
TrackerRole.LEFT_ELBOW -> computedLeftElbowTracker!!
TrackerRole.RIGHT_ELBOW -> computedRightElbowTracker!!
TrackerRole.LEFT_HAND -> computedLeftHandTracker!!
TrackerRole.RIGHT_HAND -> computedRightHandTracker!!
else -> throw IllegalArgumentException("Unsupported computed tracker's TrackerRole in HumanSkeleton")
}
/**
@@ -403,7 +401,7 @@ class HumanSkeleton(
leftFootTrackerBone,
leftUpperLegTracker,
leftLowerLegTracker,
leftFootTracker
leftFootTracker,
)
// Right leg
updateLegTransforms(
@@ -414,7 +412,7 @@ class HumanSkeleton(
rightFootTrackerBone,
rightUpperLegTracker,
rightLowerLegTracker,
rightFootTracker
rightFootTracker,
)
// Left arm
updateArmTransforms(
@@ -428,7 +426,7 @@ class HumanSkeleton(
leftShoulderTracker,
leftUpperArmTracker,
leftLowerArmTracker,
leftHandTracker
leftHandTracker,
)
// Right arm
updateArmTransforms(
@@ -442,7 +440,7 @@ class HumanSkeleton(
rightShoulderTracker,
rightUpperArmTracker,
rightLowerArmTracker,
rightHandTracker
rightHandTracker,
)
}
@@ -477,7 +475,7 @@ class HumanSkeleton(
upperChestTracker,
chestTracker,
waistTracker,
hipTracker
hipTracker,
)?.let { headRot = it.getRotation() }
headBone.setRotation(headRot)
@@ -840,18 +838,27 @@ class HumanSkeleton(
fun updateToggleState(configToggle: SkeletonConfigToggles, newValue: Boolean) {
when (configToggle) {
SkeletonConfigToggles.EXTENDED_SPINE_MODEL -> extendedSpineModel = newValue
SkeletonConfigToggles.EXTENDED_PELVIS_MODEL -> extendedPelvisModel = newValue
SkeletonConfigToggles.EXTENDED_KNEE_MODEL -> extendedKneeModel = newValue
SkeletonConfigToggles.FORCE_ARMS_FROM_HMD -> {
forceArmsFromHMD = newValue
assembleSkeletonArms(true) // Rebuilds the arm skeleton nodes attachments
computeDependentArmOffsets() // Refresh node offsets for arms
}
SkeletonConfigToggles.SKATING_CORRECTION -> legTweaks.setSkatingCorrectionEnabled(newValue)
SkeletonConfigToggles.FLOOR_CLIP -> legTweaks.setFloorClipEnabled(newValue)
SkeletonConfigToggles.VIVE_EMULATION -> viveEmulation.enabled = newValue
SkeletonConfigToggles.TOE_SNAP -> legTweaks.toeSnapEnabled = newValue
SkeletonConfigToggles.FOOT_PLANT -> legTweaks.footPlantEnabled = newValue
SkeletonConfigToggles.SELF_LOCALIZATION -> localizer.setEnabled(newValue)
}
}
@@ -912,42 +919,40 @@ class HumanSkeleton(
humanPoseManager.computeNodeOffset(BoneType.RIGHT_HAND)
}
fun getBone(bone: BoneType): Bone {
return when (bone) {
BoneType.HEAD -> headBone
BoneType.HEAD_TRACKER -> headTrackerBone
BoneType.NECK -> neckBone
BoneType.UPPER_CHEST -> upperChestBone
BoneType.CHEST_TRACKER -> chestTrackerBone
BoneType.CHEST -> chestBone
BoneType.WAIST -> waistBone
BoneType.HIP -> hipBone
BoneType.HIP_TRACKER -> hipTrackerBone
BoneType.LEFT_HIP -> leftHipBone
BoneType.RIGHT_HIP -> rightHipBone
BoneType.LEFT_UPPER_LEG -> leftUpperLegBone
BoneType.RIGHT_UPPER_LEG -> rightUpperLegBone
BoneType.LEFT_KNEE_TRACKER -> leftKneeTrackerBone
BoneType.RIGHT_KNEE_TRACKER -> rightKneeTrackerBone
BoneType.LEFT_LOWER_LEG -> leftLowerLegBone
BoneType.RIGHT_LOWER_LEG -> rightLowerLegBone
BoneType.LEFT_FOOT -> leftFootBone
BoneType.RIGHT_FOOT -> rightFootBone
BoneType.LEFT_FOOT_TRACKER -> leftFootTrackerBone
BoneType.RIGHT_FOOT_TRACKER -> rightFootTrackerBone
BoneType.LEFT_SHOULDER -> leftShoulderBone
BoneType.RIGHT_SHOULDER -> rightShoulderBone
BoneType.LEFT_UPPER_ARM -> leftUpperArmBone
BoneType.RIGHT_UPPER_ARM -> rightUpperArmBone
BoneType.LEFT_ELBOW_TRACKER -> leftElbowTrackerBone
BoneType.RIGHT_ELBOW_TRACKER -> rightElbowTrackerBone
BoneType.LEFT_LOWER_ARM -> leftLowerArmBone
BoneType.RIGHT_LOWER_ARM -> rightLowerArmBone
BoneType.LEFT_HAND -> leftHandBone
BoneType.RIGHT_HAND -> rightHandBone
BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone
BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone
}
fun getBone(bone: BoneType): Bone = when (bone) {
BoneType.HEAD -> headBone
BoneType.HEAD_TRACKER -> headTrackerBone
BoneType.NECK -> neckBone
BoneType.UPPER_CHEST -> upperChestBone
BoneType.CHEST_TRACKER -> chestTrackerBone
BoneType.CHEST -> chestBone
BoneType.WAIST -> waistBone
BoneType.HIP -> hipBone
BoneType.HIP_TRACKER -> hipTrackerBone
BoneType.LEFT_HIP -> leftHipBone
BoneType.RIGHT_HIP -> rightHipBone
BoneType.LEFT_UPPER_LEG -> leftUpperLegBone
BoneType.RIGHT_UPPER_LEG -> rightUpperLegBone
BoneType.LEFT_KNEE_TRACKER -> leftKneeTrackerBone
BoneType.RIGHT_KNEE_TRACKER -> rightKneeTrackerBone
BoneType.LEFT_LOWER_LEG -> leftLowerLegBone
BoneType.RIGHT_LOWER_LEG -> rightLowerLegBone
BoneType.LEFT_FOOT -> leftFootBone
BoneType.RIGHT_FOOT -> rightFootBone
BoneType.LEFT_FOOT_TRACKER -> leftFootTrackerBone
BoneType.RIGHT_FOOT_TRACKER -> rightFootTrackerBone
BoneType.LEFT_SHOULDER -> leftShoulderBone
BoneType.RIGHT_SHOULDER -> rightShoulderBone
BoneType.LEFT_UPPER_ARM -> leftUpperArmBone
BoneType.RIGHT_UPPER_ARM -> rightUpperArmBone
BoneType.LEFT_ELBOW_TRACKER -> leftElbowTrackerBone
BoneType.RIGHT_ELBOW_TRACKER -> rightElbowTrackerBone
BoneType.LEFT_LOWER_ARM -> leftLowerArmBone
BoneType.RIGHT_LOWER_ARM -> rightLowerArmBone
BoneType.LEFT_HAND -> leftHandBone
BoneType.RIGHT_HAND -> rightHandBone
BoneType.LEFT_HAND_TRACKER -> leftHandTrackerBone
BoneType.RIGHT_HAND_TRACKER -> rightHandTrackerBone
}
/**
@@ -976,7 +981,7 @@ class HumanSkeleton(
leftLowerArmBone,
rightLowerArmBone,
leftHandBone,
rightHandBone
rightHandBone,
)
/**
@@ -995,28 +1000,30 @@ class HumanSkeleton(
leftHandBone,
rightHandBone,
leftHandTrackerBone,
rightHandTrackerBone
rightHandTrackerBone,
)
val hmdHeight: Float
get() = headTracker?.position?.y ?: 0f
/**
* Runs checks to know if we should (and are) performing the tracking of the
* left arm from the controller.
*
* @return a bool telling us if we are tracking the left arm from the
* controller or not.
*/
val isTrackingLeftArmFromController: Boolean
/**
* Runs checks to know if we should (and are) performing the tracking of the
* left arm from the controller.
*
* @return a bool telling us if we are tracking the left arm from the
* controller or not.
*/
get() = leftHandTracker != null && leftHandTracker!!.hasPosition && !forceArmsFromHMD
/**
* Runs checks to know if we should (and are) performing the tracking of the
* right arm from the controller.
*
* @return a bool telling us if we are tracking the right arm from the
* controller or not.
*/
val isTrackingRightArmFromController: Boolean
/**
* Runs checks to know if we should (and are) performing the tracking of the
* right arm from the controller.
*
* @return a bool telling us if we are tracking the right arm from the
* controller or not.
*/
get() = rightHandTracker != null && rightHandTracker!!.hasPosition && !forceArmsFromHMD
val localTrackers: List<Tracker?>
get() = listOf(
@@ -1037,7 +1044,7 @@ class HumanSkeleton(
leftHandTracker,
rightHandTracker,
leftShoulderTracker,
rightShoulderTracker
rightShoulderTracker,
)
fun resetTrackersFull(resetSourceName: String?) {
@@ -1167,7 +1174,7 @@ class HumanSkeleton(
if (skatingCorrection) {
legTweaks
.setSkatingCorrectionEnabled(
humanPoseManager.getToggle(SkeletonConfigToggles.SKATING_CORRECTION)
humanPoseManager.getToggle(SkeletonConfigToggles.SKATING_CORRECTION),
)
}
if (floorClip) {
@@ -1206,9 +1213,7 @@ class HumanSkeleton(
humanPoseManager.setToggle(SkeletonConfigToggles.SKATING_CORRECTION, value)
}
fun getPauseTracking(): Boolean {
return pauseTracking
}
fun getPauseTracking(): Boolean = pauseTracking
fun setPauseTracking(pauseTracking: Boolean, sourceName: String?) {
if (!pauseTracking && this.pauseTracking) {
@@ -1232,7 +1237,7 @@ class HumanSkeleton(
EulerOrder.YZX,
FastMath.HALF_PI,
0f,
0f
0f,
).toQuaternion()
}
}

View File

@@ -184,7 +184,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
fun tweakLegs() {
// If user doesn't have knees or legtweaks is disabled,
// don't spend time doing calculations!
if (!skeleton.hasKneeTrackers && !alwaysUseFloorclip || !enabled) return
if ((!skeleton.hasKneeTrackers && !alwaysUseFloorclip) || !enabled) return
// update the class with the latest data from the skeleton
// if false is returned something indicated that the legs should not
@@ -205,11 +205,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
// (use the buffer to get the positions before corrections)
val leftFootDif = FastMath
.abs(
(bufferHead.leftFootPosition - leftFootPosition).y
(bufferHead.leftFootPosition - leftFootPosition).y,
)
val rightFootDif = FastMath
.abs(
(bufferHead.rightFootPosition - rightFootPosition).y
(bufferHead.rightFootPosition - rightFootPosition).y,
)
if (!active && leftFootDif < NEARLY_ZERO) {
@@ -228,24 +228,24 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
leftFootPosition = Vector3(
leftFootPosition.x,
bufferHead.leftFootPosition.y,
leftFootPosition.z
leftFootPosition.z,
)
leftKneePosition = Vector3(
leftKneePosition.x,
bufferHead.leftKneePosition.y,
leftKneePosition.z
leftKneePosition.z,
)
}
if (!rightLegActive) {
rightFootPosition = Vector3(
rightFootPosition.x,
bufferHead.rightFootPosition.y,
rightFootPosition.z
rightFootPosition.z,
)
rightKneePosition = Vector3(
rightKneePosition.x,
bufferHead.rightKneePosition.y,
rightKneePosition.z
rightKneePosition.z,
)
}
@@ -259,7 +259,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
rightFootPosition,
leftKneePosition,
rightKneePosition,
hipPosition
hipPosition,
)
// Set the corrected positions in the skeleton
@@ -275,21 +275,19 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
LegTweaksBuffer.setSkatingVelocityThreshold(
getScaledHyperParameter(
newStrength,
LegTweaksBuffer.getSkatingVelocityThreshold()
)
LegTweaksBuffer.getSkatingVelocityThreshold(),
),
)
LegTweaksBuffer.setSkatingAccelerationThreshold(
getScaledHyperParameter(
newStrength,
LegTweaksBuffer.getSkatingAccelerationThreshold()
)
LegTweaksBuffer.getSkatingAccelerationThreshold(),
),
)
currentCorrectionStrength = newStrength
}
private fun getScaledHyperParameter(newStrength: Float, currentValue: Float): Float {
return currentValue - currentCorrectionStrength * MAX_CORRECTION_STRENGTH_DELTA + newStrength * MAX_CORRECTION_STRENGTH_DELTA
}
private fun getScaledHyperParameter(newStrength: Float, currentValue: Float): Float = currentValue - currentCorrectionStrength * MAX_CORRECTION_STRENGTH_DELTA + newStrength * MAX_CORRECTION_STRENGTH_DELTA
private fun setFloorLevel(floorLevel: Float) {
this.floorLevel = floorLevel
@@ -350,7 +348,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
rightFootPosition,
leftKneePosition,
rightKneePosition,
hipPosition
hipPosition,
)
// if active correct clipping before populating corrected positions
@@ -364,7 +362,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
rightFootPosition,
leftKneePosition,
rightKneePosition,
hipPosition
hipPosition,
)
bufferHead.leftLegState = LegTweaksBuffer.UNLOCKED
bufferHead.rightLegState = LegTweaksBuffer.UNLOCKED
@@ -404,7 +402,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
hipPosition,
centerOfMass,
bufferHead,
active
active,
)
// update the lock duration counters
@@ -412,12 +410,10 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
}
// returns true if the foot is clipped and false if it is not
private fun isClipped(leftOffset: Float, rightOffset: Float): Boolean {
return (
leftFootPosition.y < floorLevel + leftOffset * footLength ||
rightFootPosition.y < floorLevel + rightOffset * footLength
)
}
private fun isClipped(leftOffset: Float, rightOffset: Float): Boolean = (
leftFootPosition.y < floorLevel + leftOffset * footLength ||
rightFootPosition.y < floorLevel + rightOffset * footLength
)
// corrects the foot position to be above the floor level that is calculated
// on calibration
@@ -440,17 +436,17 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
(
floorLevel + footLength * leftOffset - leftFootPosition.y -
currentDisengagementOffset
)
),
)
leftFootPosition = Vector3(
leftFootPosition.x,
leftFootPosition.y + displacement,
leftFootPosition.z
leftFootPosition.z,
)
leftKneePosition = Vector3(
leftKneePosition.x,
leftKneePosition.y + displacement,
leftKneePosition.z
leftKneePosition.z,
)
avgOffset += displacement
}
@@ -463,17 +459,17 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
(
floorLevel + footLength * rightOffset - rightFootPosition.y -
currentDisengagementOffset
)
),
)
rightFootPosition = Vector3(
rightFootPosition.x,
rightFootPosition.y + displacement,
rightFootPosition.z
rightFootPosition.z,
)
rightKneePosition = Vector3(
rightKneePosition.x,
rightKneePosition.y + displacement,
rightKneePosition.z
rightKneePosition.z,
)
avgOffset += displacement
}
@@ -481,7 +477,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
hipPosition = Vector3(
hipPosition.x,
hipPosition.y + avgOffset / 2 * WAIST_PUSH_WEIGHT,
hipPosition.z
hipPosition.z,
)
}
@@ -500,7 +496,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
leftFootPosition.y,
bufPrev
.leftFootPositionCorrected
.z
.z,
)
}
if (bufferHead.rightLegState == LegTweaksBuffer.LOCKED) {
@@ -511,7 +507,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
rightFootPosition.y,
bufPrev
.rightFootPositionCorrected
.z
.z,
)
}
@@ -549,7 +545,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
// applied
val weight: Float = calculateCorrectionWeight(
newFootPosition,
previousFootPositionCorrected
previousFootPositionCorrected,
)
val constantCorrection = getConstantCorrectionQuantity(framesUnlocked)
var newX = newFootPosition.x
@@ -598,7 +594,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
if (checkOverShoot(
footPosition.x,
previousFootPositionCorrected.x,
newX
newX,
)
) {
newX = footPosition.x
@@ -606,7 +602,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
if (checkOverShoot(
footPosition.z,
previousFootPositionCorrected.z,
newZ
newZ,
)
) {
newZ = footPosition.z
@@ -618,15 +614,13 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
}
// get the amount of the constant correction to apply.
private fun getConstantCorrectionQuantity(framesUnlocked: Int): Float {
return if (framesUnlocked >= CONTINUOUS_CORRECTION_WARMUP) {
private fun getConstantCorrectionQuantity(framesUnlocked: Int): Float = if (framesUnlocked >= CONTINUOUS_CORRECTION_WARMUP) {
CONTINUOUS_CORRECTION_DIST
} else {
(
CONTINUOUS_CORRECTION_DIST
} else {
(
CONTINUOUS_CORRECTION_DIST
* (leftFramesUnlocked.toFloat() / CONTINUOUS_CORRECTION_WARMUP)
)
}
* (leftFramesUnlocked.toFloat() / CONTINUOUS_CORRECTION_WARMUP)
)
}
// correct the rotations of the feet
@@ -660,12 +654,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
// if foot trackers exist add to the weights
if (leftFootTracker) {
weightL *= getRotationalDistanceToPlant(
leftFootRotation
leftFootRotation,
)
}
if (rightFootTracker) {
weightR *= getRotationalDistanceToPlant(
rightFootRotation
rightFootRotation,
)
}
@@ -673,12 +667,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
leftFootRotation = leftFootRotation
.interpR(
isolateYaw(leftFootRotation),
weightL * masterWeightL
weightL * masterWeightL,
)
rightFootRotation = rightFootRotation
.interpR(
isolateYaw(rightFootRotation),
weightR * masterWeightR
weightR * masterWeightR,
)
}
@@ -711,14 +705,14 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
leftFootRotation = leftFootRotation
.interpR(
replacePitch(leftFootRotation, -angleL),
weightL * masterWeightL
weightL * masterWeightL,
)
}
if (!rightFootTracker) {
rightFootRotation = rightFootRotation
.interpR(
replacePitch(rightFootRotation, -angleR),
weightR * masterWeightR
weightR * masterWeightR,
)
}
@@ -796,11 +790,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
val angle = FastMath.clamp(footPos.y - floorLevel, 0.0f, footLength)
return if (angle > footLength * MAXIMUM_TOE_DOWN_ANGLE) {
FastMath.asin(
footLength * MAXIMUM_TOE_DOWN_ANGLE / footLength
footLength * MAXIMUM_TOE_DOWN_ANGLE / footLength,
)
} else {
FastMath.asin(
angle / footLength
angle / footLength,
)
}
}
@@ -820,7 +814,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
angle = FastMath.clamp(
angle,
MIN_DISTANCE_FOR_PLANT,
MAX_DISTANCE_FOR_PLANT
MAX_DISTANCE_FOR_PLANT,
)
return (
1 -
@@ -955,16 +949,16 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
if (armsAvailable) {
val leftUpperArm: Vector3 = getCenterOfJoint(
skeleton.leftUpperArmBone
skeleton.leftUpperArmBone,
)
val rightUpperArm: Vector3 = getCenterOfJoint(
skeleton.rightUpperArmBone
skeleton.rightUpperArmBone,
)
val leftForearm: Vector3 = getCenterOfJoint(
skeleton.leftLowerArmBone
skeleton.leftLowerArmBone,
)
val rightForearm: Vector3 = getCenterOfJoint(
skeleton.rightLowerArmBone
skeleton.rightLowerArmBone,
)
centerOfMass += leftUpperArm * UPPER_ARM_MASS
centerOfMass += rightUpperArm * UPPER_ARM_MASS
@@ -974,7 +968,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
// if the arms are not available put them slightly in front
// of the upper chest.
val chestUnitVector: Vector3 = computeUnitVector(
skeleton.upperChestBone.getGlobalRotation()
skeleton.upperChestBone.getGlobalRotation(),
)
val armLocation =
abdomen + (chestUnitVector * DEFAULT_ARM_DISTANCE)
@@ -989,13 +983,11 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
}
// get the center of two joints
private fun getCenterOfJoint(bone: Bone): Vector3 {
return (
bone.getPosition() +
bone.getTailPosition()
) *
0.5f
}
private fun getCenterOfJoint(bone: Bone): Vector3 = (
bone.getPosition() +
bone.getTailPosition()
) *
0.5f
// update counters for the lock state of the feet
private fun updateLockStateCounters() {
@@ -1016,14 +1008,12 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
}
// remove the x and z components of the given quaternion
private fun isolateYaw(quaternion: Quaternion): Quaternion {
return Quaternion(
quaternion.w,
0f,
quaternion.y,
0f
)
}
private fun isolateYaw(quaternion: Quaternion): Quaternion = Quaternion(
quaternion.w,
0f,
quaternion.y,
0f,
)
// return a quaternion that has been rotated by the new pitch amount
private fun replacePitch(quaternion: Quaternion, newPitch: Float): Quaternion {
@@ -1032,7 +1022,7 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
EulerOrder.YZX,
newPitch,
y,
z
z,
)
return newAngs.toQuaternion()
}
@@ -1043,12 +1033,8 @@ class LegTweaks(private val skeleton: HumanSkeleton) {
trueVal: Float,
valBefore: Float,
valAfter: Float,
): Boolean {
return (trueVal - valBefore) * (trueVal - valAfter) < 0
}
): Boolean = (trueVal - valBefore) * (trueVal - valAfter) < 0
// get the unit vector of the given rotation
private fun computeUnitVector(quaternion: Quaternion): Vector3 {
return quaternion.toMatrix().z.unit()
}
private fun computeUnitVector(quaternion: Quaternion): Vector3 = quaternion.toMatrix().z.unit()
}

View File

@@ -19,7 +19,7 @@ import io.github.axisangles.ktmath.Vector3
* large range of actions and body types.
*/
class LegTweaksBuffer() {
class LegTweaksBuffer @Suppress("ktlint") constructor() {
// hyperparameters / constants
companion object {
const val STATE_UNKNOWN = 0
@@ -92,9 +92,7 @@ class LegTweaksBuffer() {
)
}
fun getSkatingVelocityThreshold(): Float {
return SKATING_VELOCITY_THRESHOLD
}
fun getSkatingVelocityThreshold(): Float = SKATING_VELOCITY_THRESHOLD
fun setSkatingAccelerationThreshold(value: Float) {
SKATING_ACCELERATION_THRESHOLD = value
@@ -104,9 +102,7 @@ class LegTweaksBuffer() {
)
}
fun getSkatingAccelerationThreshold(): Float {
return SKATING_ACCELERATION_THRESHOLD
}
fun getSkatingAccelerationThreshold(): Float = SKATING_ACCELERATION_THRESHOLD
}
// states for the legs
@@ -267,9 +263,7 @@ class LegTweaksBuffer() {
}
// returns 1 / delta time
fun getTimeDelta(): Float {
return if (parent == null) 0.0f else 1.0f / ((timeOfFrame - parent!!.timeOfFrame) / NS_CONVERT)
}
fun getTimeDelta(): Float = if (parent == null) 0.0f else 1.0f / ((timeOfFrame - parent!!.timeOfFrame) / NS_CONVERT)
// calculate movement attributes
private fun calculateFootAttributes(active: Boolean) {
@@ -322,7 +316,7 @@ class LegTweaksBuffer() {
leftFootAngleDiff,
leftFloorLevel,
accelerationAboveThresholdLeft,
leftFootPosition
leftFootPosition,
)
rightLegState = checkState(
parent!!.rightLegState,
@@ -332,7 +326,7 @@ class LegTweaksBuffer() {
rightFootAngleDiff,
rightFloorLevel,
accelerationAboveThresholdRight,
rightFootPosition
rightFootPosition,
)
computeNumericalState()
@@ -381,13 +375,13 @@ class LegTweaksBuffer() {
leftFootVelocityMagnitude,
leftFootAccelerationMagnitude,
leftFootSensitivityAccel,
leftFootSensitivityVel
leftFootSensitivityVel,
)
rightLegNumericalState = computeNumericalState(
rightFootVelocityMagnitude,
rightFootAccelerationMagnitude,
rightFootSensitivityAccel,
rightFootSensitivityVel
rightFootSensitivityVel,
)
}
@@ -417,14 +411,12 @@ class LegTweaksBuffer() {
return Vector3(
diff.x,
0f,
diff.z
diff.z,
).len()
}
// get the angular velocity of the left foot (kinda we just want a scalar)
private fun getFootAngularVelocity(oldRot: Quaternion, rot: Quaternion): Float {
return (rot.toMatrix().z.unit() - oldRot.toMatrix().z.unit()).len()
}
private fun getFootAngularVelocity(oldRot: Quaternion, rot: Quaternion): Float = (rot.toMatrix().z.unit() - oldRot.toMatrix().z.unit()).len()
// compute the velocity of the feet from the position in the last frames
private fun computeVelocity() {
@@ -438,9 +430,7 @@ class LegTweaksBuffer() {
}
// get the nth parent of this frame
private fun getNParent(n: Int): LegTweaksBuffer? {
return if (n == 0 || parent == null) this else parent!!.getNParent(n - 1)
}
private fun getNParent(n: Int): LegTweaksBuffer? = if (n == 0 || parent == null) this else parent!!.getNParent(n - 1)
// compute the acceleration magnitude of the feet from the acceleration
// given by the imus
@@ -459,11 +449,11 @@ class LegTweaksBuffer() {
private fun computeAccelerationAboveThresholdFootTrackers() {
accelerationAboveThresholdLeft = (
leftFootAccelerationMagnitude
> SKATING_ACCELERATION_CUTOFF_ENGAGE * leftFootSensitivityAccel
> SKATING_ACCELERATION_CUTOFF_ENGAGE * leftFootSensitivityAccel
)
accelerationAboveThresholdRight = (
rightFootAccelerationMagnitude
> SKATING_ACCELERATION_CUTOFF_ENGAGE * rightFootSensitivityAccel
> SKATING_ACCELERATION_CUTOFF_ENGAGE * rightFootSensitivityAccel
)
}
@@ -472,11 +462,11 @@ class LegTweaksBuffer() {
private fun computeAccelerationAboveThresholdAnkleTrackers() {
accelerationAboveThresholdLeft = (
leftFootAccelerationMagnitude
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * leftFootSensitivityAccel
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * leftFootSensitivityAccel
)
accelerationAboveThresholdRight = (
rightFootAccelerationMagnitude
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * rightFootSensitivityAccel
> (SKATING_ACCELERATION_THRESHOLD + SIX_TRACKER_TOLERANCE) * rightFootSensitivityAccel
)
}
@@ -494,13 +484,13 @@ class LegTweaksBuffer() {
leftFootVelocity,
rightFootVelocity,
leftFootVelocityMagnitude,
rightFootVelocityMagnitude
rightFootVelocityMagnitude,
)
val rightFootScalarVel: Float = getFootLockLikelihood(
rightFootVelocity,
leftFootVelocity,
rightFootVelocityMagnitude,
leftFootVelocityMagnitude
leftFootVelocityMagnitude,
)
// get the third set of scalars that is based on where the COM is
@@ -515,7 +505,7 @@ class LegTweaksBuffer() {
FastMath.clamp(
pressureScalars[0] * 2.0f,
PRESSURE_SCALAR_MIN,
PRESSURE_SCALAR_MAX
PRESSURE_SCALAR_MAX,
)
)
rightFootSensitivityVel = (
@@ -526,7 +516,7 @@ class LegTweaksBuffer() {
FastMath.clamp(
pressureScalars[1] * 2.0f,
PRESSURE_SCALAR_MIN,
PRESSURE_SCALAR_MAX
PRESSURE_SCALAR_MAX,
)
)
@@ -728,7 +718,5 @@ class LegTweaksBuffer() {
}
// simple error function for the force vector gradient descent
private fun getForceVectorError(testForce: Vector3, otherForce: Vector3): Vector3 {
return centerOfMassAcceleration - (testForce + otherForce + GRAVITY)
}
private fun getForceVectorError(testForce: Vector3, otherForce: Vector3): Vector3 = centerOfMassAcceleration - (testForce + otherForce + GRAVITY)
}

View File

@@ -66,9 +66,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
private var comTravel: Vector3 = Vector3.NULL
private var sittingTravel: Vector3 = Vector3.NULL
fun getEnabled(): Boolean {
return enabled
}
fun getEnabled(): Boolean = enabled
fun setEnabled(enabled: Boolean) {
this.enabled = enabled
@@ -133,7 +131,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
finalTravel = Vector3(
finalTravel.x,
comTravel.y,
finalTravel.z
finalTravel.z,
)
}
@@ -214,9 +212,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
}
// get the travel of a foot over a frame
private fun getFootTravel(loc: Vector3): Vector3 {
return loc - targetFoot
}
private fun getFootTravel(loc: Vector3): Vector3 = loc - targetFoot
// update the target position of the foot
private fun updateTargetPos(loc: Vector3, foot: MovementStates) {
@@ -319,7 +315,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
comAccel = Vector3(
comAccel.x,
FastMath.clamp(comAccel.y, -9999.0f, 0.0f),
comAccel.z
comAccel.z,
)
}
@@ -331,19 +327,17 @@ class Localizer(humanSkeleton: HumanSkeleton) {
comVelocity = Vector3(
comVelocity.x,
comY + (gravity / bufCur.getTimeDelta()),
comVelocity.z
comVelocity.z,
)
return comVelocity
}
// returns true if either foot is below 0.0
private fun isFootOnGround(): Boolean {
return (
bufCur.leftFootPosition.y <= floor ||
bufCur.rightFootPosition.y <= floor
)
}
private fun isFootOnGround(): Boolean = (
bufCur.leftFootPosition.y <= floor ||
bufCur.rightFootPosition.y <= floor
)
// returns the tracker closest to or the furthest in the ground
private fun getLowestTracker(): Tracker? {
@@ -358,7 +352,7 @@ class Localizer(humanSkeleton: HumanSkeleton) {
skeleton.computedLeftKneeTracker,
skeleton.computedRightKneeTracker,
skeleton.computedLeftFootTracker,
skeleton.computedRightFootTracker
skeleton.computedRightFootTracker,
)
var minVal = trackerList[0]?.position?.y

View File

@@ -84,8 +84,7 @@ class Tracker @JvmOverloads constructor(
*/
var statusResetRecently = false
private var alreadyInitialized = false
var status: TrackerStatus by Delegates.observable(TrackerStatus.DISCONNECTED) {
_, old, new ->
var status: TrackerStatus by Delegates.observable(TrackerStatus.DISCONNECTED) { _, old, new ->
if (old == new) return@observable
if (!new.reset) {
@@ -106,8 +105,7 @@ class Tracker @JvmOverloads constructor(
}
}
var trackerPosition: TrackerPosition? by Delegates.observable(trackerPosition) {
_, old, new ->
var trackerPosition: TrackerPosition? by Delegates.observable(trackerPosition) { _, old, new ->
if (old == new) return@observable
if (!isInternal) {
@@ -307,12 +305,10 @@ class Tracker @JvmOverloads constructor(
/**
* Gets the world-adjusted acceleration
*/
fun getAcceleration(): Vector3 {
return if (needsReset) {
resetsHandler.getReferenceAdjustedAccel(rotation, acceleration)
} else {
acceleration
}
fun getAcceleration(): Vector3 = if (needsReset) {
resetsHandler.getReferenceAdjustedAccel(rotation, acceleration)
} else {
acceleration
}
/**
@@ -341,9 +337,7 @@ class Tracker @JvmOverloads constructor(
* Gets the raw (unadjusted) rotation of the tracker.
* If this is an IMU, this will be the raw sensor rotation.
*/
fun getRawRotation(): Quaternion {
return rotation
}
fun getRawRotation(): Quaternion = rotation
/**
* Sets the raw (unadjusted) rotation of the tracker.
@@ -359,9 +353,7 @@ class Tracker @JvmOverloads constructor(
this.acceleration = vec
}
fun isImu(): Boolean {
return imuType != null
}
fun isImu(): Boolean = imuType != null
/**
* Gets the current TPS of the tracker

View File

@@ -24,7 +24,7 @@ class TrackerFilteringHandler {
movingAverage = QuaternionMovingAverage(
type,
config.amount,
currentRawRotation
currentRawRotation,
)
enabled = true
} else {
@@ -50,7 +50,5 @@ class TrackerFilteringHandler {
/**
* Get the filtered rotation from the moving average
*/
fun getFilteredRotation(): Quaternion {
return movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
}
fun getFilteredRotation(): Quaternion = movingAverage?.filteredQuaternion ?: Quaternion.IDENTITY
}

View File

@@ -40,7 +40,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
EulerOrder.YZX,
0f,
Math.PI.toFloat(),
0f
0f,
).toQuaternion()
set(value) {
field = value
@@ -93,11 +93,12 @@ class TrackerResetsHandler(val tracker: Tracker) {
* a computed head tracker exists.
*/
fun refreshDriftCompensationEnabled() {
driftCompensationEnabled = compensateDrift && allowDriftCompensation &&
driftCompensationEnabled = compensateDrift &&
allowDriftCompensation &&
TrackerUtils.getNonInternalNonImuTrackerForBodyPosition(
VRServer.instance.allTrackers,
TrackerPosition.HEAD
) != null
VRServer.instance.allTrackers,
TrackerPosition.HEAD,
) != null
}
/**
@@ -112,24 +113,18 @@ class TrackerResetsHandler(val tracker: Tracker) {
* Takes a rotation and adjusts it to resets, mounting,
* and drift compensation, with the HMD as the reference.
*/
fun getReferenceAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion {
return adjustToDrift(adjustToReference(rotation))
}
fun getReferenceAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion = adjustToDrift(adjustToReference(rotation))
/**
* Takes a rotation and adjusts it to resets and mounting,
* with the identity Quaternion as the reference.
*/
fun getIdentityAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion {
return adjustToDrift(adjustToIdentity(rotation))
}
fun getIdentityAdjustedDriftRotationFrom(rotation: Quaternion): Quaternion = adjustToDrift(adjustToIdentity(rotation))
/**
* Get the adjusted accel from yawFixZeroReference
*/
fun getReferenceAdjustedAccel(rawRot: Quaternion, accel: Vector3): Vector3 {
return (adjustToReference(rawRot) / yawFix).sandwich(accel)
}
fun getReferenceAdjustedAccel(rawRot: Quaternion, accel: Vector3): Vector3 = (adjustToReference(rawRot) / yawFix).sandwich(accel)
/**
* Converts raw or filtered rotation into reference- and
@@ -166,7 +161,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
return rotation
.interpR(
averagedDriftQuat * rotation,
driftAmount * ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime)
driftAmount * ((System.currentTimeMillis() - driftSince).toFloat() / totalDriftTime),
)
}
return rotation
@@ -183,7 +178,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
EulerOrder.YZX,
0f,
0f,
-FastMath.HALF_PI
-FastMath.HALF_PI,
).toQuaternion()
} else if ((isRightArmTracker() && armsResetMode == ArmsResetModes.TPOSE_DOWN)) {
tposeFix = EulerAngles(EulerOrder.YZX, 0f, 0f, FastMath.HALF_PI).toQuaternion()
@@ -308,13 +303,9 @@ class TrackerResetsHandler(val tracker: Tracker) {
mountRotFix = Quaternion.IDENTITY
}
private fun fixGyroscope(sensorRotation: Quaternion): Quaternion {
return getYawQuaternion(sensorRotation).inv()
}
private fun fixGyroscope(sensorRotation: Quaternion): Quaternion = getYawQuaternion(sensorRotation).inv()
private fun fixAttachment(sensorRotation: Quaternion): Quaternion {
return (gyroFix * sensorRotation).inv()
}
private fun fixAttachment(sensorRotation: Quaternion): Quaternion = (gyroFix * sensorRotation).inv()
private fun fixYaw(sensorRotation: Quaternion, reference: Quaternion): Quaternion {
var rot = gyroFix * sensorRotation
@@ -329,9 +320,7 @@ class TrackerResetsHandler(val tracker: Tracker) {
// incorrect. Projection around the Y-axis is worse.
// In both cases, the isolated yaw value changes
// with the tracker's roll when pointing forward.
private fun getYawQuaternion(rot: Quaternion): Quaternion {
return EulerAngles(EulerOrder.YZX, 0f, rot.toEulerAngles(EulerOrder.YZX).y, 0f).toQuaternion()
}
private fun getYawQuaternion(rot: Quaternion): Quaternion = EulerAngles(EulerOrder.YZX, 0f, rot.toEulerAngles(EulerOrder.YZX).y, 0f).toQuaternion()
private fun makeIdentityAdjustmentQuatsFull() {
val sensorRotation = tracker.getRawRotation()
@@ -368,11 +357,15 @@ class TrackerResetsHandler(val tracker: Tracker) {
// Add drift time to total
driftTimes.add(System.currentTimeMillis() - driftSince)
totalDriftTime = 0
for (time in driftTimes) { totalDriftTime += time }
for (time in driftTimes) {
totalDriftTime += time
}
// Calculate drift Quaternions' weights
val driftWeights = ArrayList<Float>(driftTimes.size)
for (time in driftTimes) { driftWeights.add(time.toFloat() / totalDriftTime.toFloat()) }
for (time in driftTimes) {
driftWeights.add(time.toFloat() / totalDriftTime.toFloat())
}
// Make it so recent Quaternions weigh more
for (i in driftWeights.size - 1 downTo 1) {
@@ -396,11 +389,15 @@ class TrackerResetsHandler(val tracker: Tracker) {
// Add drift time to total
driftTimes[driftTimes.size - 1] = driftTimes.latest + System.currentTimeMillis() - driftSince
totalDriftTime = 0
for (time in driftTimes) { totalDriftTime += time }
for (time in driftTimes) {
totalDriftTime += time
}
// Calculate drift Quaternions' weights
val driftWeights = ArrayList<Float>(driftTimes.size)
for (time in driftTimes) { driftWeights.add(time.toFloat() / totalDriftTime.toFloat()) }
for (time in driftTimes) {
driftWeights.add(time.toFloat() / totalDriftTime.toFloat())
}
// Make it so recent Quaternions weigh more
for (i in driftWeights.size - 1 downTo 1) {

View File

@@ -16,9 +16,7 @@ object TrackerUtils {
fun getTrackerForSkeleton(
allTrackers: List<Tracker>,
position: TrackerPosition,
): Tracker? {
return getNonInternalTrackerForBodyPosition(allTrackers, position)
}
): Tracker? = getNonInternalTrackerForBodyPosition(allTrackers, position)
/**
* Finds the first non-internal tracker from allTrackers

View File

@@ -13,7 +13,7 @@ class FirmwareFeatures {
// Add new flags here
BITS_TOTAL, ;
BITS_TOTAL,
}
fun has(flag: FirmwareFeatureFlags): Boolean {
@@ -50,7 +50,7 @@ enum class ServerFeatureFlags {
companion object {
val flagsEnabled: Set<ServerFeatureFlags> = setOf(
PROTOCOL_BUNDLE_SUPPORT
PROTOCOL_BUNDLE_SUPPORT,
// Add enabled flags here
)

View File

@@ -45,27 +45,25 @@ enum class BoardType(val id: UInt) {
DEV_RESERVED(250u),
;
override fun toString(): String {
return when (this) {
UNKNOWN -> "Unknown"
SLIMEVR_LEGACY -> "SlimeVR Legacy"
SLIMEVR_DEV -> "SlimeVR Dev"
NODEMCU -> "NodeMCU"
CUSTOM -> "Custom Board"
WROOM32 -> "WROOM32"
WEMOSD1MINI -> "Wemos D1 Mini"
TTGO_TBASE -> "TTGO T-Base"
ESP01 -> "ESP-01"
SLIMEVR -> "SlimeVR"
LOLIN_C3_MINI -> "Lolin C3 Mini"
BEETLE32C32 -> "Beetle ESP32-C3"
ES32C3DEVKITM1 -> "Espressif ESP32-C3 DevKitM-1"
OWOTRACK -> "owoTrack"
WRANGLER -> "Wrangler Joycons"
MOCOPI -> "Sony Mocopi"
WEMOSWROOM02 -> "Wemos Wroom-02 D1 Mini"
DEV_RESERVED -> "Prototype"
}
override fun toString(): String = when (this) {
UNKNOWN -> "Unknown"
SLIMEVR_LEGACY -> "SlimeVR Legacy"
SLIMEVR_DEV -> "SlimeVR Dev"
NODEMCU -> "NodeMCU"
CUSTOM -> "Custom Board"
WROOM32 -> "WROOM32"
WEMOSD1MINI -> "Wemos D1 Mini"
TTGO_TBASE -> "TTGO T-Base"
ESP01 -> "ESP-01"
SLIMEVR -> "SlimeVR"
LOLIN_C3_MINI -> "Lolin C3 Mini"
BEETLE32C32 -> "Beetle ESP32-C3"
ES32C3DEVKITM1 -> "Espressif ESP32-C3 DevKitM-1"
OWOTRACK -> "owoTrack"
WRANGLER -> "Wrangler Joycons"
MOCOPI -> "Sony Mocopi"
WEMOSWROOM02 -> "Wemos Wroom-02 D1 Mini"
DEV_RESERVED -> "Prototype"
}
companion object {

View File

@@ -4,6 +4,8 @@ data class SensorTap(val tapBits: Int) {
val doubleTap = tapBits and 0x40 > 0
enum class TapAxis {
X, Y, Z
X,
Y,
Z,
}
}

View File

@@ -26,8 +26,7 @@ import java.util.function.Consumer
/**
* Receives trackers data by UDP using extended owoTrack protocol.
*/
class TrackersUDPServer(private val port: Int, name: String, private val trackersConsumer: Consumer<Tracker>) :
Thread(name) {
class TrackersUDPServer(private val port: Int, name: String, private val trackersConsumer: Consumer<Tracker>) : Thread(name) {
private val random = Random()
private val connections: MutableList<UDPDevice> = FastList()
private val connectionsByAddress: MutableMap<SocketAddress, UDPDevice> = HashMap()
@@ -83,7 +82,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
firmware: ${handshake.firmware} ($firmwareBuild),
mac: ${handshake.macString},
name: $name
""".trimIndent()
""".trimIndent(),
)
} ?: connectionsByAddress[socketAddr]?.apply {
// Look for an existing connection by the socket address (IP and port)
@@ -104,7 +103,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
firmware: ${handshake.firmware} ($firmwareBuild),
mac: ${handshake.macString},
name: $name
""".trimIndent()
""".trimIndent(),
)
}
} ?: run {
@@ -114,7 +113,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
addr,
handshake.macString ?: addr.hostAddress,
handshake.boardType,
handshake.mcuType
handshake.mcuType,
)
VRServer.instance.deviceManager.addDevice(connection)
connection.firmwareBuild = handshake.firmwareBuild
@@ -148,7 +147,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
firmware: ${handshake.firmware} (${connection.firmwareBuild}),
mac: ${handshake.macString},
name: ${connection.name}
""".trimIndent()
""".trimIndent(),
)
}
if (connection.protocol == NetworkProtocol.OWO_LEGACY || connection.firmwareBuild < 9) {
@@ -189,7 +188,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
allowFiltering = true,
needsReset = true,
needsMounting = true,
usesTimeout = true
usesTimeout = true,
)
connection.trackers[trackerId] = imuTracker
trackersConsumer.accept(imuTracker)
@@ -233,7 +232,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
} catch (e: Exception) {
LogManager.warning(
"[TrackerServer] Error parsing packet ${packetToString(received)}",
e
e,
)
}
if (lastKeepup + 500 < System.currentTimeMillis()) {
@@ -298,7 +297,9 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
val tracker: Tracker?
when (packet) {
is UDPPacket0Heartbeat, is UDPPacket1Heartbeat -> {}
is UDPPacket3Handshake -> setUpNewConnection(received, packet)
is RotationPacket -> {
var rot = packet.rotation
rot = AXES_OFFSET.times(rot)
@@ -307,6 +308,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
tracker.setRotation(rot)
tracker.dataTick()
}
is UDPPacket17RotationData -> {
tracker = connection?.getTracker(packet.sensorId)
if (tracker == null) return
@@ -328,13 +330,16 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
}
}
}
is UDPPacket18MagnetometerAccuracy -> {}
is UDPPacket4Acceleration -> {
tracker = connection?.getTracker(packet.sensorId)
if (tracker == null) return
// Switch x and y around to adjust for different axes
tracker.setAcceleration(Vector3(packet.acceleration.y, packet.acceleration.x, packet.acceleration.z))
}
is UDPPacket10PingPong -> {
if (connection == null) return
if (connection.lastPingPacketId == packet.pingId) {
@@ -344,7 +349,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
}
} else {
LogManager.debug(
"[TrackerServer] Wrong ping id ${packet.pingId} != ${connection.lastPingPacketId}"
"[TrackerServer] Wrong ping id ${packet.pingId} != ${connection.lastPingPacketId}",
)
}
}
@@ -363,13 +368,13 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
tracker = connection?.getTracker(packet.sensorId)
if (tracker == null) return
LogManager.info(
"[TrackerServer] Tap packet received from ${tracker.name}: ${packet.tap}"
"[TrackerServer] Tap packet received from ${tracker.name}: ${packet.tap}",
)
}
is UDPPacket14Error -> {
LogManager.severe(
"[TrackerServer] Error received from ${received.socketAddress}: ${packet.errorNumber}"
"[TrackerServer] Error received from ${received.socketAddress}: ${packet.errorNumber}",
)
tracker = connection?.getTracker(packet.sensorId)
if (tracker == null) return
@@ -385,7 +390,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
parser.writeSensorInfoResponse(bb, connection, packet)
socket.send(DatagramPacket(rcvBuffer, bb.position(), connection.address))
LogManager.info(
"[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}"
"[TrackerServer] Sensor info for ${connection.descriptiveName}/${packet.sensorId}: ${packet.sensorStatus}",
)
}
@@ -406,13 +411,13 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
UDPPacket21UserAction.RESET_FULL -> {
name = "Full reset"
VRServer.instance.resetHandler.sendStarted(ResetType.Full)
VRServer.instance.resetTrackersFull(resetSourceName)
VRServer.instance.resetTrackersFull(RESET_SOURCE_NAME)
}
UDPPacket21UserAction.RESET_YAW -> {
name = "Yaw reset"
VRServer.instance.resetHandler.sendStarted(ResetType.Yaw)
VRServer.instance.resetTrackersYaw(resetSourceName)
VRServer.instance.resetTrackersYaw(RESET_SOURCE_NAME)
}
UDPPacket21UserAction.RESET_MOUNTING -> {
@@ -421,17 +426,17 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
.instance
.resetHandler
.sendStarted(ResetType.Mounting)
VRServer.instance.resetTrackersMounting(resetSourceName)
VRServer.instance.resetTrackersMounting(RESET_SOURCE_NAME)
}
UDPPacket21UserAction.PAUSE_TRACKING -> {
name = "Pause tracking toggle"
VRServer.instance.togglePauseTracking(resetSourceName)
VRServer.instance.togglePauseTracking(RESET_SOURCE_NAME)
}
}
LogManager.info(
"[TrackerServer] User action from ${connection.descriptiveName } received. $name performed."
"[TrackerServer] User action from ${connection.descriptiveName } received. $name performed.",
)
}
@@ -449,16 +454,14 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker
}
}
fun getConnections(): List<UDPDevice?> {
return connections
}
fun getConnections(): List<UDPDevice?> = connections
companion object {
/**
* Change between IMU axes and OpenGL/SteamVR axes
*/
private val AXES_OFFSET = fromRotationVector(-FastMath.HALF_PI, 0f, 0f)
private const val resetSourceName = "TrackerServer"
private const val RESET_SOURCE_NAME = "TrackerServer"
private fun packetToString(packet: DatagramPacket?): String {
val sb = StringBuilder()
sb.append("DatagramPacket{")

View File

@@ -61,9 +61,7 @@ class UDPDevice(
return true
}
override fun toString(): String {
return "udp:/$ipAddress"
}
override fun toString(): String = "udp:/$ipAddress"
override var manufacturer: String?
get() = "SlimeVR"
@@ -76,7 +74,5 @@ class UDPDevice(
super.firmwareVersion = firmwareVersion
}
fun getTracker(id: Int): Tracker? {
return trackers[id]
}
fun getTracker(id: Int): Tracker? = trackers[id]
}

View File

@@ -72,9 +72,7 @@ sealed interface SensorSpecificPacket {
* @param sensorId
* @return
*/
fun isGlobal(sensorId: Int): Boolean {
return sensorId == 255
}
fun isGlobal(sensorId: Int): Boolean = sensorId == 255
}
}
@@ -85,7 +83,8 @@ sealed interface RotationPacket : SensorSpecificPacket {
data object UDPPacket0Heartbeat : UDPPacket(0)
data object UDPPacket1Heartbeat : UDPPacket(1)
data class UDPPacket1Rotation(override var rotation: Quaternion = Quaternion.IDENTITY) :
UDPPacket(1), RotationPacket {
UDPPacket(1),
RotationPacket {
override val sensorId = 0
override fun readData(buf: ByteBuffer) {
rotation = UDPUtils.getSafeBufferQuaternion(buf)
@@ -112,7 +111,9 @@ data class UDPPacket3Handshake(
mcuType = MCUType.getById(buf.int.toUInt()) ?: MCUType.UNKNOWN
} // MCU TYPE
if (buf.remaining() > 11) {
buf.int; buf.int; buf.int // IMU info
buf.int
buf.int
buf.int // IMU info
}
if (buf.remaining() > 3) firmwareBuild = buf.int
var length = 0
@@ -130,7 +131,7 @@ data class UDPPacket3Handshake(
mac[2],
mac[3],
mac[4],
mac[5]
mac[5],
)
if (macString == "00:00:00:00:00:00") macString = null
}
@@ -146,7 +147,8 @@ data class UDPPacket3Handshake(
}
data class UDPPacket4Acceleration(var acceleration: Vector3 = Vector3.NULL) :
UDPPacket(4), SensorSpecificPacket {
UDPPacket(4),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
acceleration = Vector3(UDPUtils.getSafeBufferFloat(buf), UDPUtils.getSafeBufferFloat(buf), UDPUtils.getSafeBufferFloat(buf))
@@ -199,7 +201,8 @@ data class UDPPacket12BatteryLevel(
}
data class UDPPacket13Tap(var tap: SensorTap = SensorTap(0)) :
UDPPacket(13), SensorSpecificPacket {
UDPPacket(13),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -208,7 +211,8 @@ data class UDPPacket13Tap(var tap: SensorTap = SensorTap(0)) :
}
data class UDPPacket14Error(var errorNumber: Int = 0) :
UDPPacket(14), SensorSpecificPacket {
UDPPacket(14),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -219,7 +223,8 @@ data class UDPPacket14Error(var errorNumber: Int = 0) :
data class UDPPacket15SensorInfo(
var sensorStatus: Int = 0,
var sensorType: IMUType = IMUType.UNKNOWN,
) : UDPPacket(15), SensorSpecificPacket {
) : UDPPacket(15),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -231,19 +236,18 @@ data class UDPPacket15SensorInfo(
}
companion object {
fun getStatus(sensorStatus: Int): TrackerStatus? {
return when (sensorStatus) {
0 -> TrackerStatus.DISCONNECTED
1 -> TrackerStatus.OK
2 -> TrackerStatus.ERROR
else -> null
}
fun getStatus(sensorStatus: Int): TrackerStatus? = when (sensorStatus) {
0 -> TrackerStatus.DISCONNECTED
1 -> TrackerStatus.OK
2 -> TrackerStatus.ERROR
else -> null
}
}
}
data class UDPPacket16Rotation2(override var rotation: Quaternion = Quaternion.IDENTITY) :
UDPPacket(16), RotationPacket {
UDPPacket(16),
RotationPacket {
override val sensorId = 1
override fun readData(buf: ByteBuffer) {
rotation = UDPUtils.getSafeBufferQuaternion(buf)
@@ -254,7 +258,8 @@ data class UDPPacket17RotationData(
var rotation: Quaternion = Quaternion.IDENTITY,
var dataType: Int = 0,
var calibrationInfo: Int = 0,
) : UDPPacket(17), SensorSpecificPacket {
) : UDPPacket(17),
SensorSpecificPacket {
override var sensorId: Int = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -270,7 +275,8 @@ data class UDPPacket17RotationData(
}
data class UDPPacket18MagnetometerAccuracy(var accuracyInfo: Float = 0.0f) :
UDPPacket(18), SensorSpecificPacket {
UDPPacket(18),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -279,7 +285,8 @@ data class UDPPacket18MagnetometerAccuracy(var accuracyInfo: Float = 0.0f) :
}
data class UDPPacket19SignalStrength(var signalStrength: Int = 0) :
UDPPacket(19), SensorSpecificPacket {
UDPPacket(19),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -288,7 +295,8 @@ data class UDPPacket19SignalStrength(var signalStrength: Int = 0) :
}
data class UDPPacket20Temperature(var temperature: Float = 0.0f) :
UDPPacket(20), SensorSpecificPacket {
UDPPacket(20),
SensorSpecificPacket {
override var sensorId = 0
override fun readData(buf: ByteBuffer) {
sensorId = buf.get().toInt() and 0xFF
@@ -311,8 +319,7 @@ data class UDPPacket21UserAction(var type: Int = 0) : UDPPacket(21) {
class UDPPacket22FeatureFlags(
var firmwareFeatures: FirmwareFeatures = FirmwareFeatures(),
) :
UDPPacket(22) {
) : UDPPacket(22) {
override fun readData(buf: ByteBuffer) {
firmwareFeatures = FirmwareFeatures.from(buf, buf.remaining())
}
@@ -325,8 +332,7 @@ class UDPPacket22FeatureFlags(
data class UDPPacket200ProtocolChange(
var targetProtocol: Int = 0,
var targetProtocolVersion: Int = 0,
) :
UDPPacket(200) {
) : UDPPacket(200) {
override fun readData(buf: ByteBuffer) {
targetProtocol = buf.get().toInt() and 0xFF
targetProtocolVersion = buf.get().toInt() and 0xFF

View File

@@ -13,7 +13,7 @@ class UDPProtocolParser {
if (!connection.isNextPacket(packetNumber)) {
// Skip packet because it's not next
throw IOException(
"Out of order packet received: id $packetId, number $packetNumber, last ${connection.lastPacketNumber}, from $connection"
"Out of order packet received: id $packetId, number $packetNumber, last ${connection.lastPacketNumber}, from $connection",
)
}
connection.lastPacket = System.currentTimeMillis()
@@ -77,28 +77,26 @@ class UDPProtocolParser {
buf.put(packet.sensorStatus.toByte())
}
protected fun getNewPacket(packetId: Int): UDPPacket? {
return when (packetId) {
PACKET_HEARTBEAT -> UDPPacket0Heartbeat
PACKET_ROTATION -> UDPPacket1Rotation()
PACKET_HANDSHAKE -> UDPPacket3Handshake()
PACKET_PING_PONG -> UDPPacket10PingPong()
PACKET_ACCEL -> UDPPacket4Acceleration()
PACKET_SERIAL -> UDPPacket11Serial()
PACKET_BATTERY_LEVEL -> UDPPacket12BatteryLevel()
PACKET_TAP -> UDPPacket13Tap()
PACKET_ERROR -> UDPPacket14Error()
PACKET_SENSOR_INFO -> UDPPacket15SensorInfo()
PACKET_ROTATION_2 -> UDPPacket16Rotation2()
PACKET_ROTATION_DATA -> UDPPacket17RotationData()
PACKET_MAGNETOMETER_ACCURACY -> UDPPacket18MagnetometerAccuracy()
PACKET_SIGNAL_STRENGTH -> UDPPacket19SignalStrength()
PACKET_TEMPERATURE -> UDPPacket20Temperature()
PACKET_USER_ACTION -> UDPPacket21UserAction()
PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags()
PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange()
else -> null
}
protected fun getNewPacket(packetId: Int): UDPPacket? = when (packetId) {
PACKET_HEARTBEAT -> UDPPacket0Heartbeat
PACKET_ROTATION -> UDPPacket1Rotation()
PACKET_HANDSHAKE -> UDPPacket3Handshake()
PACKET_PING_PONG -> UDPPacket10PingPong()
PACKET_ACCEL -> UDPPacket4Acceleration()
PACKET_SERIAL -> UDPPacket11Serial()
PACKET_BATTERY_LEVEL -> UDPPacket12BatteryLevel()
PACKET_TAP -> UDPPacket13Tap()
PACKET_ERROR -> UDPPacket14Error()
PACKET_SENSOR_INFO -> UDPPacket15SensorInfo()
PACKET_ROTATION_2 -> UDPPacket16Rotation2()
PACKET_ROTATION_DATA -> UDPPacket17RotationData()
PACKET_MAGNETOMETER_ACCURACY -> UDPPacket18MagnetometerAccuracy()
PACKET_SIGNAL_STRENGTH -> UDPPacket19SignalStrength()
PACKET_TEMPERATURE -> UDPPacket20Temperature()
PACKET_USER_ACTION -> UDPPacket21UserAction()
PACKET_FEATURE_FLAGS -> UDPPacket22FeatureFlags()
PACKET_PROTOCOL_CHANGE -> UDPPacket200ProtocolChange()
else -> null
}
companion object {

View File

@@ -14,6 +14,7 @@ enum class OperatingSystem(
OSX("osx", arrayOf("mac")),
UNKNOWN("unknown", arrayOf()),
;
companion object {
val currentPlatform: OperatingSystem by lazy {
val osName = System.getProperty("os.name").lowercase(Locale.getDefault())
@@ -46,16 +47,22 @@ enum class OperatingSystem(
fun resolveConfigDirectory(identifier: String): Path? = when (currentPlatform) {
LINUX -> System.getenv("XDG_CONFIG_HOME")?.let { Path(it, identifier) }
?: System.getenv("HOME")?.let { Path(it, ".config", identifier) }
WINDOWS -> System.getenv("AppData")?.let { Path(it, identifier) }
OSX -> System.getenv("HOME")?.let { Path(it, "Library", "Application Support", identifier) }
UNKNOWN -> null
}
fun resolveLogDirectory(identifier: String): Path? = when (currentPlatform) {
LINUX -> System.getenv("XDG_DATA_HOME")?.let { Path(it, identifier, "logs") }
?: System.getenv("HOME")?.let { Path(it, ".local", "share", identifier, "logs") }
WINDOWS -> System.getenv("AppData")?.let { Path(it, identifier, "logs") }
OSX -> System.getenv("HOME")?.let { Path(it, "Library", "Logs", identifier) }
UNKNOWN -> null
}
}

View File

@@ -25,37 +25,42 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
cX * cY * cZ - sX * sY * sZ,
cY * cZ * sX + cX * sY * sZ,
cX * cZ * sY - cY * sX * sZ,
cZ * sX * sY + cX * cY * sZ
cZ * sX * sY + cX * cY * sZ,
)
EulerOrder.YZX -> Quaternion(
cX * cY * cZ - sX * sY * sZ,
cY * cZ * sX + cX * sY * sZ,
cX * cZ * sY + cY * sX * sZ,
cX * cY * sZ - cZ * sX * sY
cX * cY * sZ - cZ * sX * sY,
)
EulerOrder.ZXY -> Quaternion(
cX * cY * cZ - sX * sY * sZ,
cY * cZ * sX - cX * sY * sZ,
cX * cZ * sY + cY * sX * sZ,
cZ * sX * sY + cX * cY * sZ
cZ * sX * sY + cX * cY * sZ,
)
EulerOrder.ZYX -> Quaternion(
cX * cY * cZ + sX * sY * sZ,
cY * cZ * sX - cX * sY * sZ,
cX * cZ * sY + cY * sX * sZ,
cX * cY * sZ - cZ * sX * sY
cX * cY * sZ - cZ * sX * sY,
)
EulerOrder.YXZ -> Quaternion(
cX * cY * cZ + sX * sY * sZ,
cY * cZ * sX + cX * sY * sZ,
cX * cZ * sY - cY * sX * sZ,
cX * cY * sZ - cZ * sX * sY
cX * cY * sZ - cZ * sX * sY,
)
EulerOrder.XZY -> Quaternion(
cX * cY * cZ + sX * sY * sZ,
cY * cZ * sX - cX * sY * sZ,
cX * cZ * sY - cY * sX * sZ,
cZ * sX * sY + cX * cY * sZ
cZ * sX * sY + cX * cY * sZ,
)
}
}
@@ -74,9 +79,9 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
val sY = sin(y)
val sZ = sin(z)
@Suppress("ktlint")
return when (order) {
// ktlint ruining spacing
/* ktlint-disable */
EulerOrder.XYZ -> Matrix3(
cY*cZ , -cY*sZ , sY ,
cZ*sX*sY + cX*sZ , cX*cZ - sX*sY*sZ , -cY*sX ,
@@ -106,7 +111,6 @@ data class EulerAngles(val order: EulerOrder, val x: Float, val y: Float, val z:
cY*cZ , -sZ , cZ*sY ,
sX*sY + cX*cY*sZ , cX*cZ , cX*sY*sZ - cY*sX ,
cY*sX*sZ - cX*sY , cZ*sX , cX*cY + sX*sY*sZ )
/* ktlint-enable */
}
}
}

View File

@@ -1,16 +1,14 @@
@file:Suppress("unused")
@file:Suppress("ktlint", "unused")
package io.github.axisangles.ktmath
import kotlin.math.*
/* ktlint-disable */
data class Matrix3(
val xx: Float, val yx: Float, val zx: Float,
val xy: Float, val yy: Float, val zy: Float,
val xz: Float, val yz: Float, val zz: Float
) {
/* ktlint-enable */
companion object {
val NULL = Matrix3(
0f, 0f, 0f,
@@ -416,4 +414,4 @@ data class Matrix3(
operator fun Float.times(that: Matrix3): Matrix3 = that * this
operator fun Float.div(that: Matrix3): Matrix3 = that.inv() * this
operator fun Float.div(that: Matrix3): Matrix3 = that.inv() * this

View File

@@ -44,11 +44,11 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
* @return Q
**/
fun fromTo(u: Vector3, v: Vector3): Quaternion {
val U = Quaternion(0f, u)
val V = Quaternion(0f, v)
val D = V / U
val u = Quaternion(0f, u)
val v = Quaternion(0f, v)
val d = v / u
return (D + D.len()).unit()
return (d + d.len()).unit()
}
/**
@@ -92,7 +92,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
this.w + that.w,
this.x + that.x,
this.y + that.y,
this.z + that.z
this.z + that.z,
)
operator fun plus(that: Float): Quaternion =
@@ -102,7 +102,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
this.w - that.w,
this.x - that.x,
this.y - that.y,
this.z - that.z
this.z - that.z,
)
operator fun minus(that: Float): Quaternion =
@@ -140,14 +140,14 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
this.w * that,
this.x * that,
this.y * that,
this.z * that
this.z * that,
)
operator fun times(that: Quaternion): Quaternion = Quaternion(
this.w * that.w - this.x * that.x - this.y * that.y - this.z * that.z,
this.x * that.w + this.w * that.x - this.z * that.y + this.y * that.z,
this.y * that.w + this.z * that.x + this.w * that.y - this.x * that.z,
this.z * that.w - this.y * that.x + this.x * that.y + this.w * that.z
this.z * that.w - this.y * that.x + this.x * that.y + this.w * that.z,
)
/**
@@ -160,7 +160,7 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
w / lenSq,
-x / lenSq,
-y / lenSq,
-z / lenSq
-z / lenSq,
)
}
@@ -336,10 +336,10 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
* @return Q
**/
fun align(u: Vector3, v: Vector3): Quaternion {
val U = Quaternion(0f, u)
val V = Quaternion(0f, v)
val u = Quaternion(0f, u)
val v = Quaternion(0f, v)
return (V * this / U + (V / U).len() * this) / 2f
return (v * this / u + (v / u).len() * this) / 2f
}
/**
@@ -379,18 +379,17 @@ data class Quaternion(val w: Float, val x: Float, val y: Float, val z: Float) {
**/
fun toRotationVector(): Vector3 = 2f * twinNearest(IDENTITY).log().xyz
@Suppress("ktlint")
/**
* computes the matrix representing this quaternion's rotation
* @return rotation matrix
**/
fun toMatrix(): Matrix3 {
val d = lenSq()
/* ktlint-disable */
return Matrix3(
(w*w + x*x - y*y - z*z)/d , 2f*(x*y - w*z)/d , 2f*(w*y + x*z)/d ,
2f*(x*y + w*z)/d , (w*w - x*x + y*y - z*z)/d , 2f*(y*z - w*x)/d ,
2f*(x*z - w*y)/d , 2f*(w*x + y*z)/d , (w*w - x*x - y*y + z*z)/d )
/* ktlint-enable */
}
/**

View File

@@ -20,13 +20,13 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
operator fun plus(that: Vector3) = Vector3(
this.x + that.x,
this.y + that.y,
this.z + that.z
this.z + that.z,
)
operator fun minus(that: Vector3) = Vector3(
this.x - that.x,
this.y - that.y,
this.z - that.z
this.z - that.z,
)
/**
@@ -44,13 +44,13 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
infix fun cross(that: Vector3) = Vector3(
this.y * that.z - this.z * that.y,
this.z * that.x - this.x * that.z,
this.x * that.y - this.y * that.x
this.x * that.y - this.y * that.x,
)
infix fun hadamard(that: Vector3) = Vector3(
this.x * that.x,
this.y * that.y,
this.z * that.z
this.z * that.z,
)
/**
@@ -76,14 +76,14 @@ data class Vector3(val x: Float, val y: Float, val z: Float) {
operator fun times(that: Float) = Vector3(
this.x * that,
this.y * that,
this.z * that
this.z * that,
)
// computes division of this vector3 by a float
operator fun div(that: Float) = Vector3(
this.x / that,
this.y / that,
this.z / that
this.z / that,
)
/**

View File

@@ -26,14 +26,14 @@ class ReferenceAdjustmentsTests {
get() = anglesSet
.map { p: AnglesSet ->
DynamicTest.dynamicTest(
"Adjustment Yaw Test of Tracker(${p.pitch},${p.yaw},${p.roll})"
"Adjustment Yaw Test of Tracker(${p.pitch},${p.yaw},${p.roll})",
) {
yaws.forEach {
checkReferenceAdjustmentYaw(
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
0,
it,
0
0,
)
}
}
@@ -44,7 +44,7 @@ class ReferenceAdjustmentsTests {
get() = anglesSet
.map { p: AnglesSet ->
DynamicTest.dynamicTest(
"Adjustment Full Test of Tracker(${p.pitch},${p.yaw},${p.roll})"
"Adjustment Full Test of Tracker(${p.pitch},${p.yaw},${p.roll})",
) {
anglesSet
.forEach {
@@ -52,7 +52,7 @@ class ReferenceAdjustmentsTests {
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
it.pitch,
it.yaw,
it.roll
it.roll,
)
}
}
@@ -66,13 +66,13 @@ class ReferenceAdjustmentsTests {
.flatMap { p: AnglesSet ->
yaws.asSequence().map {
DynamicTest.dynamicTest(
"Adjustment Rotation Test of Tracker(${p.pitch},${p.yaw},${p.roll}), Ref $it"
"Adjustment Rotation Test of Tracker(${p.pitch},${p.yaw},${p.roll}), Ref $it",
) {
testAdjustedTrackerRotation(
q(p.pitch.toFloat(), p.yaw.toFloat(), p.roll.toFloat()),
0,
it,
0
0,
)
}
}.asStream()
@@ -94,7 +94,7 @@ class ReferenceAdjustmentsTests {
hasRotation = true,
isInternal = true,
imuType = IMUType.UNKNOWN,
needsReset = true
needsReset = true,
)
tracker.setRotation(trackerQuat)
tracker.resetsHandler.resetFull(referenceQuat)
@@ -106,7 +106,7 @@ class ReferenceAdjustmentsTests {
Assertions.assertEquals(
QuatEqualFullWithEpsilon(referenceQuat),
QuatEqualFullWithEpsilon(read),
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})"
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})",
)
}
@@ -127,7 +127,7 @@ class ReferenceAdjustmentsTests {
hasRotation = true,
isInternal = true,
imuType = IMUType.UNKNOWN,
needsReset = true
needsReset = true,
)
tracker.setRotation(trackerQuat)
tracker.resetsHandler.resetYaw(referenceQuat)
@@ -136,7 +136,7 @@ class ReferenceAdjustmentsTests {
Assertions.assertEquals(
QuatEqualYawWithEpsilon(referenceQuat),
QuatEqualYawWithEpsilon(read),
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})"
"Adjusted quat is not equal to reference quat (${toDegs(referenceQuat)} vs ${toDegs(read)})",
)
}
@@ -156,7 +156,7 @@ class ReferenceAdjustmentsTests {
hasRotation = true,
isInternal = true,
imuType = IMUType.UNKNOWN,
needsReset = true
needsReset = true,
)
tracker.setRotation(trackerQuat)
tracker.resetsHandler.resetFull(referenceQuat)
@@ -177,13 +177,13 @@ class ReferenceAdjustmentsTests {
EulerOrder.YZX,
pitch * FastMath.DEG_TO_RAD,
yaw * FastMath.DEG_TO_RAD,
roll * FastMath.DEG_TO_RAD
roll * FastMath.DEG_TO_RAD,
).toQuaternion()
val rotationCompare = EulerAngles(
EulerOrder.YZX,
pitch * FastMath.DEG_TO_RAD,
(yaw + refYaw) * FastMath.DEG_TO_RAD,
roll * FastMath.DEG_TO_RAD
roll * FastMath.DEG_TO_RAD,
).toQuaternion()
rotationNode.localTransform.rotation = rotation
rotationNode.update()
@@ -200,7 +200,7 @@ class ReferenceAdjustmentsTests {
FloatMath.equalsToZero(anglesDiff.x) &&
FloatMath.equalsToZero(anglesDiff.y) &&
FloatMath.equalsToZero(anglesDiff.z),
name(yaw, pitch, roll, angles, anglesAdj, anglesDiff)
name(yaw, pitch, roll, angles, anglesAdj, anglesDiff),
)
} else {
if (FloatMath.equalsToZero(anglesDiff.x) &&
@@ -237,7 +237,7 @@ class ReferenceAdjustmentsTests {
EulerOrder.YZX,
degs1.x,
degs1.y + FastMath.TWO_PI,
degs1.z
degs1.z,
)
}
if (degs2.y < -FloatMath.ANGLE_EPSILON_RAD) {
@@ -245,21 +245,17 @@ class ReferenceAdjustmentsTests {
EulerOrder.YZX,
degs2.x,
degs2.y + FastMath.TWO_PI,
degs2.z
degs2.z,
)
}
return FloatMath.equalsWithEpsilon(degs1.y, degs2.y)
}
override fun hashCode(): Int {
return q.hashCode()
}
override fun hashCode(): Int = q.hashCode()
}
data class QuatEqualFullWithEpsilon(val q: Quaternion) {
override fun hashCode(): Int {
return q.hashCode()
}
override fun hashCode(): Int = q.hashCode()
override fun equals(other: Any?): Boolean {
if (other == null) return false
@@ -275,7 +271,7 @@ class ReferenceAdjustmentsTests {
EulerOrder.YZX,
degs1.x,
degs1.y + FastMath.TWO_PI,
degs1.z
degs1.z,
)
}
if (degs2.y < -FloatMath.ANGLE_EPSILON_RAD) {
@@ -283,7 +279,7 @@ class ReferenceAdjustmentsTests {
EulerOrder.YZX,
degs2.x,
degs2.y + FastMath.TWO_PI,
degs2.z
degs2.z,
)
}
return (
@@ -305,8 +301,7 @@ class ReferenceAdjustmentsTests {
val anglesSet: Stream<AnglesSet>
get() = yaws.asSequence()
.zip(pitches.asSequence())
.zip(rolls.asSequence()) {
(yaw, pitch), roll ->
.zip(rolls.asSequence()) { (yaw, pitch), roll ->
AnglesSet(pitch, yaw, roll)
}.asStream()
@@ -317,8 +312,7 @@ class ReferenceAdjustmentsTests {
angles: EulerAngles,
anglesAdj: EulerAngles,
anglesDiff: EulerAngles,
): String {
return """Rot: $yaw/$pitch/$roll.
): String = """Rot: $yaw/$pitch/$roll.
Angles: ${prettyNumber(angles.x * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.x * FastMath.RAD_TO_DEG, 1)},
${prettyNumber(angles.y * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.y * FastMath.RAD_TO_DEG, 1)},
${prettyNumber(angles.z * FastMath.RAD_TO_DEG, 1)}/${prettyNumber(anglesAdj.z * FastMath.RAD_TO_DEG, 1)}.
@@ -326,16 +320,13 @@ class ReferenceAdjustmentsTests {
${prettyNumber(anglesDiff.y * FastMath.RAD_TO_DEG, 1)},
${prettyNumber(anglesDiff.z * FastMath.RAD_TO_DEG, 1)}
""".replace('\n', ' ')
}
fun q(pitch: Float, yaw: Float, roll: Float): Quaternion {
return EulerAngles(
EulerOrder.YZX,
pitch * FastMath.DEG_TO_RAD,
yaw * FastMath.DEG_TO_RAD,
roll * FastMath.DEG_TO_RAD
).toQuaternion()
}
fun q(pitch: Float, yaw: Float, roll: Float): Quaternion = EulerAngles(
EulerOrder.YZX,
pitch * FastMath.DEG_TO_RAD,
yaw * FastMath.DEG_TO_RAD,
roll * FastMath.DEG_TO_RAD,
).toQuaternion()
fun toDegs(q: Quaternion): String {
val (_, x, y, z) = q.toEulerAngles(EulerOrder.YZX)

View File

@@ -201,14 +201,13 @@ class QuaternionTest {
assertEquals(v2, v1)
}
@Suppress("ktlint")
@Test
fun toMatrix() {
/* ktlint-disable */
val m1 = Matrix3(
-1f, 0f, 0f,
0f, -1f, 0f,
0f, 0f, 1f)
/* ktlint-enable */
val m2 = Quaternion(0f, 0f, 0f, 2f).toMatrix()
assertEquals(m1, m2)
}
@@ -262,7 +261,7 @@ class QuaternionTest {
val squareSum = expected.lenSq() + actual.lenSq()
assertTrue(
len <= tolerance * tolerance * squareSum,
"Expected: $expected but got: $actual"
"Expected: $expected but got: $actual",
)
}
}
@@ -274,9 +273,7 @@ fun randInt(): Int {
return randSeed
}
fun randFloat(): Float {
return randInt().toFloat() / 2147483648
}
fun randFloat(): Float = randInt().toFloat() / 2147483648
fun randGaussian(): Float {
var thing = 1f - randFloat()
@@ -287,22 +284,14 @@ fun randGaussian(): Float {
return sqrt(-2f * ln(thing)) * cos(PI.toFloat() * randFloat())
}
fun randMatrix(): Matrix3 {
return Matrix3(
randGaussian(), randGaussian(), randGaussian(),
randGaussian(), randGaussian(), randGaussian(),
randGaussian(), randGaussian(), randGaussian()
)
}
fun randMatrix(): Matrix3 = Matrix3(
randGaussian(), randGaussian(), randGaussian(),
randGaussian(), randGaussian(), randGaussian(),
randGaussian(), randGaussian(), randGaussian(),
)
fun randQuaternion(): Quaternion {
return Quaternion(randGaussian(), randGaussian(), randGaussian(), randGaussian())
}
fun randQuaternion(): Quaternion = Quaternion(randGaussian(), randGaussian(), randGaussian(), randGaussian())
fun randRotMatrix(): Matrix3 {
return randQuaternion().toMatrix()
}
fun randRotMatrix(): Matrix3 = randQuaternion().toMatrix()
fun randVector(): Vector3 {
return Vector3(randGaussian(), randGaussian(), randGaussian())
}
fun randVector(): Vector3 = Vector3(randGaussian(), randGaussian(), randGaussian())

View File

@@ -88,7 +88,7 @@ fun main(args: Array<String>) {
null,
"SlimeVR start-up error! A minimum of Java 17 is required.",
"SlimeVR: Java Runtime Mismatch",
JOptionPane.ERROR_MESSAGE
JOptionPane.ERROR_MESSAGE,
)
LogManager.closeLogger()
return
@@ -102,7 +102,7 @@ fun main(args: Array<String>) {
LogManager
.severe(
"SlimeVR start-up error! Required ports are busy. " +
"Make sure there is no other instance of SlimeVR Server running."
"Make sure there is no other instance of SlimeVR Server running.",
)
JOptionPane
.showMessageDialog(
@@ -110,7 +110,7 @@ fun main(args: Array<String>) {
"SlimeVR start-up error! Required ports are busy. " +
"Make sure there is no other instance of SlimeVR Server running.",
"SlimeVR: Ports are busy",
JOptionPane.ERROR_MESSAGE
JOptionPane.ERROR_MESSAGE,
)
LogManager.closeLogger()
return
@@ -122,13 +122,13 @@ fun main(args: Array<String>) {
::provideSteamVRBridge,
::provideFeederBridge,
{ _ -> DesktopSerialHandler() },
configDir
configDir,
)
vrServer.start()
// Start service for USB HID trackers
TrackersHID(
"Sensors HID service"
"Sensors HID service",
) { tracker: Tracker -> vrServer.registerTracker(tracker) }
Keybinding(vrServer)
@@ -162,7 +162,7 @@ fun provideSteamVRBridge(
"steamvr",
"SteamVR Driver Bridge",
"""\\.\pipe\SlimeVRDriver""",
computedTrackers
computedTrackers,
)
} else if (OperatingSystem.currentPlatform == OperatingSystem.LINUX) {
var linuxBridge: SteamVRBridge? = null
@@ -173,12 +173,12 @@ fun provideSteamVRBridge(
"SteamVR Driver Bridge",
Paths.get(OperatingSystem.socketDirectory, "SlimeVRDriver")
.toString(),
computedTrackers
computedTrackers,
)
} catch (ex: Exception) {
LogManager.severe(
"Failed to initiate Unix socket, disabling driver bridge...",
ex
ex,
)
}
driverBridge = linuxBridge
@@ -191,7 +191,7 @@ fun provideSteamVRBridge(
} catch (e: Exception) {
throw RuntimeException(e)
}
}
},
)
}
} else {
@@ -213,9 +213,10 @@ fun provideFeederBridge(
"steamvr_feeder",
"SteamVR Feeder Bridge",
"""\\.\pipe\SlimeVRInput""",
FastList()
FastList(),
)
}
OperatingSystem.LINUX -> {
feederBridge = UnixSocketBridge(
server,
@@ -223,9 +224,10 @@ fun provideFeederBridge(
"SteamVR Feeder Bridge",
Paths.get(OperatingSystem.socketDirectory, "SlimeVRInput")
.toString(),
FastList()
FastList(),
)
}
else -> {
feederBridge = null
}

View File

@@ -31,7 +31,9 @@ class SerialPortWrapper(val port: SerialPort) : SlimeSerialPort() {
get() = port.productID
}
class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
class DesktopSerialHandler :
SerialHandler(),
SerialPortMessageListener {
private val listeners: MutableList<SerialListener> = CopyOnWriteArrayList()
private val getDevicesTimer = Timer("GetDevicesTimer")
private var currentPort: SerialPort? = null
@@ -52,13 +54,13 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
} catch (t: Throwable) {
LogManager.severe(
"[SerialHandler] Error while watching for new devices, cancelling the \"getDevicesTimer\".",
t
t,
)
getDevicesTimer.cancel()
}
},
0,
3000
3000,
)
}
@@ -92,7 +94,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
}
if (newPort == null) {
LogManager.info(
"[SerialHandler] No serial ports found to connect to (${ports.size}) total ports"
"[SerialHandler] No serial ports found to connect to (${ports.size}) total ports",
)
return false
}
@@ -100,7 +102,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
if (SerialPortWrapper(newPort) != currentPort?.let { SerialPortWrapper(it) }) {
LogManager.info(
"[SerialHandler] Closing current serial port " +
currentPort!!.descriptivePortName
currentPort!!.descriptivePortName,
)
currentPort!!.removeDataListener()
currentPort!!.closePort()
@@ -113,14 +115,14 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
currentPort = newPort
LogManager.info(
"[SerialHandler] Trying to connect to new serial port " +
currentPort!!.descriptivePortName
currentPort!!.descriptivePortName,
)
currentPort?.setBaudRate(115200)
currentPort?.clearRTS()
currentPort?.clearDTR()
if (currentPort?.openPort(1000) == false) {
LogManager.warning(
"[SerialHandler] Can't open serial port ${currentPort?.descriptivePortName}, last error: ${currentPort?.lastErrorCode}"
"[SerialHandler] Can't open serial port ${currentPort?.descriptivePortName}, last error: ${currentPort?.lastErrorCode}",
)
currentPort = null
@@ -154,13 +156,13 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
currentPort?.closePort()
listeners.forEach { it.onSerialDisconnected() }
LogManager.info(
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay"
"[SerialHandler] Port ${currentPort?.descriptivePortName} closed okay",
)
currentPort = null
} catch (e: Exception) {
LogManager.warning(
"[SerialHandler] Error closing port ${currentPort?.descriptivePortName}",
e
e,
)
}
}
@@ -198,12 +200,10 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
listeners.forEach { it.onSerialLog(str) }
}
override fun getListeningEvents(): Int {
return (
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED
or SerialPort.LISTENING_EVENT_DATA_RECEIVED
)
}
override fun getListeningEvents(): Int = (
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED
or SerialPort.LISTENING_EVENT_DATA_RECEIVED
)
override fun serialEvent(event: SerialPortEvent) {
when (event.eventType) {
@@ -212,6 +212,7 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
val s = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(newData)).toString()
addLog(s)
}
SerialPort.LISTENING_EVENT_PORT_DISCONNECTED -> {
closeSerial()
}
@@ -222,13 +223,9 @@ class DesktopSerialHandler : SerialHandler(), SerialPortMessageListener {
override val isConnected: Boolean
get() = currentPort?.isOpen ?: false
override fun getMessageDelimiter(): ByteArray {
return byteArrayOf(0x0A.toByte())
}
override fun getMessageDelimiter(): ByteArray = byteArrayOf(0x0A.toByte())
override fun delimiterIndicatesEndOfMessage(): Boolean {
return true
}
override fun delimiterIndicatesEndOfMessage(): Boolean = true
override val knownPorts: Stream<SerialPortWrapper>
get() = SerialPort.getCommPorts()

View File

@@ -4,7 +4,5 @@ import dev.slimevr.tracking.trackers.Device
import dev.slimevr.tracking.trackers.Tracker
class HIDDevice(val hidId: Int) : Device() {
fun getTracker(id: Int): Tracker? {
return trackers[id]
}
fun getTracker(id: Int): Tracker? = trackers[id]
}

View File

@@ -22,7 +22,9 @@ import kotlin.experimental.and
/**
* Receives trackers data by UDP using extended owoTrack protocol.
*/
class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>) : Thread(name), HidServicesListener {
class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>) :
Thread(name),
HidServicesListener {
private val devices: MutableList<HIDDevice> = mutableListOf()
private val devicesBySerial: MutableMap<String, MutableList<Int>> = HashMap()
private val devicesByHID: MutableMap<HidDevice, MutableList<Int>> = HashMap()
@@ -107,7 +109,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
allowFiltering = true,
needsReset = true,
needsMounting = true,
usesTimeout = false
usesTimeout = false,
)
// usesTimeout false because HID trackers aren't "Disconnected" unless receiver is physically removed probably
// TODO: Could tracker maybe use "Timed out" status without marking as disconnecting?
@@ -116,7 +118,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
imuTracker.status = sensorStatus
LogManager
.info(
"[TrackerServer] Added sensor $trackerId for ${device.name}, type $sensorType"
"[TrackerServer] Added sensor $trackerId for ${device.name}, type $sensorType",
)
}
}
@@ -227,9 +229,7 @@ class TrackersHID(name: String, private val trackersConsumer: Consumer<Tracker>)
override fun run() { // Doesn't seem to run
}
fun getDevices(): List<Device> {
return devices
}
fun getDevices(): List<Device> = devices
override fun hidDeviceAttached(event: HidServicesEvent) {
checkConfigureDevice(event.hidDevice)

View File

@@ -20,6 +20,7 @@ pluginManagement {
val spotlessVersion: String by settings
val shadowJarVersion: String by settings
val buildconfigVersion: String by settings
val grgitVersion: String by settings
plugins {
kotlin("plugin.serialization") version kotlinVersion
kotlin("jvm") version kotlinVersion
@@ -27,6 +28,7 @@ pluginManagement {
id("com.diffplug.spotless") version spotlessVersion
id("com.github.johnrengelman.shadow") version shadowJarVersion
id("com.github.gmazzo.buildconfig") version buildconfigVersion
id("org.ajoberstar.grgit") version grgitVersion
}
}