using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; using UnityEngine; using UnityEngine.Networking; using System.Net; using System.Threading; namespace Seengene.XDKUnityPluginCloud { public delegate void AuthorizationResponseHandler(AuthorizationResponse response); public delegate void RelocationResponseHandler(RelocationResponse response); public class XDKCloudInterface : MonoBehaviour { private const string k_DefaultAuthorizationAPIAddress = "http://124.70.37.47:80/requestMap"; private const string k_DefaultRelocationAPIAddress = "http://124.70.37.47:80/relocalize"; [SerializeField] private string m_AuthorizationAPIAddress = k_DefaultAuthorizationAPIAddress; [SerializeField] private string m_RelocationAPIAddress = k_DefaultRelocationAPIAddress; [SerializeField] private string m_MapId = ""; string k_FieldNameServerFlag = "ServerFlag"; int m_ServerFlag = 0; public event AuthorizationResponseHandler OnAuthorized; public event RelocationResponseHandler OnRelocated; bool m_IsUploadingImage = false; Thread m_ThreadUploadImage = null; List m_UploadImageList = new List(); private void Awake() { m_ServerFlag = UnityEngine.Random.Range(1, 1000); if (string.IsNullOrEmpty(XDKConfigs.AuthorizationAPIAddress)) { XDKConfigs.AuthorizationAPIAddress = m_AuthorizationAPIAddress; } if (string.IsNullOrEmpty(XDKConfigs.RelocationAPIAddress)) { XDKConfigs.RelocationAPIAddress = m_RelocationAPIAddress; } if (string.IsNullOrEmpty(XDKConfigs.MapId)) { XDKConfigs.MapId = m_MapId; } } private void Start() { try { m_IsUploadingImage = true; m_ThreadUploadImage = new Thread(RelocUploadImageThread); m_ThreadUploadImage.IsBackground = true; m_ThreadUploadImage.Start(); Debug.Log("开始线程 RelocUploadingImageThread 成功"); } catch (Exception e) { Debug.LogErrorFormat("开始线程 RelocUploadingImageThread 失败: {0}", e.Message); } } private void OnDestroy() { try { m_IsUploadingImage = false; if (m_ThreadUploadImage != null) m_ThreadUploadImage.Abort(); Debug.Log("结束线程 RelocUploadingImageThread 成功"); } catch (Exception e) { Debug.LogErrorFormat("结束线程 RelocUploadingImageThread 失败:{0}", e.Message); } XDKConfigs.SetDefault(); } public void Authorize() { StartCoroutine(AuthorizeAsync(XDKConfigs.MapId)); } public void Relocate(string sessionID, Int32 seq, Matrix4x4 cameraPose, CameraCalibration cameraCalibration, byte[] imageBytes) { RelocUploadImageItem item = new RelocUploadImageItem(sessionID, seq, cameraPose, cameraCalibration, imageBytes); m_UploadImageList.Add(item); } IEnumerator AuthorizeAsync(string mapId) { byte[] myData; using (MemoryStream mMemStream = new MemoryStream()) { using (BinaryWriter mBinaryWriter = new BinaryWriter(mMemStream, Encoding.ASCII)) { mBinaryWriter.Write(RequestMapKeys.RequestType_MapId); byte[] bytesMapId = System.Text.Encoding.ASCII.GetBytes(mapId); mBinaryWriter.Write(bytesMapId.Length); mBinaryWriter.Write(bytesMapId); myData = mMemStream.ToArray(); } } UnityWebRequest webRequest = new UnityWebRequest(XDKConfigs.AuthorizationAPIAddress, UnityWebRequest.kHttpVerbPOST); webRequest.SetRequestHeader(k_FieldNameServerFlag, m_ServerFlag.ToString()); UploadHandler uploader = new UploadHandlerRaw(myData); DownloadHandler downloadHandler = new DownloadHandlerBuffer(); webRequest.downloadHandler = downloadHandler; webRequest.uploadHandler = uploader; webRequest.uploadHandler.contentType = "application/json"; webRequest.timeout = 30; long startTicks = DateTime.Now.Ticks / 10000; if (XDKConfigs.IfLogOn) { Debug.LogFormat("Start To Authorize(RequestSessionID) ... MapID:{0}; {1}:{2};startTime:{3},{4}ms", mapId, k_FieldNameServerFlag, webRequest.GetRequestHeader(k_FieldNameServerFlag), DateTime.Now, startTicks); } yield return webRequest.SendWebRequest(); if (webRequest.isNetworkError || webRequest.isHttpError) { Debug.LogErrorFormat("{0}, {1}", webRequest.error, webRequest.url); } else { long endTicks = DateTime.Now.Ticks / 10000; string msgInfo = ""; switch (webRequest.responseCode) { case 200: msgInfo = "获取SessionID成功"; break; case 400: msgInfo = "参数错误"; break; case 404: msgInfo = "地图不存在"; break; case 500: msgInfo = "内部服务器错误"; break; case 503: msgInfo = "服务器忙,请稍后再试"; break; default: msgInfo = "其它错误"; break; } if (webRequest.responseCode == 200) { if (XDKConfigs.IfLogOn) { Debug.LogFormat("Request SessionID: {0}, code:{1}; endTime:{2},{3}ms; delay:{4}ms", msgInfo, webRequest.responseCode, DateTime.Now, endTicks, endTicks - startTicks); } ParseAuthorizationResponse(webRequest.downloadHandler.data); } else { if (XDKConfigs.IfLogOn) { Debug.LogErrorFormat("Request SessionID: {0}, code:{1}; endTime:{2},{3}ms; delay:{4}ms", msgInfo, webRequest.responseCode, DateTime.Now, endTicks, endTicks - startTicks); } } } } private void ParseAuthorizationResponse(byte[] buffer) { Int32 status = 0; string sessionID = string.Empty; double scale = 0; using (MemoryStream mMemStream = new MemoryStream(buffer)) { using (BinaryReader mBinaryReader = new BinaryReader(mMemStream, Encoding.ASCII)) { while (mBinaryReader.BaseStream.Position < buffer.Length) { byte type = mBinaryReader.ReadByte(); int len = mBinaryReader.ReadInt32(); switch (type) { case RequestMapKeys.ResponseType_SessionId: byte[] bytes = mBinaryReader.ReadBytes(len); System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); sessionID = encoding.GetString(bytes); break; case RequestMapKeys.ResponseType_Status: status = mBinaryReader.ReadInt32(); break; case RequestMapKeys.ResponseType_Scale: scale = mBinaryReader.ReadDouble(); break; default: break; } } } } if (XDKConfigs.IfLogOn) { Debug.LogFormat("ParseAuthorizationResponse Success, status:{0}; scale:{1}; sessionID:{2}", status, scale, sessionID); } AuthorizationResponse response = new AuthorizationResponse(status, scale, sessionID); OnAuthorized?.Invoke(response); } private void ParseRelocationResponse(byte[] buffer, Matrix4x4 cameraPos, CameraCalibration cameraCalibration, string sessionID) { Int32 status = 0; Int32 seq = 0; List point2d_vec = new List(); List point3d_vec = new List(); List transform_ltg = new List(); string extra_msg = string.Empty; using (MemoryStream mMemStream = new MemoryStream(buffer)) { using (BinaryReader mBinaryReader = new BinaryReader(mMemStream, Encoding.ASCII)) { while (mBinaryReader.BaseStream.Position < buffer.Length) { byte type = mBinaryReader.ReadByte(); int length = mBinaryReader.ReadInt32(); switch (type) { case RelocalizeKeys.ResponseType_Status: status = mBinaryReader.ReadInt32(); break; case RelocalizeKeys.RequestType_Seq: seq = mBinaryReader.ReadInt32(); break; case RelocalizeKeys.ResponseType_Point2dVec: int countV2 = length / 8; for (int i = 0; i < countV2; i++) { float x = mBinaryReader.ReadSingle(); float y = mBinaryReader.ReadSingle(); Vector2 v2 = new Vector2(x, y); point2d_vec.Add(v2); } break; case RelocalizeKeys.ResponseType_Point3dVec: int countV3 = length / 12; for (int i = 0; i < countV3; i++) { float x = mBinaryReader.ReadSingle(); float y = mBinaryReader.ReadSingle(); float z = mBinaryReader.ReadSingle(); Vector3 v3 = new Vector3(x, y, z); point3d_vec.Add(v3); } break; case RelocalizeKeys.ResponseType_TransformLtg: for (int i = 0; i < 16; i++) { double item = mBinaryReader.ReadDouble(); transform_ltg.Add(item); } break; case RelocalizeKeys.ResponseType_ExtraMsg: byte[] bytes = mBinaryReader.ReadBytes(length); System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); extra_msg = encoding.GetString(bytes); break; default: break; } } } } if (XDKConfigs.IfLogOn) { string strLog = string.Format("ParseRelocationResponse Success:\nstatus: {0} \n\n seq: {1} \n\n point2d_vec: \n{2} \n\n point3d_vec: \n{3} \n\n transform_ltg: \n{4} \n\n extra_msg: \n{5}", status, seq, XDKTools.ListVectro2ToString(point2d_vec), XDKTools.ListVector3ToString(point3d_vec), XDKTools.ListDoubleToString(transform_ltg), extra_msg); Debug.LogFormat(strLog); } RelocationResponse response = new RelocationResponse(status, seq, point2d_vec, point3d_vec, transform_ltg, extra_msg, cameraPos, cameraCalibration, sessionID); Loom.QueueOnMainThread(() => { OnRelocated?.Invoke(response); }); } /// /// 同步更新图片给云定位 /// U3D端使用单独线程,为了减少主线程UI界面卡顿 /// private void RelocUploadImageThread() { while (m_IsUploadingImage) { if (m_UploadImageList.Count > 0) { try { RelocUploadImageItem item = m_UploadImageList[0]; PostValue(item); m_UploadImageList.RemoveAt(0); } catch (Exception ex) { // 一旦出错, 做相应的处理,进入下一次循环 Debug.LogError(ex.Message); m_UploadImageList.RemoveAt(0); continue; } } Thread.Sleep(10); } } private void PostValue(RelocUploadImageItem uploadImageItem) { try { byte[] postBytes; using (MemoryStream mMemStream = new MemoryStream()) { using (BinaryWriter mBinaryWriter = new BinaryWriter(mMemStream, Encoding.ASCII)) { // write sessionID mBinaryWriter.Write(RelocalizeKeys.RequestType_SessionId); byte[] bytesSessionID = System.Text.Encoding.ASCII.GetBytes(uploadImageItem.sessionID); mBinaryWriter.Write(bytesSessionID.Length); mBinaryWriter.Write(bytesSessionID); // write seq mBinaryWriter.Write(RelocalizeKeys.RequestType_Seq); mBinaryWriter.Write(4); mBinaryWriter.Write(uploadImageItem.seq); // write pose mBinaryWriter.Write(RelocalizeKeys.RequestType_Pose); mBinaryWriter.Write(4 * 16); for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { mBinaryWriter.Write(uploadImageItem.cameraPose[x, y]); } } // write intrinsics mBinaryWriter.Write(RelocalizeKeys.RequestType_Intrinsics); mBinaryWriter.Write(4 * 9); float intrinsic_00 = uploadImageItem.cameraCalibration.focal_length.x; float intrinsic_01 = 0; float intrinsic_02 = uploadImageItem.cameraCalibration.principal_point.x; float intrinsic_10 = 0; float intrinsic_11 = uploadImageItem.cameraCalibration.focal_length.y; float intrinsic_12 = uploadImageItem.cameraCalibration.principal_point.y; float intrinsic_20 = 0; float intrinsic_21 = 0; float intrinsic_22 = 1; mBinaryWriter.Write(intrinsic_00); mBinaryWriter.Write(intrinsic_01); mBinaryWriter.Write(intrinsic_02); mBinaryWriter.Write(intrinsic_10); mBinaryWriter.Write(intrinsic_11); mBinaryWriter.Write(intrinsic_12); mBinaryWriter.Write(intrinsic_20); mBinaryWriter.Write(intrinsic_21); mBinaryWriter.Write(intrinsic_22); // write image mBinaryWriter.Write(RelocalizeKeys.RequestType_Image); mBinaryWriter.Write(uploadImageItem.imageBytes.Length); mBinaryWriter.Write(uploadImageItem.imageBytes); // write camera model 相机模型 是否为鱼眼图 mBinaryWriter.Write(RelocalizeKeys.RequestType_CameraModel); mBinaryWriter.Write(4); if (uploadImageItem.cameraCalibration.fish_eye == true) { mBinaryWriter.Write(2); } else { mBinaryWriter.Write(1); } // write ditortion para:相机畸变参数 mBinaryWriter.Write(RelocalizeKeys.RequestType_DitortionPara); mBinaryWriter.Write(4 * 8); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[0]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[1]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[2]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[3]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[4]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[5]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[6]); mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[7]); postBytes = mMemStream.ToArray(); } } long startTicks = DateTime.Now.Ticks / 10000; HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(XDKConfigs.RelocationAPIAddress); req.Headers.Add(k_FieldNameServerFlag, m_ServerFlag.ToString()); req.Method = "POST"; req.ContentType = "application/json"; req.ContentLength = postBytes.Length; if (XDKConfigs.IfLogOn) Debug.LogFormat("Start to relocalize web request ... seq:{0}; {1}:{2};startTime:{3},{4}ms;imageBytesLength:{5}", uploadImageItem.seq, k_FieldNameServerFlag, req.Headers.Get(k_FieldNameServerFlag), DateTime.Now, startTicks, uploadImageItem.imageBytes.Length); using (Stream reqStream = req.GetRequestStream()) { reqStream.Write(postBytes, 0, postBytes.Length); } using (HttpWebResponse myHttpWebResponse = (HttpWebResponse)req.GetResponse()) { long endTicks = DateTime.Now.Ticks / 10000; string msgInfo = ""; switch ((int)myHttpWebResponse.StatusCode) { case 200: msgInfo = "请求成功"; break; case 400: msgInfo = "参数错误"; break; case 404: msgInfo = "地图不存在"; break; case 500: msgInfo = "内部服务器错误"; break; case 503: msgInfo = "服务器忙,请稍后再试"; break; default: msgInfo = "其它错误"; break; } if (myHttpWebResponse.StatusCode == HttpStatusCode.OK) { if (XDKConfigs.IfLogOn) { Debug.LogFormat("Relocalize WebRequest: {0}, code:{1}; seq:{2}; endTime:{3},{4}ms; delay:{5}ms", msgInfo, myHttpWebResponse.StatusCode, uploadImageItem.seq, DateTime.Now, endTicks, endTicks - startTicks ); } Stream responseStream = myHttpWebResponse.GetResponseStream(); ParseRelocationResponse(HttpResponseStreamToBytes(responseStream), uploadImageItem.cameraPose, uploadImageItem.cameraCalibration, uploadImageItem.sessionID); } else { if (XDKConfigs.IfLogOn) { Debug.LogErrorFormat("Relocalize WebRequest: {0}, code:{1}; seq:{2}; endTime:{3},{4}ms; delay:{5}ms", msgInfo, myHttpWebResponse.StatusCode, uploadImageItem.seq, DateTime.Now, endTicks, endTicks - startTicks ); } Debug.LogErrorFormat("{0}, {1}", myHttpWebResponse.StatusDescription, req.Address); } } } catch (Exception ex) { Debug.LogError(ex.ToString()); throw ex; } } /// 将 Stream 转成 byte[] private byte[] HttpResponseStreamToBytes(Stream responseStream) { using (StreamReader reader = new StreamReader(responseStream)) { MemoryStream stmMemory = new MemoryStream(); byte[] buffer = new byte[64 * 1024]; int i; while ((i = responseStream.Read(buffer, 0, buffer.Length)) > 0) { stmMemory.Write(buffer, 0, i); } byte[] arraryByte = stmMemory.ToArray(); stmMemory.Close(); return arraryByte; } } } }