问题
I need to get the direction of the front facing camera excluding the devices orientation (landscape/portrait). I tried to represent this using Core Motion and accessing device attitude. Here I tried to access the Euler angles and exclude the yaw, however this doesn't seem to work as when rotating the device more that one Euler angle value changes. I am also considering using the orientation quaternion but I don't have experience using them. I need this information in a serialisable manner as I would later need to determine if a different device has it's camera pointed in the same direction ( this device may be either iOS or Android).
To reiterate: if a user is pointing his phone camera (main camera not selfie one) towards the statue of liberty, what would be the best way to encode this information regardless if the user is holding the phone in portrait or landscape, such that if another user is in the same location he would know the direction in which to point his camera?
回答1:
I believe that in order to achieve this, you can use CLLocation
.
As you main objective is to find the cardinal point towards which the phone points, you can do things like:
fun locationManager(_ manager: CLLocationManager, didUpdateHeading heading: CLHeading) {
let angle = newHeading.trueHeading.toRadians // convert from degrees to radians
// do what you please with this information
}
As stated in this tutorial:
The trueHeading is the angle between that vector and the vector starting from the same point but pointing towards the true north. If your phone points exactly to the True North you’ll get a heading of 0 (zero) degrees, if it points towards East you’ll get 90 degrees etc.
Now, as stated here, the device orientation can cause some trouble:
Unfortunately, if the user orientates the device into Landscape Mode, the reported headings will be incorrect, or at least look incorrect to the user. This will become especially important when you look at augmented reality interfaces later in the book; such interfaces are generally viewed in Landscape Left mode.
BUT! There is a solution for this problem:
And you can use something like this to retrieve the heading you are looking for:
-(float)magneticHeading:(float)heading
fromOrientation:(UIDeviceOrientation) orientation {
float realHeading = heading;
switch (orientation) {1
case UIDeviceOrientationPortrait:
break;
case UIDeviceOrientationPortraitUpsideDown:
realHeading = realHeading + 180.0f;
break;
case UIDeviceOrientationLandscapeLeft:
realHeading = realHeading + 90.0f;
break;
case UIDeviceOrientationLandscapeRight:
realHeading = realHeading - 90.0f;
break;
default:
break;
}
while ( realHeading > 360.0f ) {
realHeading = realHeading - 360;
}
return realHeading;
}
Sorry about the different languages (Swift - Objective C), but in order to fully understand the problem and find a complete solution I would recommend to read into the sources:
- Medium Compass Tutorial
- O'Reilly's Compass Tutorial
Hope this helps! Let me know.
回答2:
There is 4 type of them. one is deprecated:
- public static final int ORIENTATION_UNDEFINED = 0;
- public static final int ORIENTATION_PORTRAIT = 1;
- public static final int ORIENTATION_LANDSCAPE = 2:
- @Deprecated public static final int ORIENTATION_SQUARE = 3;
You can learn with
val orientation: Int = resources.configuration.orientation
If you want to learn specific angle and position you should use Sensor service with this.sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
and for exact position
sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)?.let { this.rotationVector = it}
this class also has different features like.
TYPE_ACCELEROMETER
Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), including the force of gravity.
Motion detection (shake, tilt, etc.).
TYPE_GRAVITY
Measures the force of gravity in m/s2 that is applied to a device on all three physical axes (x, y, z).
Motion detection (shake, tilt, etc.).
TYPE_GYROSCOPE
Measures a device’s rate of rotation in rad/s around each of the three physical axes (x, y, and z).
Rotation detection (spin, turn, etc.).
TYPE_LINEAR_ACCELERATION
Measures the acceleration force in m/s2 that is applied to a device on all three physical axes (x, y, and z), without the force of gravity.
Monitoring acceleration along a single axis.
TYPE_ROTATION_VECTOR
Measures the orientation of a device by providing the three elements of the device’s rotation vector.
Motion detection and rotation detection.
回答3:
In android, I use setRotation() method to rotted the camera.
setRotation(camera, parameters, requestedCameraId);
private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {
WindowManager windowManager =
(WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
int degrees = 0;
//get current display rotation
int rotation = windowManager.getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
default:
Log.e(TAG, "Bad rotation value: " + rotation);
}
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
int angle;
int displayAngle;
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
angle = (cameraInfo.orientation + degrees) % 360;
displayAngle = (360 - angle) % 360; // compensate for it being mirrored
} else { // back-facing
angle = (cameraInfo.orientation - degrees + 360) % 360;
displayAngle = angle;
}
// This corresponds to the rotation constants.
// mRotation = angle / 90;
camera.setDisplayOrientation(displayAngle);
parameters.setRotation(angle);
}
I hope this is work for you.
来源:https://stackoverflow.com/questions/60507826/device-camera-direction-excluding-device-landscape-portrait-orientation