public static ulong[] GetCellIdsForLatLong(double latitude, double longitude) { var latLong = S2LatLng.FromDegrees(latitude, longitude); var cell = S2CellId.FromLatLng(latLong); var cellId = cell.ParentForLevel(15); var cells = cellId.GetEdgeNeighbors(); var cellIds = new List <ulong> { cellId.Id }; foreach (var cellEdge1 in cells) { if (!cellIds.Contains(cellEdge1.Id)) { cellIds.Add(cellEdge1.Id); } foreach (var cellEdge2 in cellEdge1.GetEdgeNeighbors()) { if (!cellIds.Contains(cellEdge2.Id)) { cellIds.Add(cellEdge2.Id); } } } return(cellIds.ToArray()); }
private S2CellId getCellId(double latDegrees, double lngDegrees) { var id = S2CellId.FromLatLng(S2LatLng.FromDegrees(latDegrees, lngDegrees)); Trace.WriteLine(Convert.ToString(unchecked ((long)id.Id), 16)); return(id); }
public static ulong GetPokeCell(ICoordinate poke) { var latLng = S2LatLng.FromDegrees((double)poke.Latitude, (double)poke.Longitude); var hash = S2CellId.FromLatLng(latLng).ParentForLevel(20).Id; return(hash); }
public void AddUser(Guid uid, double lon, double lat) { var lonLat = S2LatLng.FromDegrees(lat, lon); var cellId = S2CellId.FromLatLng(lonLat); var cellIdStorageLevel = cellId.ParentForLevel(_level); var userList = new UserList { s2CellId = cellIdStorageLevel, list = new List <Guid>() }; var item = tree.Search(userList.s2CellId); if (item != null) { userList = new UserList { s2CellId = item.Key, list = item.Pointer }; tree.Delete(userList.s2CellId); } if (userList.list == null) { userList.list = new List <Guid>(); } userList.list.Add(uid); tree.Insert(userList.s2CellId, userList.list); }
public void testInverses() { Trace.WriteLine("TestInverses"); // Check the conversion of random leaf cells to S2LatLngs and back. for (var i = 0; i < 200000; ++i) { var id = getRandomCellId(S2CellId.MaxLevel); Assert.True(id.IsLeaf && id.Level == S2CellId.MaxLevel); var center = id.ToLatLng(); JavaAssert.Equal(S2CellId.FromLatLng(center).Id, id.Id); } }
public static List <ulong> GetNearbyCellIds(double longitude, double latitude) { var nearbyCellIds = new List <S2CellId>(); var cellId = S2CellId.FromLatLng(S2LatLng.FromDegrees(latitude, longitude)).ParentForLevel(15);//.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent; nearbyCellIds.Add(cellId); for (int i = 0; i < 10; i++) { nearbyCellIds.Add(GetPrevious(cellId, i)); nearbyCellIds.Add(GetNext(cellId, i)); } return(nearbyCellIds.Select(c => c.Id).OrderBy(c => c).ToList()); }
private async Task <ServiceResponse> ConvertPokestopToGym(IPokestop pokestop, string newName) { var gym = GymRepository.CreateInstance(); gym.Name = pokestop.Name; gym.ExternalId = pokestop.ExternalId; gym.PictureUrl = pokestop.Url; gym.Latitude = pokestop.Latitude; gym.Longitude = pokestop.Longitude; // Calculate WeatherCellId var latlng = S2LatLng.FromDegrees(pokestop.Latitude, pokestop.Longitude); var cellId = S2CellId.FromLatLng(latlng); var level10 = cellId.ParentForLevel(10); gym.WeatherCellId = level10.Id; //await GymRepository.AddAsync(gym); //await Repository.DeleteAsync(pokestop); return(new ServiceResponse(true, "Pokestop converted to Gym. WeatherCellId: " + gym.WeatherCellId)); }
public static List <ulong> GetNearbyCellIds(double longitude, double latitude) { var nearbyCellIds = new List <S2CellId>(); var cellId = S2CellId.FromLatLng(S2LatLng.FromDegrees(latitude, longitude)).ParentForLevel(15); nearbyCellIds.Add(cellId); var neighbours = new List <S2CellId>(); cellId.GetAllNeighbors(15, neighbours); foreach (var neighbour in neighbours) { nearbyCellIds.Add(neighbour); nearbyCellIds.AddRange(neighbour.GetEdgeNeighbors()); } return(nearbyCellIds.Select(c => c.Id).Distinct().OrderBy(c => c).ToList()); }
public void AddUser(Guid uid, double lon, double lat) { lock (locker) { var lonLat = S2LatLng.FromDegrees(lat, lon); var cellId = S2CellId.FromLatLng(lonLat); var cellIdStorageLevel = cellId.ParentForLevel(_level); _currentUsersLocations[uid] = cellIdStorageLevel; var query_res = rtree.Search(new UserList() { s2CellId = cellIdStorageLevel }); var users = new List <Guid>(); if (query_res.Count > 0) { foreach (var item in query_res) { item.Start.list.Add(uid); } return; } users.Add(uid); var toinsert = new UserList() { s2CellId = cellIdStorageLevel, list = users }; rtree.Add(new Interval <UserList>() { Start = toinsert, End = toinsert }); } }
public void AddUser(Guid uid, double lon, double lat) { var lonLat = S2LatLng.FromDegrees(lat, lon); var cellId = S2CellId.FromLatLng(lonLat); var cellIdStorageLevel = cellId.ParentForLevel(_level); //var userList = new UserList { s2CellId = cellIdStorageLevel, list = new List<Guid>() }; var query_res = rtree.Query(cellIdStorageLevel); _currentUsersLocations[uid] = cellIdStorageLevel; SimpleRangeItem rangeItem = null; if (query_res.Count > 0) { var users = new List <Guid>(); foreach (var item in query_res) { users.AddRange(item.Content); } rangeItem = new SimpleRangeItem { Range = new Range <S2CellId>(cellIdStorageLevel), Content = users }; rtree.Remove(query_res[0]); } if (rangeItem == null) { rangeItem = new SimpleRangeItem { Range = new Range <S2CellId>(cellIdStorageLevel), Content = new List <Guid> () }; } rangeItem.Content.Add(uid); rtree.Add(rangeItem); }
// Handle MAD data /* * [ * HttpPost("/raw"), * Produces("application/json"), * ] * public async Task<ProtoResponse> PostAsync(List<ProtoData> payloads) * { * Response.Headers["Accept"] = "application/json"; * Response.Headers["Content-Type"] = "application/json"; * var response await HandleProtoRequest(new ProtoPayload * { * Username = "******", * Uuid = Request.Headers["Origin"], * Contents = payloads, * }); * return response; * } */ #endregion #region Handlers private async Task <ProtoResponse> HandleProtoRequest(ProtoPayload payload) { if (payload == null) { _logger.LogError("Invalid proto payload received"); return(null); } var stopwatch = new Stopwatch(); stopwatch.Start(); var device = await _deviceRepository.GetByIdAsync(payload.Uuid).ConfigureAwait(false); if (device != null) { device.LastLatitude = payload.LatitudeTarget; device.LastLongitude = payload.LongitudeTarget; device.LastSeen = DateTime.UtcNow.ToTotalSeconds(); await _deviceRepository.UpdateAsync(device).ConfigureAwait(false); } if (!string.IsNullOrEmpty(payload.Username) && payload.Level > 0) { if (!_levelCache.ContainsKey(payload.Username)) { _levelCache.Add(payload.Username, payload.Level); } else { var oldLevel = _levelCache[payload.Username]; if (oldLevel != payload.Level) { var account = await _accountRepository.GetByIdAsync(payload.Username).ConfigureAwait(false); if (account != null) { account.Level = payload.Level; await _accountRepository.UpdateAsync(account).ConfigureAwait(false); } _levelCache[payload.Username] = payload.Level; } } } if (payload.Contents?.Count == 0) { _logger.LogWarning($"[Proto] [{payload.Uuid}] Invalid GMO"); return(null); } var wildPokemon = 0; var nearbyPokemon = 0; var clientWeather = 0; var forts = 0; var fortDetails = new List <FortDetailsOutProto>(); var quests = 0; var fortSearch = 0; var encounters = 0; var cells = new List <ulong>(); var inventory = new List <InventoryDeltaProto>(); var playerData = 0; //var spawnpoints = new List<Spawnpoint>(); var isEmptyGmo = true; var isInvalidGmo = true; var containsGmo = false; if (payload.Contents == null) { _logger.LogWarning($"[Proto] [{payload.Uuid}] Empty data"); return(null); } Coordinate targetCoord = null; var inArea = false; if (payload.LatitudeTarget != 0 && payload.LongitudeTarget != 0) { targetCoord = new Coordinate(payload.LatitudeTarget, payload.LongitudeTarget); } var targetKnown = false; S2CellId targetCellId = default; if (targetCoord != null) { // Check target is within cell id instead of checking geofences targetKnown = true; targetCellId = S2CellId.FromLatLng(S2LatLng.FromDegrees(targetCoord.Latitude, targetCoord.Longitude)); //_logger.LogDebug($"[Proto] [{payload.Uuid}] Data received within target area {targetCoord} and target distance {payload.TargetMaxDistance}"); } //_logger.LogWarning($"[{device.Uuid}] InArea={inArea}"); foreach (var rawData in payload.Contents) { if (string.IsNullOrEmpty(rawData.Data)) { _logger.LogWarning($"[Proto] [{payload.Uuid}] Unhandled proto {rawData.Method}: {rawData.Data}"); continue; } var data = rawData.Data; var method = (Method)rawData.Method; switch (method) { case Method.GetPlayer: try { var gpr = GetPlayerOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (gpr?.Success == true) { await PushData(RedisChannels.ProtoAccount, new { gpr, username = payload.Username, }); playerData++; } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetPlayerOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetPlayerOutProto: {ex}"); } break; case Method.GetHoloholoInventory: try { var ghi = GetHoloholoInventoryOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (ghi?.Success == true) { if (ghi.InventoryDelta.InventoryItem?.Count > 0) { // TODO: Publish with redis inventory.Add(ghi.InventoryDelta); } } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetHoloholoInventoryOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetHoloholoInventoryOutProto: {ex}"); } break; case Method.FortSearch: try { var fsr = FortSearchOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (fsr != null) { if (fsr.ChallengeQuest?.Quest != null) { await PushData(RedisChannels.ProtoQuest, new { raw = data, }); quests++; } //fortSearch.Add(fsr); fortSearch++; } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed FortSearchOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode FortSearchOutProto: {ex}"); } break; case Method.Encounter: isEmptyGmo = false; isInvalidGmo = false; try { if (payload.Level >= 30) { var er = EncounterOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (er?.Status == EncounterOutProto.Types.Status.EncounterSuccess) { await PushData(RedisChannels.ProtoEncounter, new { data = er, username = payload.Username, }); encounters++; } else if (er == null) { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed EncounterOutProto"); } } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode EncounterOutProto: {ex}"); } break; case Method.FortDetails: try { var fdr = FortDetailsOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (fdr != null) { fortDetails.Add(fdr); //fortDetails++; // TODO: Publish with redis //await PublishData(RedisChannels.Fort, fdr); } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed FortDetailsOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode FortDetailsOutProto: {ex}"); } break; case Method.GetMapObjects: containsGmo = true; try { var gmo = GetMapObjectsOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (gmo != null) { isInvalidGmo = false; var mapCellsNew = gmo.MapCell; if (mapCellsNew.Count == 0) { //_logger.LogDebug($"[Proto] [{payload.Uuid}] Map cells are empty"); //return null; } // Check if we're within the same cell, if so then we are within the target distance if (!inArea && targetKnown && mapCellsNew.Select(x => x.S2CellId).Contains(targetCellId.Id)) { inArea = true; } foreach (var mapCell in mapCellsNew) { cells.Add(mapCell.S2CellId); await PushData(RedisChannels.ProtoCell, mapCell.S2CellId); var tsMs = mapCell.AsOfTimeMs; foreach (var wild in mapCell.WildPokemon) { await PushData(RedisChannels.ProtoWildPokemon, new { cell = mapCell.S2CellId, data = wild, timestamp_ms = tsMs, username = payload.Username, }); wildPokemon++; } foreach (var nearby in mapCell.NearbyPokemon) { await PushData(RedisChannels.ProtoNearbyPokemon, new { cell = mapCell.S2CellId, data = nearby, timestamp_ms = tsMs, username = payload.Username, }); nearbyPokemon++; } foreach (var fort in mapCell.Fort) { await PushData(RedisChannels.ProtoFort, new { cell = mapCell.S2CellId, data = fort, }); forts++; } } foreach (var weather in gmo.ClientWeather) { await PushData(RedisChannels.ProtoWeather, new Weather(weather)); clientWeather++; } if (wildPokemon == 0 && nearbyPokemon == 0 && forts == 0 && quests == 0) { foreach (var cellId in cells) { if (!_emptyCells.ContainsKey(cellId)) { _emptyCells.Add(cellId, 1); } else { _emptyCells[cellId]++; } if (_emptyCells[cellId] == 3) { _logger.LogWarning($"[Proto] [{payload.Uuid}] Cell {cellId} was empty 3 times in a row, assuming empty..."); await PushData(RedisChannels.ProtoCell, cellId); } } _logger.LogDebug($"[Proto] [{payload.Uuid}] GMO is empty"); isEmptyGmo = true; } else { cells.ForEach(cellId => _emptyCells[cellId] = 0); isEmptyGmo = false; } } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GetMapObjectsOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GetMapObjectsOutProto: {ex}"); } break; case Method.GymGetInfo: try { var ggi = GymGetInfoOutProto.Parser.ParseFrom(Convert.FromBase64String(data)); if (ggi != null) { if (ggi.GymStatusAndDefenders == null) { ConsoleExt.WriteWarn($"[DataConsumer] Invalid GymStatusAndDefenders provided, skipping...\n: {ggi}"); continue; } var fortId = ggi.GymStatusAndDefenders.PokemonFortProto.FortId; var gymDefenders = ggi.GymStatusAndDefenders.GymDefender; if (gymDefenders == null) { continue; } foreach (var gymDefender in gymDefenders) { if (gymDefender.TrainerPublicProfile != null) { await PushData(RedisChannels.ProtoGymTrainer, new Trainer(gymDefender)); } if (gymDefender.MotivatedPokemon != null) { await PushData(RedisChannels.ProtoGymDefender, new GymDefender(fortId, gymDefender)); } } } else { _logger.LogError($"[Proto] [{payload.Uuid}] Malformed GymGetInfoOutProto"); } } catch (Exception ex) { _logger.LogError($"[Proto] [{payload.Uuid}] Unable to decode GymGetInfoOutProto: {ex}"); } break; //case Method.Unset: default: _logger.LogDebug($"[Proto] [{payload.Uuid}] Invalid method or data provided. {method}:{data}"); break; } } Coordinate pokemonCoords = null; /* * if (targetCoord != null) * { * foreach (var fort in forts) * { * if (!inArea) * { * var coord = new Coordinate(fort.data.Latitude, fort.data.Longitude); * if (coord.DistanceTo(targetCoord) <= payload.TargetMaxDistance) * { * inArea = true; * } * } * } * } * if (targetCoord != null || payload.PokemonEncounterId != null) * { * foreach (var pokemon in wildPokemons) * { * WildPokemonProto wild = (WildPokemonProto)pokemon.data; * if (targetCoord != null) * { * if (pokemonCoords != null && inArea) * { * break; * } * * if (!inArea) * { * var coord = new Coordinate(wild.Latitude, wild.Longitude); * if (coord.DistanceTo(targetCoord) <= payload.TargetMaxDistance) * { * inArea = true; * } * } * } * if (!string.IsNullOrEmpty(payload.PokemonEncounterId)) * { * if (pokemonCoords != null && inArea) * { * break; * } * * if (pokemonCoords == null) * { * if (string.Compare(wild.EncounterId.ToString(), payload.PokemonEncounterId, true) == 0) * { * pokemonCoords = new Coordinate(wild.Latitude, wild.Longitude); * } * } * } * } * } * if (targetCoord != null && !inArea) * { * foreach (var cell in cells) * { * if (inArea) * { * break; * } * * var s2cell = new S2Cell(new S2CellId(cell)); * var latlng = new S2LatLng(s2cell.Center); * var coord = new Coordinate(latlng.LatDegrees, latlng.LngDegrees); * if (coord.DistanceTo(targetCoord) <= Math.Max(payload.TargetMaxDistance ?? 250, 100)) * { * inArea = true; * } * } * } */ stopwatch.Stop(); var response = new ProtoResponse { Status = "ok", Data = new ProtoDataDetails { Nearby = nearbyPokemon, Wild = wildPokemon, Forts = forts, Quests = quests, FortSearch = fortSearch, Encounters = encounters, Level = payload.Level, OnlyEmptyGmos = containsGmo && isEmptyGmo, OnlyInvalidGmos = containsGmo && isInvalidGmo, ContainsGmos = containsGmo, InArea = inArea, LatitudeTarget = targetCoord?.Latitude, LongitudeTarget = targetCoord?.Longitude, PokemonLatitude = pokemonCoords?.Latitude, PokemonLongitude = pokemonCoords?.Longitude, PokemonEncounterId = payload.PokemonEncounterId, }, }; _logger.LogInformation($"[{payload.Uuid}] {response.ToJson()} parsed in {stopwatch.Elapsed.TotalSeconds}s"); return(response); }
public bool UpdateUser(Guid uid, double lon, double lat) { lock (locker) { var lonLat = S2LatLng.FromDegrees(lat, lon); var cellId = S2CellId.FromLatLng(lonLat); var cellIdStorageLevel = cellId.ParentForLevel(_level); if (!_currentUsersLocations.ContainsKey(uid)) { return(false); } var oldCell = _currentUsersLocations[uid]; if (oldCell == cellIdStorageLevel) { return(true); } _currentUsersLocations[uid] = cellIdStorageLevel; var query_res = rtree.Search(new UserList() { s2CellId = oldCell }); var users = new List <Guid>(); if (query_res.Count > 0) { //remove from old cell foreach (var item in query_res) { item.Start.list.Remove(uid); if (item.Start.list.Count == 0) { rtree.Remove(item); } } } query_res = rtree.Search(new UserList() { s2CellId = cellIdStorageLevel }); if (query_res.Count > 0) { foreach (var item in query_res) { item.Start.list.Add(uid); } return(true); } users.Add(uid); var toinsert = new UserList() { s2CellId = cellIdStorageLevel, list = users }; rtree.Add(new Interval <UserList>() { Start = toinsert, End = toinsert }); return(true); } }