minor fixes
This commit is contained in:
parent
c58696f1c8
commit
d5902cba08
|
|
@ -59,38 +59,41 @@ class DefaultOrientationChecker : OrientationChecker {
|
||||||
/* ============================================================= */
|
/* ============================================================= */
|
||||||
|
|
||||||
class DefaultTiltChecker : TiltChecker {
|
class DefaultTiltChecker : TiltChecker {
|
||||||
|
|
||||||
override suspend fun analyze(input: PipelineInput): Instruction {
|
override suspend fun analyze(input: PipelineInput): Instruction {
|
||||||
|
|
||||||
val tolerance = 25f
|
val tolerance = 20f
|
||||||
var levelMessage = "Keep the phone straight"
|
|
||||||
|
|
||||||
Log.d("TiltChecker", "Device Roll: ${input.deviceRoll}, Device Pitch: ${input.devicePitch}, Device Azimuth: ${input.deviceAzimuth}")
|
val (targetPitch, targetRoll) = Pair(-90f, 0f)
|
||||||
|
|
||||||
|
Log.d("TiltCheckerMessage", "targetPitch: ${input.devicePitch}, targetRoll: ${input.deviceRoll}, targetAz: ${input.deviceAzimuth}, tP: $targetPitch, tR: $targetRoll")
|
||||||
|
val pitchError = abs(input.devicePitch - targetPitch)
|
||||||
|
val rollError = abs(input.deviceRoll - targetRoll)
|
||||||
|
|
||||||
val isLevel = when (input.requiredOrientation) {
|
val isLevel = pitchError <= tolerance && rollError <= tolerance && input.deviceAzimuth > 0
|
||||||
CameraOrientation.PORTRAIT ->
|
val isRollError = rollError > tolerance
|
||||||
abs(input.devicePitch + 90f) <= tolerance
|
val isPitchError = pitchError > tolerance
|
||||||
CameraOrientation.LANDSCAPE ->
|
|
||||||
abs(input.devicePitch) <= tolerance
|
|
||||||
}
|
|
||||||
|
|
||||||
val standardPitch = when (input.requiredOrientation) {
|
val message = if (isLevel) {
|
||||||
CameraOrientation.PORTRAIT -> -90f
|
"Device is level"
|
||||||
CameraOrientation.LANDSCAPE -> 0f
|
} else {
|
||||||
}
|
when {
|
||||||
|
input.deviceAzimuth < 0 -> "Tilt phone forward"
|
||||||
if (!isLevel) {
|
input.deviceAzimuth >= 0 && !isRollError && isPitchError -> "Tilt phone backward"
|
||||||
if (input.devicePitch > standardPitch) {
|
input.deviceRoll > 0 -> "Rotate phone left"
|
||||||
levelMessage = "Rotate the phone Right"
|
input.deviceRoll <= 0 -> "Rotate phone right"
|
||||||
} else if (input.devicePitch < standardPitch) {
|
else -> "Device is level"
|
||||||
levelMessage = "Rotate the phone Left"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Instruction(
|
return Instruction(
|
||||||
message = if (isLevel) "Device is level" else levelMessage,
|
message = message,
|
||||||
isValid = isLevel,
|
isValid = isLevel,
|
||||||
result = TiltResult(input.deviceRoll, input.devicePitch, isLevel)
|
result = TiltResult(
|
||||||
|
roll = input.deviceRoll,
|
||||||
|
pitch = input.devicePitch,
|
||||||
|
isLevel = isLevel
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@ fun AddProfileScreen(
|
||||||
// If opened for edit, attempt to load existing animal details
|
// If opened for edit, attempt to load existing animal details
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val existing = viewModel.savedStateHandle?.get<String>("animalId")
|
val existing = viewModel.savedStateHandle?.get<String>("animalId")
|
||||||
if (existing != null) viewModel.loadAnimal(existing)
|
val loadEntry = viewModel.savedStateHandle?.get<Boolean>("loadEntry")
|
||||||
|
if (existing != null && loadEntry == true) viewModel.loadAnimal(existing)
|
||||||
}
|
}
|
||||||
|
|
||||||
val speciesList = stringArrayResource(id = R.array.species_list).toList()
|
val speciesList = stringArrayResource(id = R.array.species_list).toList()
|
||||||
|
|
|
||||||
|
|
@ -134,6 +134,9 @@ fun CameraCaptureScreen(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
// This screen can be called from AddProfileScreen or ViewImageScreen (for retakes).
|
||||||
|
// In both cases, we pop the back stack and set the result on the previous entry.
|
||||||
|
// The NavGraph logic for each screen handles the received URI accordingly.
|
||||||
navController.previousBackStackEntry?.savedStateHandle?.set("newImageUri", uri.toString())
|
navController.previousBackStackEntry?.savedStateHandle?.set("newImageUri", uri.toString())
|
||||||
navController.previousBackStackEntry?.savedStateHandle?.set("newImageOrientation", orientation)
|
navController.previousBackStackEntry?.savedStateHandle?.set("newImageOrientation", orientation)
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,7 @@ fun NavGraph(
|
||||||
|
|
||||||
composable<Route.ViewImageScreen> { backStackEntry ->
|
composable<Route.ViewImageScreen> { backStackEntry ->
|
||||||
val args: Route.ViewImageScreen = backStackEntry.toRoute()
|
val args: Route.ViewImageScreen = backStackEntry.toRoute()
|
||||||
|
|
||||||
ViewImageScreen(
|
ViewImageScreen(
|
||||||
imageUri = args.imageUri,
|
imageUri = args.imageUri,
|
||||||
shouldAllowRetake = args.shouldAllowRetake,
|
shouldAllowRetake = args.shouldAllowRetake,
|
||||||
|
|
@ -160,7 +161,7 @@ fun NavGraph(
|
||||||
orientation = args.orientation,
|
orientation = args.orientation,
|
||||||
onRetake = {
|
onRetake = {
|
||||||
navController.popBackStack()
|
navController.popBackStack()
|
||||||
// navController.navigate(Route.CameraScreen(...))
|
args.orientation?.let { navController.navigate(Route.CameraScreen(orientation = it, animalId = args.animalId)) }
|
||||||
},
|
},
|
||||||
onAccept = { uri ->
|
onAccept = { uri ->
|
||||||
// If it's a segmented result, add to segmented list
|
// If it's a segmented result, add to segmented list
|
||||||
|
|
|
||||||
|
|
@ -14,33 +14,29 @@ class TiltSensorManager(
|
||||||
context: Context
|
context: Context
|
||||||
) : SensorEventListener {
|
) : SensorEventListener {
|
||||||
|
|
||||||
private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
private val sensorManager =
|
||||||
private val rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
|
context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||||
|
|
||||||
|
private val windowManager =
|
||||||
|
context.getSystemService(Context.WINDOW_SERVICE) as android.view.WindowManager
|
||||||
|
|
||||||
|
private val rotationVectorSensor =
|
||||||
|
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
|
||||||
|
|
||||||
private val _tilt = MutableStateFlow(Triple(0f, 0f, 0f)) // pitch, roll, azimuth
|
private val _tilt = MutableStateFlow(Triple(0f, 0f, 0f)) // pitch, roll, azimuth
|
||||||
val tilt: StateFlow<Triple<Float, Float, Float>> = _tilt.asStateFlow()
|
val tilt: StateFlow<Triple<Float, Float, Float>> = _tilt.asStateFlow()
|
||||||
|
|
||||||
init {
|
|
||||||
Log.d("TiltSensorManager", "TiltSensorManager initialized.")
|
|
||||||
if (rotationVectorSensor == null) {
|
|
||||||
Log.e("TiltSensorManager", "Rotation Vector Sensor not available on this device.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun start() {
|
fun start() {
|
||||||
Log.d("TiltSensorManager", "start() called.")
|
|
||||||
rotationVectorSensor?.let {
|
rotationVectorSensor?.let {
|
||||||
val registered = sensorManager.registerListener(
|
sensorManager.registerListener(
|
||||||
this,
|
this,
|
||||||
it,
|
it,
|
||||||
SensorManager.SENSOR_DELAY_UI
|
SensorManager.SENSOR_DELAY_UI
|
||||||
)
|
)
|
||||||
Log.d("TiltSensorManager", "Listener registration attempted. Success: $registered")
|
}
|
||||||
} ?: Log.e("TiltSensorManager", "Cannot start listener, sensor is null.")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stop() {
|
fun stop() {
|
||||||
Log.d("TiltSensorManager", "stop() called.")
|
|
||||||
sensorManager.unregisterListener(this)
|
sensorManager.unregisterListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,25 +45,64 @@ class TiltSensorManager(
|
||||||
if (event.sensor.type != Sensor.TYPE_ROTATION_VECTOR) return
|
if (event.sensor.type != Sensor.TYPE_ROTATION_VECTOR) return
|
||||||
|
|
||||||
val rotationMatrix = FloatArray(9)
|
val rotationMatrix = FloatArray(9)
|
||||||
|
val adjustedMatrix = FloatArray(9)
|
||||||
val orientationAngles = FloatArray(3)
|
val orientationAngles = FloatArray(3)
|
||||||
|
|
||||||
// Convert rotation vector to rotation matrix
|
|
||||||
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)
|
SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values)
|
||||||
|
|
||||||
// Convert rotation matrix to orientation angles
|
// 🔑 Get screen rotation
|
||||||
SensorManager.getOrientation(rotationMatrix, orientationAngles)
|
val rotation = windowManager.defaultDisplay.rotation
|
||||||
|
|
||||||
|
when (rotation) {
|
||||||
|
android.view.Surface.ROTATION_0 -> {
|
||||||
|
SensorManager.remapCoordinateSystem(
|
||||||
|
rotationMatrix,
|
||||||
|
SensorManager.AXIS_X,
|
||||||
|
SensorManager.AXIS_Y,
|
||||||
|
adjustedMatrix
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
android.view.Surface.ROTATION_90 -> {
|
||||||
|
SensorManager.remapCoordinateSystem(
|
||||||
|
rotationMatrix,
|
||||||
|
SensorManager.AXIS_Y,
|
||||||
|
SensorManager.AXIS_MINUS_X,
|
||||||
|
adjustedMatrix
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
android.view.Surface.ROTATION_180 -> {
|
||||||
|
SensorManager.remapCoordinateSystem(
|
||||||
|
rotationMatrix,
|
||||||
|
SensorManager.AXIS_MINUS_X,
|
||||||
|
SensorManager.AXIS_MINUS_Y,
|
||||||
|
adjustedMatrix
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
android.view.Surface.ROTATION_270 -> {
|
||||||
|
SensorManager.remapCoordinateSystem(
|
||||||
|
rotationMatrix,
|
||||||
|
SensorManager.AXIS_MINUS_Y,
|
||||||
|
SensorManager.AXIS_X,
|
||||||
|
adjustedMatrix
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorManager.getOrientation(adjustedMatrix, orientationAngles)
|
||||||
|
|
||||||
// orientationAngles: [azimuth, pitch, roll] in radians
|
|
||||||
val azimuth = Math.toDegrees(orientationAngles[0].toDouble()).toFloat()
|
val azimuth = Math.toDegrees(orientationAngles[0].toDouble()).toFloat()
|
||||||
val pitch = Math.toDegrees(orientationAngles[1].toDouble()).toFloat()
|
val pitch = Math.toDegrees(orientationAngles[1].toDouble()).toFloat()
|
||||||
val roll = Math.toDegrees(orientationAngles[2].toDouble()).toFloat()
|
val roll = Math.toDegrees(orientationAngles[2].toDouble()).toFloat()
|
||||||
|
|
||||||
Log.d("TiltSensor", "Pitch: $pitch, Roll: $roll, Azimuth: $azimuth")
|
|
||||||
|
|
||||||
_tilt.value = Triple(pitch, roll, azimuth)
|
_tilt.value = Triple(pitch, roll, azimuth)
|
||||||
|
|
||||||
|
Log.d("TiltSensor",
|
||||||
|
"Standardized → Pitch=$pitch Roll=$roll Azimuth=$azimuth"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||||
Log.d("TiltSensorManager", "Accuracy changed to $accuracy for sensor ${sensor?.name}")
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue