void ISerializationCallbackReceiver.OnAfterDeserialize() { if (_serviceProvider_serialized != null && _serviceProvider_serialized.Length != 0) { var type = System.Type.GetType(_serviceProvider_serialized); _serviceProvider = System.Activator.CreateInstance(type) as IElevationServiceProvider; } }
void OnGUI() { _isReady = _mainTask == null || _mainTask.IsCompleted; GUI.enabled = _isReady; EditorGUILayout.Separator(); EditorGUILayout.BeginVertical(); { EditorGUILayout.BeginHorizontal(); GUILayout.Label("Service Provider Selected: "); GUILayout.Label(_serviceProvider != null ? _serviceProvider.GetType().Name : "NONE"); EditorGUILayout.EndHorizontal(); foreach (var entry in _listServiveProviders) { if ( _serviceProvider.GetType() != entry.instance.GetType() && GUILayout.Button($"Switch To { entry.name }") ) { _serviceProvider = entry.instance; _key = null; } } } EditorGUILayout.EndVertical(); _scroll_window = EditorGUILayout.BeginScrollView(_scroll_window); { GUILayout.BeginVertical("- SETTINGS -", "window"); { EditorGUILayout.BeginHorizontal(); { GUILayout.Label("REGION BOTTOM LEFT CORNER:"); //GUILayout.FlexibleSpace(); GUILayout.Label("latitude:", GUILayout.Width(60f)); _settings.start.latitude = Mathf.Clamp( EditorGUILayout.FloatField(_settings.start.latitude, GUILayout.Width(60f)), -90f, 90f ); GUILayout.Label("longitude:", GUILayout.Width(60f)); _settings.start.longitude = Mathf.Clamp( EditorGUILayout.FloatField(_settings.start.longitude, GUILayout.Width(60f)), -180f, 180f ); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("REGION UPPER RIGHT CORNER:"); //GUILayout.FlexibleSpace(); GUILayout.Label("latitude:", GUILayout.Width(60f)); _settings.end.latitude = Mathf.Clamp( EditorGUILayout.FloatField(_settings.end.latitude, GUILayout.Width(60f)), -90f, 90f ); GUILayout.Label("longitude:", GUILayout.Width(60f)); _settings.end.longitude = Mathf.Clamp( EditorGUILayout.FloatField(_settings.end.longitude, GUILayout.Width(60f)), -180f, 180f ); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.FlexibleSpace(); GUILayout.Label("(move region)"); float w = _settings.end.longitude - _settings.start.longitude; float h = _settings.end.latitude - _settings.start.latitude; if (GUILayout.Button("<", GUILayout.Width(30f))) { _settings.start.longitude -= w; _settings.end.longitude -= w; } if (GUILayout.Button("^", GUILayout.Width(30f))) { _settings.start.latitude += h; _settings.end.latitude += h; } if (GUILayout.Button("v", GUILayout.Width(30f))) { _settings.start.latitude -= h; _settings.end.latitude -= h; } if (GUILayout.Button(">", GUILayout.Width(30f))) { _settings.start.longitude += w; _settings.end.longitude += w; } } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { EditorGUILayout.PrefixLabel("Resolution:"); //GUILayout.FlexibleSpace(); //calculate meters per degree: double metersPerDegreeLatitude; double metersPerDegreeLongitude; { Coordinate middlePoint = _settings.start + ((_settings.end - _settings.start) * 0.5f); metersPerDegreeLatitude = _core.HaversineDistance( new Coordinate { latitude = _settings.start.latitude, longitude = middlePoint.longitude }, new Coordinate { latitude = _settings.end.latitude, longitude = middlePoint.longitude } ) / _settings.resolution.latitude; metersPerDegreeLongitude = _core.HaversineDistance( new Coordinate { latitude = middlePoint.latitude, longitude = _settings.start.longitude }, new Coordinate { latitude = middlePoint.latitude, longitude = _settings.end.longitude } ) / _settings.resolution.longitude; } GUILayout.Label("latitude:", GUILayout.Width(60f)); _settings.resolution.latitude = Mathf.Clamp( EditorGUILayout.IntField(_settings.resolution.latitude, GUILayout.Width(60f)), 1, int.MaxValue ); GUILayout.Label($"({ metersPerDegreeLatitude.ToString("0.##") } [m])"); GUILayout.Label("longitude:", GUILayout.Width(60f)); _settings.resolution.longitude = Mathf.Clamp( EditorGUILayout.IntField(_settings.resolution.longitude, GUILayout.Width(60f)), 1, int.MaxValue ); GUILayout.Label($"({ metersPerDegreeLongitude.ToString("0.##") } [m])"); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); { GUILayout.Label("Max Coordinates Per Request"); settings.maxCoordinatesPerRequest = EditorGUILayout.IntField(settings.maxCoordinatesPerRequest); } EditorGUILayout.EndHorizontal(); } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); GUILayout.BeginVertical("- PROCESS -", "window"); { GUILayout.BeginHorizontal(); GUILayout.Label("api key: ", GUILayout.ExpandWidth(false)); _key = GUILayout.PasswordField(_key != null ? _key : "", '*'); GUILayout.EndHorizontal(); //start button: if (GUILayout.Button("START HTTP REQUESTS", GUILayout.Height(EditorGUIUtility.singleLineHeight * 2f))) { string filePath = EditorUtility.SaveFilePanel( $"Save data file", _core.GetFolderPath(), _core.GetFileNamePrefix( _settings.start, _settings.end, _settings.resolution ), "csv" ); if (filePath.Length != 0) { _taskTicket = new Ticket <float>(0f); _mainTask = _core.GetElevationData( filePath: filePath, serviceProvider: _serviceProvider, apikey: _key, ticket: _taskTicket, start: _settings.start, end: _settings.end, resolution: _settings.resolution, maxCoordinatesPerRequest: _settings.maxCoordinatesPerRequest, this.Repaint, () => { if (_onFinished == EOnFinished.createImage) { _core.WriteImageFile( filePath.Replace(".csv", ".png"), _settings.resolution.longitude, _settings.resolution.latitude, _createImageSettings.offset, _createImageSettings.lerp ); } //flash editor window (will it even does that?) EditorWindow.GetWindow <MainWindow>().Show(); }, _logTraffic ); } else { Debug.Log("Cancelled by user"); } } bool working = _mainTask != null && _mainTask.Status != TaskStatus.RanToCompletion && _mainTask.Status != TaskStatus.Canceled; //progress bar: if (working) { bool b = GUI.enabled; GUI.enabled = true; EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), _taskTicket.value, "progress"); GUI.enabled = b; } //abort button: bool abortingInProgress = working && _taskTicket.invalid; GUI.enabled = _isReady == false && abortingInProgress == false; { string abortButtonLabel = abortingInProgress ? "Aborting..." : "Abort"; if (GUILayout.Button(abortButtonLabel)) { _taskTicket.Invalidate(); } } GUI.enabled = _isReady; //toggles { bool GUIenabled = GUI.enabled; GUI.enabled = true; { //log traffic toggle: _logTraffic = EditorGUILayout.Toggle("log traffic:", _logTraffic); //do on finished: _onFinished = (EOnFinished)EditorGUILayout.EnumFlagsField("On Finished:", _onFinished); } GUI.enabled = GUIenabled; } } GUILayout.EndVertical(); GUILayout.FlexibleSpace(); GUILayout.BeginVertical("- TOOLS -", "window"); { //tools are (should be) independent from http process, so make sure GUI is enabled: GUI.enabled = true; // if (GUILayout.Button("Create Image", GUILayout.Height(EditorGUIUtility.singleLineHeight * 2f))) { CreateImageWindow.CreateWindow(this); } } GUILayout.EndVertical(); EditorGUILayout.Separator(); } EditorGUILayout.EndScrollView(); EditorGUILayout.Separator(); }
public async Task <string> HttpRequest ( IElevationServiceProvider serviceProvider, Stack <Coordinate> coordinates, string apikey, int maxCoordinatesPerRequest, Ticket ticket, bool logTraffic ) { //assertions: if (coordinates.Count == 0) { Debug.LogWarning("coordinates.Count is 0"); return(null); } // List <Coordinate> requestList = new List <Coordinate>(); //const int lengthLimit = 102375;//(bytes) this number is guesstimation, i found errors but no documentation on this int limit = maxCoordinatesPerRequest;//2200;//guesstimation for (int i = 0; i < limit && coordinates.Count != 0; i++) { requestList.Add(coordinates.Pop()); } //create the HttpContent for the form to be posted: System.Net.Http.ByteArrayContent requestContent = null; if (serviceProvider.httpMethod == HttpMethod.Post) { string json = serviceProvider.GetRequestContent(requestList); byte[] buffer = System.Text.Encoding.ASCII.GetBytes(json); requestContent = new ByteArrayContent(buffer); requestContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); //Debug.Log( "requestContent.Headers.ContentLength.Value: " + requestContent.Headers.ContentLength.Value ); //log request: if (logTraffic) { Debug.Log($"requesting { requestList.Count } values:\n{ json }"); } } //get the stream of the content. string result = null; while (result == null && ticket.valid) { try { HttpResponseMessage response; if (serviceProvider.httpMethod == HttpMethod.Post) { response = await _client.PostAsync( serviceProvider.RequestUri(null, apikey), requestContent ); } else if (serviceProvider.httpMethod == HttpMethod.Get) { response = await _client.GetAsync( serviceProvider.RequestUri(serviceProvider.GetRequestContent(requestList), apikey) ); } else { throw new System.NotImplementedException(); } result = await response.Content.ReadAsStringAsync(); if (result.StartsWith("<html>")) { const string ERROR_504 = "504 Gateway Time-out"; const string ERROR_502 = "502 Bad Gateway"; const string ERROR_500 = "500 Internal Server Error"; //log warning: if (result.Contains(ERROR_504)) { Debug.LogWarning(ERROR_504); } else if (result.Contains(ERROR_502)) { Debug.LogWarning(ERROR_502); } else if (result.Contains(ERROR_500)) { Debug.LogWarning(ERROR_500); } else { Debug.LogWarning($"invalid response:\n{ result }"); } //invalidate: result = null; await Task.Delay(1000); //try again after delay } else if (result.StartsWith("{\"error\": \"Invalid JSON.\"}")) { //log warning: Debug.LogWarning($"invalid JSON. Try decreasing { nameof(maxCoordinatesPerRequest) }"); await Task.Delay(1000); //try again after delay } } catch (System.Net.WebException ex) { Debug.LogException(ex); await Task.Delay(1000); //try again after delay } catch (System.Exception ex) { Debug.LogException(ex); await Task.Delay(1000); //try again after delay } } //log response: if (logTraffic) { Debug.Log($"\tresponse:\n{ result }"); } //return results: return(result); }
public async Task GetElevationData ( string filePath, IElevationServiceProvider serviceProvider, string apikey, Ticket <float> ticket, Coordinate start, Coordinate end, CoordinateInt resolution, int maxCoordinatesPerRequest, System.Action repaintWindowCallback, System.Action onFinish, bool logTraffic ) { Debug.Log($"{ nameof(GetElevationData) }() started"); IO.FileStream stream = null; IO.StreamWriter writer = null; try { int skip; //open file stream: { IO.FileMode fileMode; if ( IO.File.Exists(filePath) && EditorUtility.DisplayDialog( "Decide", "CONTINUE: Setting must match to succeessfully continue\nOVERWRITE: data will be lost", "CONTINUE", "OVERWRITE" ) ) { fileMode = IO.FileMode.Append; skip = 0; ForEachLine( filePath, (line) => skip++ ); } else { fileMode = IO.FileMode.Create; skip = 0; } stream = new IO.FileStream( filePath, fileMode, IO.FileAccess.Write, IO.FileShare.Read, 4096, IO.FileOptions.SequentialScan ); writer = new IO.StreamWriter(stream); } //populate stack: Stack <Coordinate> coordinates = new Stack <Coordinate>(); { //NOTE: i bet this wont work for ranges overlaping -180/180 latitude crossline etc Coordinate origin = new Coordinate { longitude = Mathf.Min(start.longitude, end.longitude), latitude = Mathf.Min(start.latitude, end.latitude) }; float stepX = Mathf.Abs(end.longitude - start.longitude) / (float)resolution.longitude; float stepY = Mathf.Abs(end.latitude - start.latitude) / (float)resolution.latitude; for (int Y = 0; Y < resolution.latitude; Y++) { for (int X = 0; X < resolution.longitude; X++) { coordinates.Push( new Coordinate { latitude = origin.latitude + (float)Y * stepY, longitude = origin.longitude + (float)X * stepX } ); } } } int numStartingCoordinates = coordinates.Count; //skip entries (if applies): if (skip != 0) { Debug.Log($"Skipping { skip } entries"); for (int i = 0; i < skip; i++) { coordinates.Pop(); } } //process stack in batches: List <float> elevations = new List <float>(maxCoordinatesPerRequest); while (coordinates.Count != 0) { //call api: { //get response: string response = await HttpRequest( serviceProvider : serviceProvider, coordinates : coordinates, apikey : apikey, maxCoordinatesPerRequest : maxCoordinatesPerRequest, ticket : ticket, logTraffic : logTraffic ); // if (serviceProvider.ParseResponse(response, elevations)) { if (elevations.Count != 0) { //write entries to file: foreach (float elevation in elevations) { writer.WriteLine(elevation); } elevations.Clear(); } else { throw new System.Exception("Parsed response contains no entries"); } } else { throw new System.Exception("Parse failed"); } } // ticket.value = 1f - ((float)coordinates.Count / (float)numStartingCoordinates); repaintWindowCallback(); //test for abort: if (ticket.invalid) { repaintWindowCallback(); throw new System.Exception("aborted"); } } //task done: ticket.value = 1f; repaintWindowCallback(); Debug.Log(coordinates.Count == 0 ? "SUCCESS!" : $"ERROR, unprocessed coordinates: { coordinates.Count } )"); await Task.CompletedTask; } catch (System.Exception ex) { Debug.LogException(ex); } finally { //log: Debug.Log($"{ nameof(GetElevationData) }() finished"); //close streams: if (writer != null) { writer.Close(); } if (stream != null) { stream.Close(); } //call on finish: if (onFinish != null) { onFinish(); } } }