XDKCloudInterface.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text;
  6. using UnityEngine;
  7. using UnityEngine.Networking;
  8. using System.Net;
  9. using System.Threading;
  10. namespace Seengene.XDKUnityPluginCloud {
  11. public delegate void AuthorizationResponseHandler(AuthorizationResponse response);
  12. public delegate void RelocationResponseHandler(RelocationResponse response);
  13. public class XDKCloudInterface : MonoBehaviour {
  14. private const string k_DefaultAuthorizationAPIAddress = "http://124.70.37.47:80/requestMap";
  15. private const string k_DefaultRelocationAPIAddress = "http://124.70.37.47:80/relocalize";
  16. [SerializeField] private string m_AuthorizationAPIAddress = k_DefaultAuthorizationAPIAddress;
  17. [SerializeField] private string m_RelocationAPIAddress = k_DefaultRelocationAPIAddress;
  18. [SerializeField] private string m_MapId = "";
  19. string k_FieldNameServerFlag = "ServerFlag";
  20. int m_ServerFlag = 0;
  21. public event AuthorizationResponseHandler OnAuthorized;
  22. public event RelocationResponseHandler OnRelocated;
  23. bool m_IsUploadingImage = false;
  24. Thread m_ThreadUploadImage = null;
  25. List<RelocUploadImageItem> m_UploadImageList = new List<RelocUploadImageItem>();
  26. private void Awake() {
  27. m_ServerFlag = UnityEngine.Random.Range(1, 1000);
  28. if (string.IsNullOrEmpty(XDKConfigs.AuthorizationAPIAddress)) {
  29. XDKConfigs.AuthorizationAPIAddress = m_AuthorizationAPIAddress;
  30. }
  31. if (string.IsNullOrEmpty(XDKConfigs.RelocationAPIAddress)) {
  32. XDKConfigs.RelocationAPIAddress = m_RelocationAPIAddress;
  33. }
  34. if (string.IsNullOrEmpty(XDKConfigs.MapId)) {
  35. XDKConfigs.MapId = m_MapId;
  36. }
  37. }
  38. private void Start() {
  39. try {
  40. m_IsUploadingImage = true;
  41. m_ThreadUploadImage = new Thread(RelocUploadImageThread);
  42. m_ThreadUploadImage.IsBackground = true;
  43. m_ThreadUploadImage.Start();
  44. Debug.Log("开始线程 RelocUploadingImageThread 成功");
  45. } catch (Exception e) {
  46. Debug.LogErrorFormat("开始线程 RelocUploadingImageThread 失败: {0}", e.Message);
  47. }
  48. }
  49. private void OnDestroy() {
  50. try {
  51. m_IsUploadingImage = false;
  52. if (m_ThreadUploadImage != null)
  53. m_ThreadUploadImage.Abort();
  54. Debug.Log("结束线程 RelocUploadingImageThread 成功");
  55. } catch (Exception e) {
  56. Debug.LogErrorFormat("结束线程 RelocUploadingImageThread 失败:{0}", e.Message);
  57. }
  58. XDKConfigs.SetDefault();
  59. }
  60. public void Authorize() {
  61. StartCoroutine(AuthorizeAsync(XDKConfigs.MapId));
  62. }
  63. public void Relocate(string sessionID, Int32 seq, Matrix4x4 cameraPose, CameraCalibration cameraCalibration, byte[] imageBytes) {
  64. RelocUploadImageItem item = new RelocUploadImageItem(sessionID, seq, cameraPose, cameraCalibration, imageBytes);
  65. m_UploadImageList.Add(item);
  66. }
  67. IEnumerator AuthorizeAsync(string mapId) {
  68. byte[] myData;
  69. using (MemoryStream mMemStream = new MemoryStream()) {
  70. using (BinaryWriter mBinaryWriter = new BinaryWriter(mMemStream, Encoding.ASCII)) {
  71. mBinaryWriter.Write(RequestMapKeys.RequestType_MapId);
  72. byte[] bytesMapId = System.Text.Encoding.ASCII.GetBytes(mapId);
  73. mBinaryWriter.Write(bytesMapId.Length);
  74. mBinaryWriter.Write(bytesMapId);
  75. myData = mMemStream.ToArray();
  76. }
  77. }
  78. UnityWebRequest webRequest = new UnityWebRequest(XDKConfigs.AuthorizationAPIAddress, UnityWebRequest.kHttpVerbPOST);
  79. webRequest.SetRequestHeader(k_FieldNameServerFlag, m_ServerFlag.ToString());
  80. UploadHandler uploader = new UploadHandlerRaw(myData);
  81. DownloadHandler downloadHandler = new DownloadHandlerBuffer();
  82. webRequest.downloadHandler = downloadHandler;
  83. webRequest.uploadHandler = uploader;
  84. webRequest.uploadHandler.contentType = "application/json";
  85. webRequest.timeout = 30;
  86. long startTicks = DateTime.Now.Ticks / 10000;
  87. if (XDKConfigs.IfLogOn) {
  88. Debug.LogFormat("Start To Authorize(RequestSessionID) ... MapID:{0}; {1}:{2};startTime:{3},{4}ms",
  89. mapId, k_FieldNameServerFlag, webRequest.GetRequestHeader(k_FieldNameServerFlag), DateTime.Now, startTicks);
  90. }
  91. yield return webRequest.SendWebRequest();
  92. if (webRequest.isNetworkError || webRequest.isHttpError) {
  93. Debug.LogErrorFormat("{0}, {1}", webRequest.error, webRequest.url);
  94. } else {
  95. long endTicks = DateTime.Now.Ticks / 10000;
  96. string msgInfo = "";
  97. switch (webRequest.responseCode) {
  98. case 200:
  99. msgInfo = "获取SessionID成功";
  100. break;
  101. case 400:
  102. msgInfo = "参数错误";
  103. break;
  104. case 404:
  105. msgInfo = "地图不存在";
  106. break;
  107. case 500:
  108. msgInfo = "内部服务器错误";
  109. break;
  110. case 503:
  111. msgInfo = "服务器忙,请稍后再试";
  112. break;
  113. default:
  114. msgInfo = "其它错误";
  115. break;
  116. }
  117. if (webRequest.responseCode == 200) {
  118. if (XDKConfigs.IfLogOn) {
  119. Debug.LogFormat("Request SessionID: {0}, code:{1}; endTime:{2},{3}ms; delay:{4}ms",
  120. msgInfo, webRequest.responseCode, DateTime.Now, endTicks, endTicks - startTicks);
  121. }
  122. ParseAuthorizationResponse(webRequest.downloadHandler.data);
  123. } else {
  124. if (XDKConfigs.IfLogOn) {
  125. Debug.LogErrorFormat("Request SessionID: {0}, code:{1}; endTime:{2},{3}ms; delay:{4}ms",
  126. msgInfo, webRequest.responseCode, DateTime.Now, endTicks, endTicks - startTicks);
  127. }
  128. }
  129. }
  130. }
  131. private void ParseAuthorizationResponse(byte[] buffer) {
  132. Int32 status = 0;
  133. string sessionID = string.Empty;
  134. double scale = 0;
  135. using (MemoryStream mMemStream = new MemoryStream(buffer)) {
  136. using (BinaryReader mBinaryReader = new BinaryReader(mMemStream, Encoding.ASCII)) {
  137. while (mBinaryReader.BaseStream.Position < buffer.Length) {
  138. byte type = mBinaryReader.ReadByte();
  139. int len = mBinaryReader.ReadInt32();
  140. switch (type) {
  141. case RequestMapKeys.ResponseType_SessionId:
  142. byte[] bytes = mBinaryReader.ReadBytes(len);
  143. System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
  144. sessionID = encoding.GetString(bytes);
  145. break;
  146. case RequestMapKeys.ResponseType_Status:
  147. status = mBinaryReader.ReadInt32();
  148. break;
  149. case RequestMapKeys.ResponseType_Scale:
  150. scale = mBinaryReader.ReadDouble();
  151. break;
  152. default:
  153. break;
  154. }
  155. }
  156. }
  157. }
  158. if (XDKConfigs.IfLogOn) {
  159. Debug.LogFormat("ParseAuthorizationResponse Success, status:{0}; scale:{1}; sessionID:{2}", status, scale, sessionID);
  160. }
  161. AuthorizationResponse response = new AuthorizationResponse(status, scale, sessionID);
  162. OnAuthorized?.Invoke(response);
  163. }
  164. private void ParseRelocationResponse(byte[] buffer, Matrix4x4 cameraPos, CameraCalibration cameraCalibration, string sessionID) {
  165. Int32 status = 0;
  166. Int32 seq = 0;
  167. List<Vector2> point2d_vec = new List<Vector2>();
  168. List<Vector3> point3d_vec = new List<Vector3>();
  169. List<double> transform_ltg = new List<double>();
  170. string extra_msg = string.Empty;
  171. using (MemoryStream mMemStream = new MemoryStream(buffer)) {
  172. using (BinaryReader mBinaryReader = new BinaryReader(mMemStream, Encoding.ASCII)) {
  173. while (mBinaryReader.BaseStream.Position < buffer.Length) {
  174. byte type = mBinaryReader.ReadByte();
  175. int length = mBinaryReader.ReadInt32();
  176. switch (type) {
  177. case RelocalizeKeys.ResponseType_Status:
  178. status = mBinaryReader.ReadInt32();
  179. break;
  180. case RelocalizeKeys.RequestType_Seq:
  181. seq = mBinaryReader.ReadInt32();
  182. break;
  183. case RelocalizeKeys.ResponseType_Point2dVec:
  184. int countV2 = length / 8;
  185. for (int i = 0; i < countV2; i++) {
  186. float x = mBinaryReader.ReadSingle();
  187. float y = mBinaryReader.ReadSingle();
  188. Vector2 v2 = new Vector2(x, y);
  189. point2d_vec.Add(v2);
  190. }
  191. break;
  192. case RelocalizeKeys.ResponseType_Point3dVec:
  193. int countV3 = length / 12;
  194. for (int i = 0; i < countV3; i++) {
  195. float x = mBinaryReader.ReadSingle();
  196. float y = mBinaryReader.ReadSingle();
  197. float z = mBinaryReader.ReadSingle();
  198. Vector3 v3 = new Vector3(x, y, z);
  199. point3d_vec.Add(v3);
  200. }
  201. break;
  202. case RelocalizeKeys.ResponseType_TransformLtg:
  203. for (int i = 0; i < 16; i++) {
  204. double item = mBinaryReader.ReadDouble();
  205. transform_ltg.Add(item);
  206. }
  207. break;
  208. case RelocalizeKeys.ResponseType_ExtraMsg:
  209. byte[] bytes = mBinaryReader.ReadBytes(length);
  210. System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
  211. extra_msg = encoding.GetString(bytes);
  212. break;
  213. default:
  214. break;
  215. }
  216. }
  217. }
  218. }
  219. if (XDKConfigs.IfLogOn) {
  220. 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}",
  221. status, seq, XDKTools.ListVectro2ToString(point2d_vec), XDKTools.ListVector3ToString(point3d_vec), XDKTools.ListDoubleToString(transform_ltg), extra_msg);
  222. Debug.LogFormat(strLog);
  223. }
  224. RelocationResponse response = new RelocationResponse(status, seq, point2d_vec, point3d_vec, transform_ltg, extra_msg, cameraPos, cameraCalibration, sessionID);
  225. Loom.QueueOnMainThread(() => {
  226. OnRelocated?.Invoke(response);
  227. });
  228. }
  229. /// <summary>
  230. /// 同步更新图片给云定位
  231. /// U3D端使用单独线程,为了减少主线程UI界面卡顿
  232. /// </summary>
  233. private void RelocUploadImageThread() {
  234. while (m_IsUploadingImage) {
  235. if (m_UploadImageList.Count > 0) {
  236. try {
  237. RelocUploadImageItem item = m_UploadImageList[0];
  238. PostValue(item);
  239. m_UploadImageList.RemoveAt(0);
  240. } catch (Exception ex) {
  241. // 一旦出错, 做相应的处理,进入下一次循环
  242. Debug.LogError(ex.Message);
  243. m_UploadImageList.RemoveAt(0);
  244. continue;
  245. }
  246. }
  247. Thread.Sleep(10);
  248. }
  249. }
  250. private void PostValue(RelocUploadImageItem uploadImageItem) {
  251. try {
  252. byte[] postBytes;
  253. using (MemoryStream mMemStream = new MemoryStream()) {
  254. using (BinaryWriter mBinaryWriter = new BinaryWriter(mMemStream, Encoding.ASCII)) {
  255. // write sessionID
  256. mBinaryWriter.Write(RelocalizeKeys.RequestType_SessionId);
  257. byte[] bytesSessionID = System.Text.Encoding.ASCII.GetBytes(uploadImageItem.sessionID);
  258. mBinaryWriter.Write(bytesSessionID.Length);
  259. mBinaryWriter.Write(bytesSessionID);
  260. // write seq
  261. mBinaryWriter.Write(RelocalizeKeys.RequestType_Seq);
  262. mBinaryWriter.Write(4);
  263. mBinaryWriter.Write(uploadImageItem.seq);
  264. // write pose
  265. mBinaryWriter.Write(RelocalizeKeys.RequestType_Pose);
  266. mBinaryWriter.Write(4 * 16);
  267. for (int x = 0; x < 4; x++) {
  268. for (int y = 0; y < 4; y++) {
  269. mBinaryWriter.Write(uploadImageItem.cameraPose[x, y]);
  270. }
  271. }
  272. // write intrinsics
  273. mBinaryWriter.Write(RelocalizeKeys.RequestType_Intrinsics);
  274. mBinaryWriter.Write(4 * 9);
  275. float intrinsic_00 = uploadImageItem.cameraCalibration.focal_length.x;
  276. float intrinsic_01 = 0;
  277. float intrinsic_02 = uploadImageItem.cameraCalibration.principal_point.x;
  278. float intrinsic_10 = 0;
  279. float intrinsic_11 = uploadImageItem.cameraCalibration.focal_length.y;
  280. float intrinsic_12 = uploadImageItem.cameraCalibration.principal_point.y;
  281. float intrinsic_20 = 0;
  282. float intrinsic_21 = 0;
  283. float intrinsic_22 = 1;
  284. mBinaryWriter.Write(intrinsic_00);
  285. mBinaryWriter.Write(intrinsic_01);
  286. mBinaryWriter.Write(intrinsic_02);
  287. mBinaryWriter.Write(intrinsic_10);
  288. mBinaryWriter.Write(intrinsic_11);
  289. mBinaryWriter.Write(intrinsic_12);
  290. mBinaryWriter.Write(intrinsic_20);
  291. mBinaryWriter.Write(intrinsic_21);
  292. mBinaryWriter.Write(intrinsic_22);
  293. // write image
  294. mBinaryWriter.Write(RelocalizeKeys.RequestType_Image);
  295. mBinaryWriter.Write(uploadImageItem.imageBytes.Length);
  296. mBinaryWriter.Write(uploadImageItem.imageBytes);
  297. // write camera model 相机模型 是否为鱼眼图
  298. mBinaryWriter.Write(RelocalizeKeys.RequestType_CameraModel);
  299. mBinaryWriter.Write(4);
  300. if (uploadImageItem.cameraCalibration.fish_eye == true) {
  301. mBinaryWriter.Write(2);
  302. } else {
  303. mBinaryWriter.Write(1);
  304. }
  305. // write ditortion para:相机畸变参数
  306. mBinaryWriter.Write(RelocalizeKeys.RequestType_DitortionPara);
  307. mBinaryWriter.Write(4 * 8);
  308. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[0]);
  309. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[1]);
  310. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[2]);
  311. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[3]);
  312. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[4]);
  313. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[5]);
  314. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[6]);
  315. mBinaryWriter.Write(uploadImageItem.cameraCalibration.radial_distortion_8[7]);
  316. postBytes = mMemStream.ToArray();
  317. }
  318. }
  319. long startTicks = DateTime.Now.Ticks / 10000;
  320. HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(XDKConfigs.RelocationAPIAddress);
  321. req.Headers.Add(k_FieldNameServerFlag, m_ServerFlag.ToString());
  322. req.Method = "POST";
  323. req.ContentType = "application/json";
  324. req.ContentLength = postBytes.Length;
  325. if (XDKConfigs.IfLogOn)
  326. Debug.LogFormat("Start to relocalize web request ... seq:{0}; {1}:{2};startTime:{3},{4}ms;imageBytesLength:{5}",
  327. uploadImageItem.seq, k_FieldNameServerFlag, req.Headers.Get(k_FieldNameServerFlag), DateTime.Now, startTicks, uploadImageItem.imageBytes.Length);
  328. using (Stream reqStream = req.GetRequestStream()) {
  329. reqStream.Write(postBytes, 0, postBytes.Length);
  330. }
  331. using (HttpWebResponse myHttpWebResponse = (HttpWebResponse)req.GetResponse()) {
  332. long endTicks = DateTime.Now.Ticks / 10000;
  333. string msgInfo = "";
  334. switch ((int)myHttpWebResponse.StatusCode) {
  335. case 200:
  336. msgInfo = "请求成功";
  337. break;
  338. case 400:
  339. msgInfo = "参数错误";
  340. break;
  341. case 404:
  342. msgInfo = "地图不存在";
  343. break;
  344. case 500:
  345. msgInfo = "内部服务器错误";
  346. break;
  347. case 503:
  348. msgInfo = "服务器忙,请稍后再试";
  349. break;
  350. default:
  351. msgInfo = "其它错误";
  352. break;
  353. }
  354. if (myHttpWebResponse.StatusCode == HttpStatusCode.OK) {
  355. if (XDKConfigs.IfLogOn) {
  356. Debug.LogFormat("Relocalize WebRequest: {0}, code:{1}; seq:{2}; endTime:{3},{4}ms; delay:{5}ms",
  357. msgInfo,
  358. myHttpWebResponse.StatusCode,
  359. uploadImageItem.seq,
  360. DateTime.Now,
  361. endTicks,
  362. endTicks - startTicks
  363. );
  364. }
  365. Stream responseStream = myHttpWebResponse.GetResponseStream();
  366. ParseRelocationResponse(HttpResponseStreamToBytes(responseStream), uploadImageItem.cameraPose, uploadImageItem.cameraCalibration, uploadImageItem.sessionID);
  367. } else {
  368. if (XDKConfigs.IfLogOn) {
  369. Debug.LogErrorFormat("Relocalize WebRequest: {0}, code:{1}; seq:{2}; endTime:{3},{4}ms; delay:{5}ms",
  370. msgInfo,
  371. myHttpWebResponse.StatusCode,
  372. uploadImageItem.seq,
  373. DateTime.Now,
  374. endTicks,
  375. endTicks - startTicks
  376. );
  377. }
  378. Debug.LogErrorFormat("{0}, {1}", myHttpWebResponse.StatusDescription, req.Address);
  379. }
  380. }
  381. } catch (Exception ex) {
  382. Debug.LogError(ex.ToString());
  383. throw ex;
  384. }
  385. }
  386. /// 将 Stream 转成 byte[]
  387. private byte[] HttpResponseStreamToBytes(Stream responseStream) {
  388. using (StreamReader reader = new StreamReader(responseStream)) {
  389. MemoryStream stmMemory = new MemoryStream();
  390. byte[] buffer = new byte[64 * 1024];
  391. int i;
  392. while ((i = responseStream.Read(buffer, 0, buffer.Length)) > 0) {
  393. stmMemory.Write(buffer, 0, i);
  394. }
  395. byte[] arraryByte = stmMemory.ToArray();
  396. stmMemory.Close();
  397. return arraryByte;
  398. }
  399. }
  400. }
  401. }