我正在寻找从IOS插件获取纬度和经度值的信息。下面给出的插件代码是一个.mm文件。
#import "iPhone_Sensors.h"
#import <CoreLocation/CoreLocation.h>
#import <CoreMotion/CoreMotion.h>
#include "iPhone_View.h"
#include "iPhone_OrientationSupport.h"
static bool gCompensateSensors = true;
bool gEnableGyroscope = false;
bool IsCompensatingSensors() { return gCompensateSensors; }
void SetCompensatingSensors(bool val) { gCompensateSensors = val;}
void UnityDidAccelerate(float x, float y, float z, NSTimeInterval timestamp);
struct Vector3f
{
float x, y, z;
};
struct Quaternion4f
{
float x, y, z, w;
};
inline float UnityReorientHeading(float heading)
{
if (IsCompensatingSensors())
{
float rotateBy = 0.f;
switch (UnityCurrentOrientation())
{
case portraitUpsideDown:
rotateBy = -180.f;
break;
case landscapeLeft:
rotateBy = -270.f;
break;
case landscapeRight:
rotateBy = -90.f;
break;
default:
break;
}
return fmodf((360.f + heading + rotateBy), 360.f);
}
else
{
return heading;
}
}
inline Vector3f UnityReorientVector3(float x, float y, float z)
{
if (IsCompensatingSensors())
{
Vector3f res;
switch (UnityCurrentOrientation())
{
case portraitUpsideDown:
{ res = (Vector3f){-x, -y, z}; }
break;
case landscapeLeft:
{ res = (Vector3f){-y, x, z}; }
break;
case landscapeRight:
{ res = (Vector3f){y, -x, z}; }
break;
default:
{ res = (Vector3f){x, y, z}; }
}
return res;
}
else
{
return (Vector3f){x, y, z};
}
}
static Quaternion4f gQuatRot[4] =
{ // { x*sin(theta/2), y*sin(theta/2), z*sin(theta/2), cos(theta/2) }
// => { 0, 0, sin(theta/2), cos(theta/2) } (since <vec> = { 0, 0, +/-1})
{ 0.f, 0.f, 0.f /*sin(0)*/, 1.f /*cos(0)*/}, // ROTATION_0, theta = 0 rad
{ 0.f, 0.f, (float)sqrt(2) * 0.5f /*sin(pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(pi/4)*/}, // ROTATION_90, theta = pi/4 rad
{ 0.f, 0.f, 1.f /*sin(pi/2)*/, 0.f /*cos(pi/2)*/}, // ROTATION_180, theta = pi rad
{ 0.f, 0.f, -(float)sqrt(2) * 0.5f/*sin(3pi/4)*/, -(float)sqrt(2) * 0.5f /*cos(3pi/4)*/} // ROTATION_270, theta = 3pi/2 rad
};
inline void MultQuat(Quaternion4f& result, const Quaternion4f& lhs, const Quaternion4f& rhs)
{
result.x = lhs.w*rhs.x + lhs.x*rhs.w + lhs.y*rhs.z - lhs.z*rhs.y;
result.y = lhs.w*rhs.y + lhs.y*rhs.w + lhs.z*rhs.x - lhs.x*rhs.z;
result.z = lhs.w*rhs.z + lhs.z*rhs.w + lhs.x*rhs.y - lhs.y*rhs.x;
result.w = lhs.w*rhs.w - lhs.x*rhs.x - lhs.y*rhs.y - lhs.z*rhs.z;
}
inline Quaternion4f UnityReorientQuaternion(float x, float y, float z, float w)
{
if (IsCompensatingSensors())
{
Quaternion4f res, inp = {x, y, z, w};
switch (UnityCurrentOrientation())
{
case landscapeLeft:
MultQuat(res, inp, gQuatRot[1]);
break;
case portraitUpsideDown:
MultQuat(res, inp, gQuatRot[2]);
break;
case landscapeRight:
MultQuat(res, inp, gQuatRot[3]);
break;
default:
res = inp;
}
return res;
}
else
{
return (Quaternion4f){x, y, z, w};
}
}
void SetGyroRotationRate(int idx, float x, float y, float z);
void SetGyroRotationRateUnbiased(int idx, float x, float y, float z);
void SetGravity(int idx, float x, float y, float z);
void SetUserAcceleration(int idx, float x, float y, float z);
void SetAttitude(int idx, float x, float y, float z, float w);
static CMMotionManager *sMotionManager = nil;
static NSOperationQueue* sMotionQueue = nil;
// Current update interval or 0.0f if not initialized. This is returned
// to the user as current update interval and this value is set to 0.0f when
// gyroscope is disabled.
static float sUpdateInterval = 0.0f;
// Update interval set by the user. Core motion will be set-up to use
// this update interval after disabling and re-enabling gyroscope
// so users can set update interval, disable gyroscope, enable gyroscope and
// after that gyroscope will be updated at this previously set interval.
static float sUserUpdateInterval = 1.0f / 30.0f;
void SensorsCleanup()
{
if (sMotionManager != nil)
{
[sMotionManager stopGyroUpdates];
[sMotionManager stopDeviceMotionUpdates];
[sMotionManager stopAccelerometerUpdates];
[sMotionManager release];
sMotionManager = nil;
}
if (sMotionQueue != nil)
{
[sMotionQueue release];
sMotionQueue = nil;
}
}
void CoreMotionStart()
{
if (sMotionQueue == nil)
sMotionQueue = [[NSOperationQueue alloc] init];
if (sMotionManager == nil)
{
sMotionManager = [[CMMotionManager alloc] init];
if (sMotionManager.gyroAvailable && gEnableGyroscope)
{
[sMotionManager startGyroUpdates];
[sMotionManager setGyroUpdateInterval: sUpdateInterval];
}
if (sMotionManager.deviceMotionAvailable && gEnableGyroscope)
{
[sMotionManager startDeviceMotionUpdates];
[sMotionManager setDeviceMotionUpdateInterval: sUpdateInterval];
}
if (sMotionManager.accelerometerAvailable)
{
int frequency = UnityGetAccelerometerFrequency();
if (frequency > 0)
{
[sMotionManager startAccelerometerUpdatesToQueue: sMotionQueue withHandler: ^( CMAccelerometerData* data, NSError* error) {
Vector3f res = UnityReorientVector3(data.acceleration.x, data.acceleration.y, data.acceleration.z);
UnityDidAccelerate(res.x, res.y, res.z, data.timestamp);
}];
[sMotionManager setAccelerometerUpdateInterval: 1.0 / frequency];
}
}
}
}
void CoreMotionStop()
{
if (sMotionManager != nil)
{
[sMotionManager stopGyroUpdates];
[sMotionManager stopDeviceMotionUpdates];
}
}
void SetGyroUpdateInterval(int idx, float interval)
{
if (interval < (1.0f / 60.0f))
interval = (1.0f / 60.0f);
else if (interval > (1.0f))
interval = 1.0f;
sUserUpdateInterval = interval;
if (sMotionManager)
{
sUpdateInterval = interval;
[sMotionManager setGyroUpdateInterval: interval];
[sMotionManager setDeviceMotionUpdateInterval: interval];
}
}
float GetGyroUpdateInterval(int idx)
{
return sUpdateInterval;
}
void UpdateGyroData()
{
CMRotationRate rotationRate = { 0.0, 0.0, 0.0 };
CMRotationRate rotationRateUnbiased = { 0.0, 0.0, 0.0 };
CMAcceleration userAcceleration = { 0.0, 0.0, 0.0 };
CMAcceleration gravity = { 0.0, 0.0, 0.0 };
CMQuaternion attitude = { 0.0, 0.0, 0.0, 1.0 };
if (sMotionManager != nil)
{
CMGyroData *gyroData = sMotionManager.gyroData;
CMDeviceMotion *motionData = sMotionManager.deviceMotion;
if (gyroData != nil)
{
rotationRate = gyroData.rotationRate;
}
if (motionData != nil)
{
CMAttitude *att = motionData.attitude;
attitude = att.quaternion;
rotationRateUnbiased = motionData.rotationRate;
userAcceleration = motionData.userAcceleration;
gravity = motionData.gravity;
}
}
Vector3f reorientedRotRate = UnityReorientVector3(rotationRate.x, rotationRate.y, rotationRate.z);
SetGyroRotationRate(0, reorientedRotRate.x, reorientedRotRate.y, reorientedRotRate.z);
Vector3f reorientedRotRateUnbiased = UnityReorientVector3(rotationRateUnbiased.x, rotationRateUnbiased.y, rotationRateUnbiased.z);
SetGyroRotationRateUnbiased(0, reorientedRotRateUnbiased.x, reorientedRotRateUnbiased.y, reorientedRotRateUnbiased.z);
Vector3f reorientedUserAcc = UnityReorientVector3(userAcceleration.x, userAcceleration.y, userAcceleration.z);
SetUserAcceleration(0, reorientedUserAcc.x, reorientedUserAcc.y, reorientedUserAcc.z);
Vector3f reorientedG = UnityReorientVector3(gravity.x, gravity.y, gravity.z);
SetGravity(0, reorientedG.x, reorientedG.y, reorientedG.z);
Quaternion4f reorientedAtt = UnityReorientQuaternion(attitude.x, attitude.y, attitude.z, attitude.w);
SetAttitude(0, reorientedAtt.x, reorientedAtt.y, reorientedAtt.z, reorientedAtt.w);
}
bool IsGyroEnabled(int idx)
{
if (sMotionManager == nil)
return false;
return sMotionManager.gyroAvailable && sMotionManager.gyroActive;
}
bool IsGyroAvailable()
{
if (sMotionManager != nil)
return sMotionManager.gyroAvailable;
return false;
}
@interface LocationServiceDelegate : NSObject <CLLocationManagerDelegate>
@end
void
UnitySetLastLocation(double timestamp,
float latitude,
float longitude,
float altitude,
float horizontalAccuracy,
float verticalAccuracy);
void
UnitySetLastHeading(float magneticHeading,
float trueHeading,
float rawX, float rawY, float rawZ,
double timestamp);
struct LocationServiceInfo
{
private:
LocationServiceDelegate* delegate;
CLLocationManager* locationManager;
public:
LocationServiceStatus locationStatus;
LocationServiceStatus headingStatus;
float desiredAccuracy;
float distanceFilter;
LocationServiceInfo();
CLLocationManager* GetLocationManager();
};
LocationServiceInfo::LocationServiceInfo()
{
locationStatus = kLocationServiceStopped;
desiredAccuracy = kCLLocationAccuracyKilometer;
distanceFilter = 500;
headingStatus = kLocationServiceStopped;
}
static LocationServiceInfo gLocationServiceStatus;
CLLocationManager*
LocationServiceInfo::GetLocationManager()
{
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
delegate = [LocationServiceDelegate alloc];
locationManager.delegate = delegate;
}
return locationManager;
}
bool LocationService::IsServiceEnabledByUser()
{
return [CLLocationManager locationServicesEnabled];
}
void LocationService::SetDesiredAccuracy(float val)
{
gLocationServiceStatus.desiredAccuracy = val;
}
float LocationService::GetDesiredAccuracy()
{
return gLocationServiceStatus.desiredAccuracy;
}
void LocationService::SetDistanceFilter(float val)
{
gLocationServiceStatus.distanceFilter = val;
}
float LocationService::GetDistanceFilter()
{
return gLocationServiceStatus.distanceFilter;
}
void LocationService::StartUpdatingLocation()
{
if (gLocationServiceStatus.locationStatus != kLocationServiceRunning)
{
CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
locationManager.desiredAccuracy = gLocationServiceStatus.desiredAccuracy;
// Set a movement threshold for new events
locationManager.distanceFilter = gLocationServiceStatus.distanceFilter;
[locationManager startUpdatingLocation];
gLocationServiceStatus.locationStatus = kLocationServiceInitializing;
}
}
void LocationService::StopUpdatingLocation()
{
if (gLocationServiceStatus.locationStatus == kLocationServiceRunning)
{
[gLocationServiceStatus.GetLocationManager() stopUpdatingLocation];
gLocationServiceStatus.locationStatus = kLocationServiceStopped;
}
}
void LocationService::SetHeadingUpdatesEnabled(bool enabled)
{
if (enabled)
{
if (gLocationServiceStatus.headingStatus != kLocationServiceRunning &&
IsHeadingAvailable())
{
CLLocationManager* locationManager = gLocationServiceStatus.GetLocationManager();
[locationManager startUpdatingHeading];
gLocationServiceStatus.headingStatus = kLocationServiceInitializing;
}
}
else
{
if(gLocationServiceStatus.headingStatus == kLocationServiceRunning)
{
[gLocationServiceStatus.GetLocationManager() stopUpdatingHeading];
gLocationServiceStatus.headingStatus = kLocationServiceStopped;
}
}
}
bool LocationService::IsHeadingUpdatesEnabled()
{
return (gLocationServiceStatus.headingStatus == kLocationServiceRunning);
}
int UnityGetLocationStatus()
{
return gLocationServiceStatus.locationStatus;
}
int UnityGetHeadingStatus()
{
return gLocationServiceStatus.headingStatus;
}
bool LocationService::IsHeadingAvailable()
{
return [CLLocationManager headingAvailable];
}
@implementation LocationServiceDelegate
// Delegate method from the CLLocationManagerDelegate protocol.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
gLocationServiceStatus.locationStatus = kLocationServiceRunning;
UnitySetLastLocation([newLocation.timestamp timeIntervalSince1970],
newLocation.coordinate.latitude,
newLocation.coordinate.longitude,
newLocation.altitude,
newLocation.horizontalAccuracy,
newLocation.verticalAccuracy);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
gLocationServiceStatus.headingStatus = kLocationServiceRunning;
Vector3f reorientedRawHeading = UnityReorientVector3(newHeading.x, newHeading.y, newHeading.z);
UnitySetLastHeading(UnityReorientHeading(newHeading.magneticHeading),
UnityReorientHeading(newHeading.trueHeading),
reorientedRawHeading.x, reorientedRawHeading.y, reorientedRawHeading.z,
[newHeading.timestamp timeIntervalSince1970]);
}
- (BOOL)locationManagerShouldDisplayHeadingCalibration:(CLLocationManager *)manager
{
return NO;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
{
gLocationServiceStatus.locationStatus = kLocationServiceFailed;
gLocationServiceStatus.headingStatus = kLocationServiceFailed;
}
@end
我点击了此链接,从插件中提取了所需的值,但无法理解其工作原理。Plugin into unity
下面的代码是我尝试从插件获取经度和纬度的方法。我编写了一个脚本并添加了一个方法
public class Getposition : MonoBehaviour {
#if UNITY_IOS
[DllImport("__Internal")]
********* // Here Which Method should I call?? I am calling from the plugin??
//I have to pass any values?? //*********
private static extern float UnitySetLastHeading(double timestamp,
float latitude,
float longitude,
float altitude,
float horizontalAccuracy,
float verticalAccuracy);
#endif
}
public getlatlonginfo( /*what all values required */)
{
//Get values from Plugin??
//string latitudevalues=?
//string longitudevalues=?
}
我要达到的目标在下面
获取在iPhone_Sensors.mm中拾取的值,将其转换为字符串,然后将其传递给Unity
我正在尝试将它们转换为字符串,以便获得更多的小数点,从而提高准确性。不是那个有插件的专家。
答案 0 :(得分:1)
我可以想到两种方法。第一种是使用结构并直接返回坐标。第二种是在位置更新时注册回调/处理程序。您应该真正了解一下:https://www.mono-project.com/docs/advanced/pinvoke/
无论如何..一些代码:
C ++方面:
//Convert a C++ string to NSString
NSString* CPPStringToIOSString(const char* cppString)
{
return cppString ? [NSString stringWithUTF8String:cppString] : nullptr;
}
//Convert an NSString to C++ string.
const char* IOSStringToCPPString(NSString *iosString)
{
if ([iosString length])
{
const char* str = [iosString UTF8String];
if (str && strlen(str))
{
char* unityString = static_cast<char*>(malloc(strlen(str) + 1));
strcpy(unityString, str);
return unityString;
}
}
return nullptr;
}
static LocationServiceInfo GetLocationServiceInfo()
{
static LocationServiceInfo info;
return info;
}
//Exports:
extern "C" {
//When called, returns a CLLocationCoordinate2D to Unity.
CLLocationCoordinate2D _GetCoordinates()
{
CLLocationManager *manager = GetLocationServiceInfo().GetLocationManager();
return [manager getCurrentLocation];
}
//When called, registers a listen with LocationManager.
//The listener is called whenever the location has updated/changed.
void _RegisterLocationUpdateHandler(void(*callback)(double, double))
{
//Implement your own logic for this..
//Then call `callback` with the lat and lon.
GetLocationServiceInfo().onLocationDidUpdate = ^(double lat, double lon) {
if (callback) {
callback(lat, lon);
}
};
}
}
C#侧(插头)。
//Struct representing coordinates received from the iOS plugin.
public struct CLLocationCoordinate2D {
double latitude;
double longitude;
}
//Imported function.
[DllImport ("__Internal")]
private static extern CLLocationCoordinate2D _GetCoordinates();
//Call the imported `GetCoordinates` when this function is called.
public static CLLocationCoordinate2D GetCoordinates()
{
return _GetCoordinates();
}
//------ Async ------
//Callback function pointer declaration..
public delegate void LocationCallbackFunc(double latitude, double longitude);
//Imported RegisterLocationUpdate function
[DllImport ("__Internal")]
private static extern void _RegisterLocationUpdateHandler(LocationCallback funcPtr);
//This function is called whenever location changed and has been updated via the iOS plugin..
private static void LocationDidChange(double latitude, double longitude)
{
Debug.Log(latitude);
Debug.Log(longitude);
}
//Call this function to register the location handler callback to be notified when location changes on the iOS side..
private static void RegisterLocationUpdateHandler()
{
_RegisterLocationUpdateHandler(new LocationCallbackFunc(this.LocationDidChange))
}