CLLocationManager and CLGeoCoder - xamarin.ios

I want to use coordinate of the actual location (CLLocationManager) to reverse geocoding (CLGeoCoder).
I have this code:
locationMgr = new CLLocationManager();
locationMgr.DesiredAccuracy = CLLocation.AccuracyNearestTenMeters;
locationMgr.DistanceFilter = 10;
locationMgr.UpdatedLocation += (object sender, CLLocationUpdatedEventArgs e) => {
Task.latitude = e.NewLocation.Coordinate.Latitude;
Task.longitude = e.NewLocation.Coordinate.Longitude;
locationMgr.StopUpdatingLocation();
};
btnLocation = new UIBarButtonItem(UIImage.FromFile("Icons/no-gps.png"), UIBarButtonItemStyle.Plain, (s,e) => {
if (CLLocationManager.LocationServicesEnabled) {
locationMgr.StartUpdatingLocation();
geoCoder = new CLGeocoder();
geoCoder.ReverseGeocodeLocation(new CLLocation(Task.latitude, Task.longitude), (CLPlacemark[] place, NSError error) => {
adr = place[0].Name+"\n"+place[0].Locality+"\n"+place[0].Country;
Utils.ShowAlert(XmlParse.LocalText("Poloha"), Task.latitude.ToString()+"\n"+Task.longitude.ToString()+"\n\n"+adr);
});
}
else {
Utils.ShowAlert(XmlParse.LocalText("PolohVypnut"));
}
});
Because UpdatedLocation() take some seconds, input of ReverseGeocodeLocation() is Task.latitude=0 and Task.longitude=0.
How can I wait for right values (Task.latitude, Task.longitude) before ReverseGoecodeLocation()?
Thanks for any help.

Your geocoder's ReverseGeocodeLocation method is called before the CLLocationManager gets a location.
Calling StartUpdatingLocation does not mean that the UpdatedLocation event will be triggered immediately. Furthermore, if you are on iOS 6, UpdatedLocation will never be triggered. Use the LocationsUpdated event instead.
Example:
locationManager.LocationsUpdated += (sender, args) => {
// Last item in the array is the latest location
CLLocation latestLocation = args.Locations[args.Locations.Length - 1];
geoCoder = new CLGeocoder();
geoCoder.ReverseGeocodeLocation(latestLocation, (pl, er) => {
// Read placemarks here
});
};
locationManager.StartUpdatingLocation();

Related

How do you show multiple locations on a map with .NET MAUI?

I have been able to open the default map application and display a single location:
var location = new Location(latitude, longitude);
var options = new MapLaunchOptions { Name = locationName };
try
{
await Map.Default.OpenAsync(location, options);
}
catch (Exception ex)
{
// No map application available to open
}
Wondering if the ability to open with multiple locations pinned exists?
You will first need to load in the location data, whether that is from an embedded resource or API call. Once you have the lat/lng data pulled in (mine is in a List) you can go ahead and add them. You will need map.Layers.Add(CreatePointLayer()); to call the code below:
private MemoryLayer CreatePointLayer()
{
return new MemoryLayer
{
Name = "Points",
IsMapInfoLayer = true,
Features = GetLocsFromList(),
Style = SymbolStyles.CreatePinStyle()
};
}
private IEnumerable<IFeature> GetLocsFromList()
{
var locs = Locs; //<- Locs is the List<Locations>
return locs.Select(l => {
var feature = new PointFeature(SphericalMercator.FromLonLat(l.lng, l.lat).ToMPoint());
return feature;
});
}

Service Fabric Actor notification fails to trigger event handler after first invocation due to possible blocking

I've got 2 Reliable actors called GameActor and PlayerActor. The ClientApp send a message to the PlayerActor when the player makes a move. Then the PlayerActor sends a message to the GameActor to indicate a movement was made. Upon being invoked, the method in the GameActor fires a notification. This notification gets handled by the ClientApp GameEventsHandler. The ClientApp then calls a method on the GameActor to retrieve the latest player positions.
ClientApp -> PlayerActor.MoveTo() -> GameActor.NotifyPlayerMoved() ->
Fire ScoreBoardUpdated event
GameEventsHandler triggered by that event ->
GameActor.GetLatestPlayerInfo()
The problem I'm having is this. The very first time I run it, the GameEventsHandler gets triggered and it tries to call the GameActor as expected. The GameActor receives the message and returns the response expected. But the client doesn't seem to receive the message. It looks like it's blocked as it doesn't throw and error or any output. Any subsequent notifications don't get handled by the event handler at all.
GameActor
public async Task<IList<PlayerInfo>> GetLatestPlayerInfoAsync(CancellationToken cancellationToken)
{
var allPlayers = await StateManager.GetStateAsync<List<string>>("players", cancellationToken);
var tasks = allPlayers.Select(actorName =>
{
var playerActor = ActorProxy.Create<IPlayerActor>(new ActorId(actorName), new Uri(PlayerActorUri));
return playerActor.GetLatestInfoAsync(cancellationToken);
}).ToList();
await Task.WhenAll(tasks);
return tasks
.Select(t => t.Result)
.ToList();
}
public async Task NotifyPlayerMovedAsync(PlayerInfo lastMovement, CancellationToken cancellationToken)
{
var ev = GetEvent<IGameEvents>();
ev.ScoreboardUpdated(lastMovement);
}
PlayerActor
public async Task MoveToAsync(int x, int y, CancellationToken cancellationToken)
{
var playerName = await StateManager.GetStateAsync<string>("playerName", cancellationToken);
var playerInfo = new PlayerInfo()
{
LastUpdate = DateTimeOffset.Now,
PlayerName = playerName,
XCoordinate = x,
YCoordinate = y
};
await StateManager.AddOrUpdateStateAsync("positions", new List<PlayerInfo>() { playerInfo }, (key, value) =>
{
value.Add(playerInfo);
return value;
}, cancellationToken);
var gameName = await StateManager.GetStateAsync<string>("gameName", cancellationToken);
var gameActor = ActorProxy.Create<IGameActor>(new ActorId(gameName), new Uri(GameActorUri));
await gameActor.NotifyPlayerMovedAsync(playerInfo, cancellationToken);
}
public async Task<PlayerInfo> GetLatestInfoAsync(CancellationToken cancellationToken)
{
var positions = await StateManager.GetStateAsync<List<PlayerInfo>>("positions", cancellationToken);
return positions.Last();
}
Client
private static async Task RunDemo(string gameName)
{
var rand = new Random();
Console.WriteLine("Hit return when the service is up...");
Console.ReadLine();
Console.WriteLine("Enter your name:");
var playerName = Console.ReadLine();
Console.WriteLine("This might take a few seconds...");
var gameActor = ActorProxy.Create<IGameActor>(new ActorId(gameName), new Uri(GameActorUri));
await gameActor.SubscribeAsync<IGameEvents>(new GameEventsHandler(gameActor));
var playerActorId = await gameActor.JoinGameAsync(playerName, CancellationToken.None);
var playerActor = ActorProxy.Create<IPlayerActor>(new ActorId(playerActorId), new Uri(PlayerActorUri));
while (true)
{
Console.WriteLine("Press return to move to new location...");
Console.ReadLine();
await playerActor.MoveToAsync(rand.Next(100), rand.Next(100), CancellationToken.None);
}
}
GameEventHandler
public void ScoreboardUpdated(PlayerInfo lastInfo)
{
Console.WriteLine($"Scoreboard updated. (Last move by: {lastInfo.PlayerName})");
var positions = _gameActor.GetLatestPlayerInfoAsync(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult();
//this hangs
foreach (var playerInfo in positions) // this line never gits hit
{
Console.WriteLine(
$"Position of {playerInfo.PlayerName} is ({playerInfo.XCoordinate},{playerInfo.YCoordinate})." +
$"\nUpdated at {playerInfo.LastUpdate}\n");
}
}
But if I wrap the event handler logic inside a Task.Run() it seems to work.
Task.Run(async () =>
{
var positions = await _gameActor.GetLatestPlayerInfoAsync(CancellationToken.None);
foreach (var playerInfo in positions)
{
Console.WriteLine(
$"Position of {playerInfo.PlayerName} is ({playerInfo.XCoordinate},{playerInfo.YCoordinate})." +
$"\nUpdated at {playerInfo.LastUpdate}\n");
}
}
);
Full source code for the demo here https://github.com/dasiths/Service-Fabric-Reliable-Actors-Demo
AFAIK notifications aren't blocking and are not reliable. So I don't understand why my initial implementation doesn't work. The reentrant pattern doesn't apply here as per my understanding either. Can someone explain to me what's going on here? Is it expected behaviour or a bug?

Phaserjs, sprite overlap, not working

I am new to Phaserjs, trying to create basic drag-drop style game.
I have created the game and add arcade physics (this.game.physics.arcade.enable(this.orange_outline);)
Currently overlap happen as soon as the edges collide.
I want to detect that my code should trigger when 50% overlap happen. is it possible in phaserjs?
var GameState = {
init:function(){
this.physics.startSystem(Phaser.Physics.ARCADE);
},
create: function () {
this.background = this.game.add.sprite(0, 0, 'background');
this.overlapHappen = false;
this.orange_outline = this.game.add.sprite(459,199,'orange_outline');
this.orange_outline.frame = 2;
this.orange_outline.anchor.setTo(.5);
this.orange_outline.customParams = {myName:'orange_outline',questionImg:'orange'};
this.orange_inner = this.game.add.sprite(150,197,'orange_inner');
this.orange_inner.anchor.setTo(.5);
this.orange_inner.customParams = {myName:'orange_inner',questionImg:'orange',targetKey:this.orange_outline,targetImg:'orange_outline'};
this.orange_inner.frame = 1;
this.orange_inner.inputEnabled = true;
this.orange_inner.input.enableDrag();
this.orange_inner.input.pixelPerfectOver = true;
this.orange_inner.events.onDragStart.add(this.onDragStart,this);
// this.game.physics.enable(this.orange_inner,Phaser.Physics.ARCADE);
this.game.physics.arcade.enable(this.orange_inner);
this.game.physics.arcade.enable(this.orange_outline);
this.orange_inner.events.onDragStop.add(this.onDragStop,this);
},
update: function () {
//this.orange.animations.play('orange_one',1)
},
onDragStart:function(sprite,pointer){
//console.log(sprite.key + " dragged")
},
onDragStop:function(sprite,pointer){
var endSprite = sprite.customParams.targetKey;
//console.log(sprite.customParams);
this.stopDrag(sprite,endSprite)
},
stopDrag:function(currentSprite,endSprite){
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
var currentSpriteTarget = currentSprite.customParams.targetImg;
var endSpriteName = endSprite.customParams.myName;
if(currentSpriteTarget === endSpriteName){
currentSprite.input.draggable = false;
currentSprite.position.copyFrom(endSprite.position);
currentSprite.anchor.setTo(endSprite.anchor.x, endSprite.anchor.y);
}
console.log(currentSpriteTarget,endSpriteName);
})) {
//currentSprite.position.copyFrom(currentSprite.originalPosition);
console.log('you')
}
}
}
In stopDrag() I am detecting overlap.
You can try to get the amount of horizontal and vertical overlap amount and check if it satisfies a certain threshold. This can be done in additional overlap function callback, that is called processCallback in documentation. As an example:
if (!this.game.physics.arcade.overlap(currentSprite, endSprite, function() {
//your callback !
},function() {
if (this.game.physics.arcade.getOverlapX(currentSprite, endSprite) > currentSprite.width / 2
&& this.game.physics.arcade.getOverlapY(currentSprite, endSprite) > currentSprite.height / 2) {
//Overlaping !
return true;
} else {
//as if no overlap occured
return false;
}
},this) {
//
}
Another way to do this (other than what Hamdi Douss offers) is to resize your body to only take up 50% of the area. This will automatically ensure that collisions/overlap don't occur unless the reduced bodies touch each other.
To view your current body, use Phaser's debug methods
this.game.debug.body(someSprite, 'rgba(255,0,0,0.5)');

C# how to call async await in a for loop

I am developing a quartz.net job which runs every 1 hour. It executes the following method. I am calling a webapi inside a for loop. I want to make sure i return from the GetChangedScripts() method only after all thread is complete? How to do this or have i done it right?
Job
public void Execute(IJobExecutionContext context)
{
try
{
var scripts = _scriptService.GetScripts().GetAwaiter().GetResult();
}
catch (Exception ex)
{
_logProvider.Error("Error while executing Script Changed Notification job : " + ex);
}
}
Service method:
public async Task<IEnumerable<ChangedScriptsByChannel>> GetScripts()
{
var result = new List<ChangedScriptsByChannel>();
var currentTime = _systemClock.CurrentTime;
var channelsToProcess = _lastRunReader.GetChannelsToProcess().ToList();
if (!channelsToProcess.Any()) return result;
foreach (var channel in channelsToProcess)
{
var changedScripts = await _scriptRepository.GetChangedScriptAsync(queryString);
if (changedScriptsList.Any())
{
result.Add(new ChangedScriptsByChannel()
{
ChannelCode = channel.ChannelCode,
ChangedScripts = changedScriptsList
});
}
}
return result;
}
As of 8 days ago there was a formal announcement from the Quartz.NET team stating that the latest version, 3.0 Alpha 1 has full support for async and await. I would suggest upgrading to that if at all possible. This would help your approach in that you'd not have to do the .GetAwaiter().GetResult() -- which is typically a code smell.
How can I use await in a for loop?
Did you mean a foreach loop, if so you're already doing that. If not the change isn't anything earth-shattering.
for (int i = 0; i < channelsToProcess.Count; ++ i)
{
var changedScripts =
await _scriptRepository.GetChangedScriptAsync(queryString);
if (changedScriptsList.Any())
{
var channel = channelsToProcess[i];
result.Add(new ChangedScriptsByChannel()
{
ChannelCode = channel.ChannelCode,
ChangedScripts = changedScriptsList
});
}
}
Doing these in either a for or foreach loop though is doing so in a serialized fashion. Another approach would be to use Linq and .Select to map out the desired tasks -- and then utilize Task.WhenAll.

Universal app: Cannot bind `StreamSocketListener` after `EnableTransferOwnership`

I am following this sample to implement a background server universal app. Here is the experimental code:
void MainPage::OnConnectionReceived(StreamSocketListener^ sender, StreamSocketListenerConnectionReceivedEventArgs^ args)
{
OutputDebugString(L"Connection received\n");
// No idea how to transfer request handling from foreground to background task!
}
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
{
// Code to register background task is omitted
auto listener = ref new StreamSocketListener();
listener->Control->QualityOfService = SocketQualityOfService::Normal;
try
{
listener->EnableTransferOwnership(Task->TaskId, SocketActivityConnectedStandbyAction::Wake);
}
catch (...)
{
OutputDebugString(L"Error: cannot transfer ownership\n");
}
listener->ConnectionReceived += ref new TypedEventHandler<StreamSocketListener^, StreamSocketListenerConnectionReceivedEventArgs^>(this, &MainPage::OnConnectionReceived);
create_task(listener->BindServiceNameAsync("56789", SocketProtectionLevel::PlainSocket))
.then([this]()
{
OutputDebugString(L"Server started on port 56789\n");
auto m_httpClient = ref new HttpClient();
auto request = ref new HttpRequestMessage(HttpMethod::Get, ref new Uri("http://" + ip + ":56789/"));
auto request_operation = m_httpClient->SendRequestAsync(request, HttpCompletionOption::ResponseContentRead);
return create_task(request_operation);
}).then([this](task<HttpResponseMessage^> previousTask)
{
try {
auto response = previousTask.get();
// Code to process the response is omitted as it is irrelevant to the question
}
catch (Exception^ ex)
{
OutputDebugString(("Error: " + ex->Message + "\n")->Data());
}
});
}
At run time, I get the error: The attempted operation is not supported for the type of object referenced. which suggests that BindServiceNameAsync fails and I have no idea why as I have followed the documentation to do EnableTransferOwnership before doing the binding. What did I do wrong here?
You are getting The attempted operation is not supported for the type of object referenced. because you are using SocketActivityConnectedStandbyAction::Wake. Change it to SocketActivityConnectedStandbyAction::DoNotWake.
The following pseudo-code should give you an idea what else you need to do to make StreamSocketListener working with SocketActivityTrigger:
// TODO: task = socketTaskBuilder.Register();
socketListener = new StreamSocketListener();
socketListener.ConnectionReceived += OnConnected;
await socketListener.BindServiceNameAsync(port);
socketListener.EnableTransferOwnership(
task.TaskId,
SocketActivityConnectedStandbyAction.DoNotWake);
// This is required, otherwise you may get error:
// A device attached to the system is not functioning.
// (Exception from HRESULT: 0x8007001F)
await socketListener.CancelIOAsync();
socketListener.TransferOwnership(socketId);
Then, in the background task do:
public async void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
var details = taskInstance.TriggerDetails as
SocketActivityTriggerDetails;
var socketInformation = details.SocketInformation;
var streamSocket = socketInformation.StreamSocket;
var socketListener = socketInformation.StreamSocketListener;
switch (details.Reason)
{
case SocketActivityTriggerReason.ConnectionAccepted:
// TODO: read, write, etc.
break;
default:
// ...
break;
}
// ...
deferral.Complete();
}

Resources