MapperBase.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. /*===============================================================================
  2. Copyright (C) 2022 Immersal - Part of Hexagon. All Rights Reserved.
  3. This file is part of the Immersal SDK.
  4. The Immersal SDK cannot be copied, distributed, or made available to
  5. third-parties for commercial purposes without written permission of Immersal Ltd.
  6. Contact sdk@immersal.com for licensing requests.
  7. ===============================================================================*/
  8. using System;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using System.Threading.Tasks;
  13. using UnityEngine;
  14. using UnityEngine.UI;
  15. using Immersal.AR;
  16. using Immersal.REST;
  17. using Immersal.Samples.Util;
  18. using UnityEngine.Events;
  19. #if PLATFORM_ANDROID
  20. using UnityEngine.Android;
  21. #endif
  22. namespace Immersal.Samples.Mapping
  23. {
  24. public abstract class MapperBase : MonoBehaviour
  25. {
  26. protected const double DefaultRadius = 200.0;
  27. public UnityEvent onConnect = null;
  28. public UnityEvent onFailedToConnect = null;
  29. public UnityEvent onImageLimitExceeded = null;
  30. [HideInInspector]
  31. public MappingUIManager mappingUIManager;
  32. [HideInInspector]
  33. public MapperSettings mapperSettings;
  34. [HideInInspector]
  35. public WorkspaceManager workspaceManager;
  36. [HideInInspector]
  37. public VisualizeManager visualizeManager;
  38. public MapperStats stats { get; protected set; } = new MapperStats();
  39. protected int m_ImageIndex = 0;
  40. protected uint m_ImageRun = 0;
  41. protected bool m_SessionFirstImage = true;
  42. protected bool m_IsTracking = false;
  43. protected List<JobAsync> m_Jobs = new List<JobAsync>();
  44. private int m_JobLock = 0;
  45. protected ImmersalSDK m_Sdk;
  46. protected double m_Latitude = 0.0;
  47. protected double m_Longitude = 0.0;
  48. protected double m_Altitude = 0.0;
  49. protected double m_Haccuracy = 0.0;
  50. protected double m_Vaccuracy = 0.0;
  51. protected double m_VLatitude = 0.0;
  52. protected double m_VLongitude = 0.0;
  53. protected double m_VAltitude = 0.0;
  54. protected float m_VBearing = 0f;
  55. protected bool m_bCaptureRunning = false;
  56. protected IntPtr m_PixelBuffer = IntPtr.Zero;
  57. protected bool m_UseGeoPose = false;
  58. private AudioSource m_CameraShutterClick;
  59. private IEnumerator m_UpdateJobList;
  60. private Camera m_MainCamera = null;
  61. private static IDispatch Dispatch;
  62. private bool m_enableStatusPolling;
  63. public Camera mainCamera
  64. {
  65. get
  66. {
  67. if (m_MainCamera == null)
  68. {
  69. m_MainCamera = Camera.main;
  70. if (m_MainCamera == null)
  71. Debug.LogError("No Camera found");
  72. }
  73. return m_MainCamera;
  74. }
  75. }
  76. public bool gpsOn
  77. {
  78. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  79. get { return NativeBindings.LocationServicesEnabled(); }
  80. #else
  81. get { return Input.location.status == LocationServiceStatus.Running; }
  82. #endif
  83. }
  84. public string tempImagePath
  85. {
  86. get
  87. {
  88. return string.Format("{0}/Images", Application.persistentDataPath);
  89. }
  90. }
  91. #region Abstract methods
  92. protected abstract void Capture(bool anchor);
  93. #endregion
  94. #region Virtual methods
  95. protected virtual void OnEnable()
  96. {
  97. stats.queueLen = 0;
  98. stats.imageCount = 0;
  99. DirectoryInfo dataDir = new DirectoryInfo(tempImagePath);
  100. if (dataDir.Exists)
  101. {
  102. dataDir.Delete(true);
  103. }
  104. Directory.CreateDirectory(tempImagePath);
  105. #if UNITY_IOS
  106. UnityEngine.iOS.Device.SetNoBackupFlag(tempImagePath);
  107. #endif
  108. m_enableStatusPolling = true;
  109. mappingUIManager.vLocationText.text = "No VGPS localizations";
  110. if (mapperSettings.useGps)
  111. {
  112. Invoke("StartGPS", 0.1f);
  113. }
  114. StatusPoll();
  115. Jobs();
  116. }
  117. protected virtual void OnDisable()
  118. {
  119. bool deleteToken = true;
  120. if (PlayerPrefs.HasKey("rememberMe"))
  121. {
  122. if(bool.Parse(PlayerPrefs.GetString("rememberMe")))
  123. {
  124. Debug.Log("Remember me feature is on - skipping token deletion");
  125. deleteToken = false;
  126. }
  127. }
  128. if (deleteToken)
  129. {
  130. PlayerPrefs.DeleteKey("token");
  131. m_Sdk.developerToken = null;
  132. }
  133. m_enableStatusPolling = false;
  134. }
  135. public virtual void Update()
  136. {
  137. UpdateLocation();
  138. stats.queueLen = m_Jobs.Count;
  139. if (m_JobLock == 1)
  140. return;
  141. if (m_Jobs.Count > 0)
  142. {
  143. m_JobLock = 1;
  144. RunJob(m_Jobs[0]);
  145. }
  146. }
  147. #endregion
  148. public void OnGPSToggleChanged(bool value)
  149. {
  150. if (value)
  151. {
  152. Invoke("StartGPS", 0.1f);
  153. }
  154. else
  155. {
  156. Invoke("StopGPS", 0.1f);
  157. }
  158. }
  159. internal void ImageRunUpdate()
  160. {
  161. long bin = System.DateTime.Now.ToBinary();
  162. uint data = (uint)bin ^ (uint)(bin >> 32);
  163. m_ImageRun = (m_ImageRun ^ data) * 16777619;
  164. }
  165. void Awake()
  166. {
  167. Dispatch = new MainThreadDispatch();
  168. m_CameraShutterClick = GetComponent<AudioSource>();
  169. mappingUIManager = GetComponentInChildren<MappingUIManager>();
  170. mapperSettings = GetComponent<MapperSettings>();
  171. workspaceManager = mappingUIManager.workspaceManager;
  172. visualizeManager = mappingUIManager.visualizeManager;
  173. visualizeManager.OnItemSelected += OnItemSelected;
  174. visualizeManager.OnItemDeleted += OnItemDeleted;
  175. visualizeManager.OnItemRestored += OnItemRestored;
  176. visualizeManager.OnSelectorOpened += OnSelectorOpened;
  177. visualizeManager.OnSelectorClosed += OnSelectorClosed;
  178. ImageRunUpdate();
  179. }
  180. void Start()
  181. {
  182. m_Sdk = ImmersalSDK.Instance;
  183. if (mapperSettings.downsampleWhenLocalizing)
  184. {
  185. Immersal.Core.SetInteger("LocalizationMaxPixels", 1280*720);
  186. }
  187. }
  188. #if PLATFORM_ANDROID
  189. private IEnumerator WaitForLocationPermission()
  190. {
  191. while (!Permission.HasUserAuthorizedPermission(Permission.FineLocation))
  192. {
  193. yield return null;
  194. }
  195. Debug.Log("Location permission OK");
  196. StartCoroutine(EnableLocationServices());
  197. yield return null;
  198. }
  199. #endif
  200. public void StartGPS()
  201. {
  202. #if UNITY_IOS
  203. StartCoroutine(EnableLocationServices());
  204. #elif PLATFORM_ANDROID
  205. if (Permission.HasUserAuthorizedPermission(Permission.FineLocation))
  206. {
  207. Debug.Log("Location permission OK");
  208. StartCoroutine(EnableLocationServices());
  209. }
  210. else
  211. {
  212. Permission.RequestUserPermission(Permission.FineLocation);
  213. StartCoroutine(WaitForLocationPermission());
  214. }
  215. #endif
  216. }
  217. public void StopGPS()
  218. {
  219. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  220. NativeBindings.StopLocation();
  221. #else
  222. Input.location.Stop();
  223. #endif
  224. mapperSettings.SetUseGPS(false);
  225. NotificationManager.Instance.GenerateNotification("Geolocation tracking stopped");
  226. mappingUIManager.locationText.text = "GPS not enabled";
  227. }
  228. private IEnumerator EnableLocationServices()
  229. {
  230. // First, check if user has location service enabled
  231. if (!Input.location.isEnabledByUser)
  232. {
  233. mappingUIManager.gpsToggle.SetIsOnWithoutNotify(false);
  234. mapperSettings.SetUseGPS(false);
  235. NotificationManager.Instance.GenerateNotification("Location services not enabled");
  236. Debug.Log("Location services not enabled");
  237. yield break;
  238. }
  239. // Start service before querying location
  240. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  241. NativeBindings.StartLocation();
  242. #else
  243. Input.location.Start(0.001f, 0.001f);
  244. #endif
  245. // Wait until service initializes
  246. int maxWait = 20;
  247. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  248. while (!NativeBindings.LocationServicesEnabled() && maxWait > 0)
  249. #else
  250. while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
  251. #endif
  252. {
  253. yield return new WaitForSeconds(1);
  254. maxWait--;
  255. }
  256. // Service didn't initialize in 20 seconds
  257. if (maxWait < 1)
  258. {
  259. mappingUIManager.gpsToggle.SetIsOnWithoutNotify(false);
  260. mapperSettings.SetUseGPS(false);
  261. NotificationManager.Instance.GenerateNotification("Location services timed out");
  262. Debug.Log("Timed out");
  263. yield break;
  264. }
  265. // Connection has failed
  266. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  267. if (!NativeBindings.LocationServicesEnabled())
  268. #else
  269. if (Input.location.status == LocationServiceStatus.Failed)
  270. #endif
  271. {
  272. mappingUIManager.gpsToggle.SetIsOnWithoutNotify(false);
  273. mapperSettings.SetUseGPS(false);
  274. NotificationManager.Instance.GenerateNotification("Unable to determine device location");
  275. Debug.Log("Unable to determine device location");
  276. yield break;
  277. }
  278. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  279. if (NativeBindings.LocationServicesEnabled())
  280. #else
  281. if (Input.location.status == LocationServiceStatus.Running)
  282. #endif
  283. {
  284. mappingUIManager.gpsToggle.SetIsOnWithoutNotify(true);
  285. mapperSettings.SetUseGPS(true);
  286. NotificationManager.Instance.GenerateNotification("Tracking geolocation");
  287. }
  288. }
  289. public void ToggleVisualization(Toggle toggle)
  290. {
  291. ARMap.pointCloudVisible = toggle.isOn;
  292. }
  293. public void ToggleVisualization(bool active)
  294. {
  295. ARMap.pointCloudVisible = active;
  296. }
  297. public void ToggleRenderPointsAs3D(Toggle toggle)
  298. {
  299. ARMap.renderAs3dPoints = toggle.isOn;
  300. }
  301. public void ToggleRenderPointsAs3D(bool renderAs3D)
  302. {
  303. ARMap.renderAs3dPoints = renderAs3D;
  304. }
  305. public void SetPointSize(Slider slider)
  306. {
  307. ARMap.pointSize = Mathf.Max(0f, slider.value);
  308. }
  309. public void SetPointSize(float pointSize)
  310. {
  311. ARMap.pointSize = Mathf.Max(0f, pointSize);
  312. }
  313. private void OnItemSelected(SDKJob job)
  314. {
  315. LoadMap(job);
  316. }
  317. private void OnItemDeleted(SDKJob job)
  318. {
  319. DeleteMap(job.id);
  320. }
  321. private void OnItemRestored(SDKJob job, bool clear)
  322. {
  323. RestoreMapImages(job.id, clear);
  324. }
  325. private void OnSelectorOpened()
  326. {
  327. if (m_UpdateJobList != null)
  328. {
  329. StopCoroutine(m_UpdateJobList);
  330. }
  331. m_UpdateJobList = UpdateJobList();
  332. StartCoroutine(m_UpdateJobList);
  333. }
  334. private void OnSelectorClosed()
  335. {
  336. if (m_UpdateJobList != null)
  337. {
  338. StopCoroutine(m_UpdateJobList);
  339. }
  340. }
  341. IEnumerator UpdateJobList()
  342. {
  343. while (true)
  344. {
  345. Jobs();
  346. yield return new WaitForSeconds(3f);
  347. }
  348. }
  349. async void StatusPoll()
  350. {
  351. JobStatusAsync j = new JobStatusAsync();
  352. j.OnResult += (SDKStatusResult result) =>
  353. {
  354. this.stats.imageCount = result.imageCount;
  355. this.stats.imageMax = result.imageMax;
  356. };
  357. await j.RunJobAsync();
  358. await Task.Delay(3000);
  359. if (Application.isPlaying && m_enableStatusPolling)
  360. {
  361. StatusPoll();
  362. }
  363. }
  364. private async void RunJob(JobAsync j)
  365. {
  366. await j.RunJobAsync();
  367. if (m_Jobs.Count > 0)
  368. {
  369. m_Jobs.RemoveAt(0);
  370. }
  371. m_JobLock = 0;
  372. }
  373. Matrix4x4 RotX(double angle)
  374. {
  375. float c = (float)System.Math.Cos(angle * System.Math.PI / 180.0);
  376. float s = (float)System.Math.Sin(angle * System.Math.PI / 180.0);
  377. Matrix4x4 r = Matrix4x4.identity;
  378. r.m11 = c;
  379. r.m22 = c;
  380. r.m12 = s;
  381. r.m21 = -s;
  382. return r;
  383. }
  384. Matrix4x4 RotZ(double angle)
  385. {
  386. float c = (float)System.Math.Cos(angle * System.Math.PI / 180.0);
  387. float s = (float)System.Math.Sin(angle * System.Math.PI / 180.0);
  388. Matrix4x4 r = Matrix4x4.identity;
  389. r.m00 = c;
  390. r.m11 = c;
  391. r.m10 = -s;
  392. r.m01 = s;
  393. return r;
  394. }
  395. Matrix4x4 Rot3d(double lat, double lon)
  396. {
  397. Matrix4x4 rz = RotZ(90 + lon);
  398. Matrix4x4 rx = RotX(90 - lat);
  399. return rx * rz;
  400. }
  401. Vector2 CompassDir(Camera cam, Matrix4x4 trackerToMap, double[] mapToEcef)
  402. {
  403. Vector3 a = trackerToMap.MultiplyPoint(cam.transform.position);
  404. Vector3 b = trackerToMap.MultiplyPoint(cam.transform.position + cam.transform.forward);
  405. double[] aEcef = new double[3];
  406. int ra = Immersal.Core.PosMapToEcef(aEcef, ARHelper.SwitchHandedness(a), mapToEcef);
  407. double[] bEcef = new double[3];
  408. int rb = Immersal.Core.PosMapToEcef(bEcef, ARHelper.SwitchHandedness(b), mapToEcef);
  409. double[] wgs84 = new double[3];
  410. int rw = Immersal.Core.PosMapToWgs84(wgs84, ARHelper.SwitchHandedness(a), mapToEcef);
  411. Matrix4x4 R = Rot3d(wgs84[0], wgs84[1]);
  412. Vector3 v = new Vector3((float)(bEcef[0] - aEcef[0]), (float)(bEcef[1] - aEcef[1]), (float)(bEcef[2] - aEcef[2]));
  413. Vector3 vt = R.MultiplyVector(v.normalized);
  414. Vector2 d = new Vector2(vt.x, vt.y);
  415. return d.normalized;
  416. }
  417. void UpdateLocation()
  418. {
  419. if (gpsOn)
  420. {
  421. #if (UNITY_IOS || PLATFORM_ANDROID) && !UNITY_EDITOR
  422. m_Latitude = NativeBindings.GetLatitude();
  423. m_Longitude = NativeBindings.GetLongitude();
  424. m_Altitude = NativeBindings.GetAltitude();
  425. m_Haccuracy = NativeBindings.GetHorizontalAccuracy();
  426. m_Vaccuracy = NativeBindings.GetVerticalAccuracy();
  427. #else
  428. m_Latitude = Input.location.lastData.latitude;
  429. m_Longitude = Input.location.lastData.longitude;
  430. m_Altitude = Input.location.lastData.altitude;
  431. m_Haccuracy = Input.location.lastData.horizontalAccuracy;
  432. m_Vaccuracy = Input.location.lastData.verticalAccuracy;
  433. #endif
  434. string txt = string.Format("Lat: {0}, Lon: {1}, Alt: {2}, HAcc: {3}, VAcc: {4}",
  435. m_Latitude.ToString("0.00000"),
  436. m_Longitude.ToString("0.00000"),
  437. m_Altitude.ToString("0.0"),
  438. m_Haccuracy.ToString("0.0"),
  439. m_Vaccuracy.ToString("0.0"));
  440. mappingUIManager.locationText.text = txt;
  441. }
  442. LocalizerPose localizerPose = m_Sdk.Localizer.lastLocalizedPose;
  443. if (localizerPose.valid)
  444. {
  445. Vector2 cd = CompassDir(mainCamera, localizerPose.matrix, localizerPose.mapToEcef);
  446. float bearing = Mathf.Atan2(-cd.x, cd.y) * (180f / (float)Math.PI);
  447. if(bearing >= 0f)
  448. {
  449. m_VBearing = bearing;
  450. }
  451. else
  452. {
  453. m_VBearing = 360f - Mathf.Abs(bearing);
  454. }
  455. Matrix4x4 trackerSpace = Matrix4x4.TRS(mainCamera.transform.position, mainCamera.transform.rotation, Vector3.one);
  456. Matrix4x4 m = localizerPose.matrix * trackerSpace;
  457. Vector3 pos = m.GetColumn(3);
  458. double[] wgs84 = new double[3];
  459. int r = Immersal.Core.PosMapToWgs84(wgs84, ARHelper.SwitchHandedness(pos), localizerPose.mapToEcef);
  460. m_VLatitude = wgs84[0];
  461. m_VLongitude = wgs84[1];
  462. m_VAltitude = wgs84[2];
  463. localizerPose.lastUpdatedPose.position = pos;
  464. localizerPose.lastUpdatedPose.rotation = m.rotation;
  465. }
  466. string txt2 = string.Format("VLat: {0}, VLon: {1}, VAlt: {2}, VBRG: {3}",
  467. m_VLatitude.ToString("0.000000"),
  468. m_VLongitude.ToString("0.000000"),
  469. m_VAltitude.ToString("0.0"),
  470. m_VBearing.ToString("0.0"));
  471. mappingUIManager.vLocationText.text = txt2;
  472. }
  473. public void DeleteMap(int jobId)
  474. {
  475. JobDeleteMapAsync j = new JobDeleteMapAsync();
  476. j.id = jobId;
  477. j.OnResult += (SDKDeleteMapResult result) =>
  478. {
  479. Debug.Log(string.Format("Map {0} deleted successfully.", jobId));
  480. };
  481. m_Jobs.Add(j);
  482. }
  483. public void RestoreMapImages(int jobId, bool clear)
  484. {
  485. JobRestoreMapImagesAsync j = new JobRestoreMapImagesAsync();
  486. j.id = jobId;
  487. j.clear = clear;
  488. j.OnResult += (SDKRestoreMapImagesResult result) =>
  489. {
  490. Debug.Log(string.Format("Successfully restored images for map {0}", jobId));
  491. };
  492. m_Jobs.Add(j);
  493. m_SessionFirstImage = true;
  494. }
  495. public void ResetMapperPictures(bool deleteAnchor)
  496. {
  497. JobClearAsync j = new JobClearAsync();
  498. j.anchor = deleteAnchor;
  499. j.OnResult += (SDKClearResult result) =>
  500. {
  501. Debug.Log("Workspace cleared successfully");
  502. };
  503. m_Jobs.Add(j);
  504. m_SessionFirstImage = true;
  505. }
  506. public void Construct()
  507. {
  508. JobConstructAsync j = new JobConstructAsync();
  509. j.name = workspaceManager.newMapName.text;
  510. j.featureCount = mapperSettings.mapDetailLevel;
  511. j.preservePoses = mapperSettings.preservePoses;
  512. j.windowSize = mapperSettings.windowSize;
  513. j.OnResult += (SDKConstructResult result) =>
  514. {
  515. Debug.Log(string.Format("Started constructing a map width ID {0}, containing {1} images and detail level of {2}", result.id, result.size, j.featureCount));
  516. };
  517. m_Jobs.Add(j);
  518. }
  519. public void NotifyIfConnected(icvCaptureInfo info)
  520. {
  521. Dispatch.Dispatch(() => {
  522. if (!m_SessionFirstImage)
  523. {
  524. if (info.connected == 0)
  525. {
  526. this.onFailedToConnect?.Invoke();
  527. }
  528. else
  529. {
  530. this.onConnect?.Invoke();
  531. }
  532. }
  533. });
  534. }
  535. public void ImageLimitExceeded()
  536. {
  537. Dispatch.Dispatch(() => {
  538. Debug.Log("Account image limit exceeded, aborting image capture");
  539. this.onImageLimitExceeded?.Invoke();
  540. });
  541. }
  542. public void Capture()
  543. {
  544. if (!m_bCaptureRunning)
  545. {
  546. var captureButton = workspaceManager.captureButton.GetComponent<Button>();
  547. captureButton.interactable = false;
  548. m_CameraShutterClick.Play();
  549. Capture(false);
  550. }
  551. }
  552. public void Anchor()
  553. {
  554. if (!m_bCaptureRunning)
  555. {
  556. m_CameraShutterClick.Play();
  557. Capture(true);
  558. }
  559. }
  560. public void LoadMap(SDKJob job)
  561. {
  562. if (ARSpace.mapIdToMap.ContainsKey(job.id))
  563. {
  564. ARMap arMap = ARSpace.mapIdToMap[job.id];
  565. arMap.FreeMap(true);
  566. return;
  567. }
  568. JobLoadMapBinaryAsync j = new JobLoadMapBinaryAsync();
  569. j.id = job.id;
  570. j.sha256_al = job.sha256_al;
  571. j.OnStart += () =>
  572. {
  573. mappingUIManager.SetProgress(0);
  574. mappingUIManager.ShowProgressBar();
  575. };
  576. j.OnResult += async (SDKMapResult result) =>
  577. {
  578. Debug.Log(string.Format("Load map {0} ({1} bytes) ({2}/{3})", job.id, result.mapData.Length, CryptoUtil.SHA256(result.mapData), result.sha256_al));
  579. Color pointCloudColor = ARMap.pointCloudColors[UnityEngine.Random.Range(0, ARMap.pointCloudColors.Length)];
  580. Transform root = null;
  581. if (!mapperSettings.useDifferentARSpaces)
  582. {
  583. ARSpace[] arSpaces = GameObject.FindObjectsOfType<ARSpace>();
  584. foreach (ARSpace space in arSpaces)
  585. {
  586. if (space.gameObject.name == "ARSpaceForAll")
  587. {
  588. root = space.transform;
  589. }
  590. }
  591. }
  592. bool applyAlignment = !mapperSettings.useDifferentARSpaces;
  593. await ARSpace.LoadAndInstantiateARMap(root, result, ARMap.RenderMode.EditorAndRuntime, pointCloudColor, applyAlignment);
  594. //await ARSpace.LoadAndInstantiateARMap(root, job, result.mapData, ARMap.RenderMode.EditorAndRuntime, pointCloudColor, applyAlignment);
  595. m_Sdk.Localizer.stats.localizationAttemptCount = 0;
  596. m_Sdk.Localizer.stats.localizationSuccessCount = 0;
  597. VisualizeManager.loadJobs.Remove(job.id);
  598. mappingUIManager.HideProgressBar();
  599. };
  600. j.Progress.ProgressChanged += (s, progress) =>
  601. {
  602. int value = (int)(100f * progress);
  603. mappingUIManager.SetProgress(value);
  604. };
  605. j.OnError += (e) =>
  606. {
  607. mappingUIManager.HideProgressBar();
  608. };
  609. m_Jobs.Add(j);
  610. }
  611. public void Jobs()
  612. {
  613. JobListJobsAsync j = new JobListJobsAsync();
  614. List<int> activeMaps = new List<int>();
  615. if (mapperSettings.listOnlyNearbyMaps)
  616. {
  617. j.useGPS = true;
  618. j.latitude = m_Latitude;
  619. j.longitude = m_Longitude;
  620. j.radius = DefaultRadius;
  621. }
  622. foreach (int id in ARSpace.mapIdToMap.Keys)
  623. {
  624. activeMaps.Add(id);
  625. }
  626. j.OnResult += (SDKJobsResult result) =>
  627. {
  628. List<SDKJob> jobList = new List<SDKJob>();
  629. foreach (SDKJob job in result.jobs)
  630. {
  631. if (job.type != (int)SDKJobType.Alignment)
  632. {
  633. jobList.Add(job);
  634. }
  635. }
  636. this.visualizeManager.SetMapListData(jobList.ToArray(), activeMaps);
  637. };
  638. m_Jobs.Add(j);
  639. }
  640. public void Logout()
  641. {
  642. if (LoginManager.Instance != null)
  643. LoginManager.Instance.Logout();
  644. }
  645. }
  646. public class MapperStats
  647. {
  648. public int queueLen;
  649. public int imageCount;
  650. public int imageMax;
  651. }
  652. }