Windows Phone Location API - c#

I am developing a location based social networking application and am using a geocoordinatewatcher on high accuracy and a movement threshold of 20m to obtain the user's location. My question is about the frequency of the location fixes. From the documentation, I gather that a movement threshold of 20m simply means that the position changed event is not triggered if the current location is 20m away from the location at the previous position changed event. This suggests that location fixes still happen, but they do not trigger the event handler if <20m. How does the device then decide how often to perform a location fix? Does changing the movement threshold change this in any way? Any extra documentation which I may have missed is welcome!
Thank you!

I think you are wanting to know about how MovementThreshold works and how to set that up.
basically you can say:
public class MyClass
{
private IGeoPositionWatcher<GeoCoordinate> _geoCoordinateWatcher;
/// <summary>
/// Gets the geo coordinate watcher.
/// </summary>
private IGeoPositionWatcher<GeoCoordinate> GeoCoordinateWatcher
{
get
{
if (_geoCoordinateWatcher == null)
{
_geoCoordinateWatcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);
((GeoCoordinateWatcher)_geoCoordinateWatcher).MovementThreshold = 3;
}
return _geoCoordinateWatcher;
}
}
}
Someplace else you might have
DispatcherTimer currentSpeedTimer = new DispatcherTimer();
currentSpeedTimer.Interval = new TimeSpan(0, 0, 1);
currentSpeedTimer.Tick += (sender, e) =>
{
if (this.GeoCoordinateWatcher.Position.Location.HorizontalAccuracy < 10)
{
if (DateTime.Now - this.GeoCoordinateWatcher.Position.Timestamp.DateTime > new TimeSpan(0, 0, 2))
{
CurrentSpeed = 0;
}
else
{
CurrentSpeed = double.IsNaN(this.GeoCoordinateWatcher.Position.Location.Speed) ? 0 : this.GeoCoordinateWatcher.Position.Location.Speed;
}
}
};
currentSpeedTimer.Start();
It's also worth pointing out that I found working with .NET Reactive Extensions and the IGeoPositionWatcher worked out really well for me.
http://msdn.microsoft.com/en-us/data/gg577609.aspx

To me it sounds like if current location > 20m from previous position fires event..
if there is a way to change the threshold, that seems will trigger differently, however maximum resolution could be 20m as that's usually what satellites have as max res, if I remember correct, not sure.

Related

Storyboard animation is not in sync with the previous animation

I am trying to implement MiddleClickScrolling in ScrollViewer and it works well.
The problem is when moving the pointer the Storyboard will restart to update the speed but when we move the pointer a jitter is occurring. I have attached a gif but you may not notice this jitter in this gif.
Since this a big class, I can't put all the code here. You can see my full code on GitHub (Note: Please select SmoothScroll branch if you are cloning it). An easy way to reproduce this issue is to move the pointer Up and Down for a small distance rapidly.
This is my code for storyboard animation
_verticalDoubleAnimation = new DoubleAnimation()
{
EnableDependentAnimation = true,
Duration = new TimeSpan(0, 0, 1)
};
//Different function
var offsetX = _currentPosition.X - _startPosition.X;
var offsetY = _currentPosition.Y - _startPosition.Y;
SetCursorType(offsetX, offsetY);
if (CanScrollVertical())
{
if (Math.Abs(offsetY) > _threshold)
{
RunInUIThread(() =>
{
_verticalDoubleAnimation.From = _scrollViewer.VerticalOffset;
_verticalDoubleAnimation.To = _scrollViewer.VerticalOffset + (offsetY > 0 ? _scrollViewer.ScrollableHeight : -_scrollViewer.ScrollableHeight);
if ((_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor)) == double.NaN)
{
return;
}
_verticalDoubleAnimation.Duration = TimeSpan.FromSeconds(_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor));
_verticalStoryboard.Begin();
});
}
else
{
RunInUIThread(() =>
{
_verticalStoryboard.Stop();
_sliderVertical.Value = _scrollViewer.VerticalOffset;
});
}
}
Instead of animating it, use a timer or a while loop to dynamically update the position using the ScrollViewer.ChangeView() method. Make sure the interval is less than 16.6ms for smooth 60fps motion. Also make sure to set the final parameter of ChangeView to false so that its built-in animation is disabled.
So in your first commit, change this:
timer = new Timer(ScrollAsync, null, 50, 50);
To this:
timer = new Timer(ScrollAsync, null, 0, 5);
The Timer does not give precision within 1ms or even 10ms to my undestanding. Overcompensating by updating it every 1-5ms should make up for that so it's probably fine and it's what I'm using in my custom scrolling control. A Stopwatch is very precise but is a massive CPU hog. Another option: It's a lot of extra work, but if you want precision timing and maximum performance with minimal battery usage, you can use Win2D's CanvasAnimatedControl which can be used to run code exactly once every 60th of a second.

Refreshing image at constant frame rate using Observable.Interval is slower than it should

Update:
I isolated the problem to its core components and a much shorter minimal working example in another question:
Observable.Interval not updating UI with expected frequency
I need to display a sequence of images (which are read from a folder) as a "movie", at a constant, previously known, frame-rate.
I have an Image control in WPF, whose Source is data-bound to a ViewModel property Image. I then proceed to update that image on a timely basis, using an Observable.Interval event source. For each elapsed interval, the UpdateImage is called, which updates the image inside a Task.Run() call.
My problem is: when I experimentally increase effective frame-rate (which depends on actual frame-rate and also on playback speed), the playback keeps being at normal speed up tu a given value. Above that value, it starts to look slower.
I believe that it has to do with RaisePropertyChanged call, but I'm not sure. I tried using SubscribeOnDispatcher (or whas it ObserveOnDispatcher?) but anyway it didnt have an effect.
Questions are:
- What I am doing wrong?
- How could I investigate and resolve the problem?
UPDATE:
It's worth mentioning that the getter for Image calls CreateImageForIndex(), which is a method that could have a non-trivial cost. Would it be possible to "async" it?
ViewModel (partial):
CancellationTokenSource _cancelPlay;
double _speed;
public void Play(double speed)
{
_speed = speed;
_cancelPlay = new CancellationTokenSource();
Observable.Interval(TimeSpan.FromSeconds(1.0 / (Math.Abs(speed) * Exame.Model.Configurações.FrameRate)))
.Subscribe(t => ExecuteRun(), _cancelPlay.Token);
}
public void Stop()
{
_cancelPlay?.Cancel();
}
void ExecuteRun()
{
Task.Run(() =>
{
Index = Math.Max(0, Math.Min(_model.MaxIndex, Index + 1 * Math.Sign(_speed)));
});
}
public int Index
{
get { return _model.Index; }
set
{
_model.Index = value;
RaisePropertyChanged(null); // this tells view to get a new value for `Image` too!
}
}
public ImageSource Image => _model.CreateImageForIndex(Index);
I've followed a hint from #Enigmativity (in the other answer I posted), that in Windows the resolution of timers is 15ms at most.
So I tested another strategy: spinning a while loop with an "when elapsed" condition, similar to a game loop, measuring time with a Stopwatch, and everything is working fine now.
public void Play(double speed)
{
_speed = speed;
_cancelPlay?.Cancel();
_cancelPlay = new CancellationTokenSource();
Task.Run(() => PlayLoop(_cancelPlay.Token), _cancelPlay.Token);
}
void PlayLoop(CancellationToken token)
{
var sw = Stopwatch.StartNew();
double previous = sw.ElapsedMilliseconds;
double timeInterval = 1000.0 / (Math.Abs(_speed) * _exame.Model.Configurações.FrameRate);
while (!token.IsCancellationRequested)
{
var current = sw.ElapsedMilliseconds;
var elapsed = current - previous;
if (elapsed > timeInterval)
{
Índice = Math.Max(0, Math.Min(ÍndiceMáximo, Índice + 1 * Math.Sign(_speed)));
previous = current;
}
}
}

Sliding elements in c# UWP

I have a question about animations in UWP. I want to have a menu on the bottom of my app that, when tapped on the top, slides up (shows) or down (hides almost entirely). I was learning WPF before and there I know I can use ThicknessAnimation to move the margin of my control and have it slide. Unfortunately, in UWP I can't use ThicknessAnimations, so I tried to find another way. I want this to work for an arbitrary FrameworkElement (so as to be able to reuse it). Eventually, I came up with this solution:
/// <summary>
/// Adds a vertical slide animation
/// </summary>
/// <param name="storyboard">The storyboard to add the animation to</param>
/// <param name="seconds">The time the animation will take</param>
/// <param name="offset">The distance the element will cover (nagative is up, positive is down)</param>
public static void AddVerticalSlide(this Storyboard storyboard, FrameworkElement element, float seconds, double offset)
{
var slideAnimation = new ObjectAnimationUsingKeyFrames();
for (int i = 0; i <= 100; ++i)
{
double scalar = (double)i / 100;
slideAnimation.KeyFrames.Add(new DiscreteObjectKeyFrame
{
Value = new Thickness(0, scalar*offset, 0, -scalar*offset),
KeyTime = TimeSpan.FromSeconds(scalar*seconds),
});
}
//slideAnimation.Duration = TimeSpan.FromSeconds(seconds);
// Set the target and target property
Storyboard.SetTarget(slideAnimation, element);
Storyboard.SetTargetProperty(slideAnimation, "(FrameworkElement.Margin)");
// Add the animation to the storyboard
storyboard.Children.Add(slideAnimation);
}
It works, looks nice, but here's the reason I'm asking this question: I don't know if it's proper. My guees is that there's a better way to slide objects than manually define 100 points on the way and move the object to each point using this animation.
This works but is just not the ideal way to offset an element. Why? Because you are creating two many DiscreteObjectKeyFrames when you really just need one DoubleAnimation.
You should almost never animate the Margin of an element. To change its position, a better approach is to animate the translate values (i.e. TranslateX/TranslateY) of its transform (RenderTransform) instead.
Animating anything in transform is efficient. They are off the UI thread. Traditionally, they were running in a special thread called Compositor thread (I think), but ever since the Creators Update, they have become even more performant according to the Windows UI team -
When you use Storyboard and Transition animations in XAML, you’re
using Composition under the hood. Animations run at 60 frames per
second!
The following is an example of using such technique
public static void Slide(this UIElement target, Orientation orientation, double? from, double to, int duration = 400, int startTime = 0, EasingFunctionBase easing = null)
{
if (easing == null)
{
easing = new ExponentialEase();
}
var transform = target.RenderTransform as CompositeTransform;
if (transform == null)
{
transform = new CompositeTransform();
target.RenderTransform = transform;
}
target.RenderTransformOrigin = new Point(0.5, 0.5);
var db = new DoubleAnimation
{
To = to,
From = from,
EasingFunction = easing,
Duration = TimeSpan.FromMilliseconds(duration)
};
Storyboard.SetTarget(db, target);
var axis = orientation == Orientation.Horizontal ? "X" : "Y";
Storyboard.SetTargetProperty(db, $"(UIElement.RenderTransform).(CompositeTransform.Translate{axis})");
var sb = new Storyboard
{
BeginTime = TimeSpan.FromMilliseconds(startTime)
};
sb.Children.Add(db);
sb.Begin();
}
Note as performant as this approach gets, there is even more powerful animation support in UWP, thanks to the new Composition API. But offset animation in Composition can be a bit tricky.
However, the UWP Community Tookit has done a great job wrapping some useful animations like Blur, Offset, etc. Feel free to check them out.

Microsoft Band UV sensor data unfamiliar

I'm using Microsoft Band of development on Windows Phone 8.1. Trying to figure out he full capability of the UV sensor. I found few examples, that find the UV level. They show that an enum can be used:
namespace Microsoft.Band.Sensors
{
public enum UVIndexLevel
{
None = 0,
Low = 1,
Medium = 2,
High = 3,
VeryHigh = 4,
}
}
Would also want to know, what's the scale of these enums. As I know there's like 0 to 11+ levels of UI. What ranges are those enums?
I'm basically using line of code:
{
bandClient.SensorManager.UV.ReadingChanged += Ultraviolet_ReadingChanged;
await bandClient.SensorManager.UV.StartReadingsAsync();
*Later on code*
await bandClient.SensorManager.UV.StopReadingsAsync();
bandClient.SensorManager.UV.ReadingChanged -= Ultraviolet_ReadingChanged;
}
The async method:
async void Ultraviolet_ReadingChanged(object sender, BandSensorReadingEventArgs<IBandUVReading> e)
{
IBandUVReading ultra = e.SensorReading;
UVIndexLevel potatoUV = ultra.IndexLevel;
}
But for some reason, I don't get Indexes most of the time. I sometimes get readings around 8 million to 10 million (or thousands) when in direct sunlight. Values are in "int" (Though sometimes gives the enums).
I am interested, on how I can measure it. Also, exactly what UV is it reading? I know there are many kinds of UV exposures. But how can I use this data?
If it's a range, then maybe I can put a range value, but I need to somehow sample it, what UV Index it has and give that information to the user. And use the index in later calculations.
ALSO...
I happened to fall on a bug. While testing the UV, when I was standing in direct light, the reading did not display. Only once I moved to another UV level, it changed (But never back to the first one). But seems like the first reading either does not change (As method is "readingchanged") or is the default location. However much sense this makes. Is there a way to call out the reading on button click?
If need be, I can search the examples I used, for mode depth of the code. But most of it is here.
A new Band SDK will be available soon and will fix the UV sensor data not correctly returned. Stay tune!
This sensor is a bit different than the others. It does require the user to do the action to acquire the data and then the data can be gathered.
Here is a code which is working on a WP8.1 with a Band.
DateTime start;
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
this.viewModel.StatusMessage = "Connecting to Band";
// Get the list of Microsoft Bands paired to the phone.
IBandInfo[] pairedBands = await BandClientManager.Instance.GetBandsAsync();
if (pairedBands.Length < 1)
{
this.viewModel.StatusMessage = "This sample app requires a Microsoft Band paired to your phone. Also make sure that you have the latest firmware installed on your Band, as provided by the latest Microsoft Health app.";
return;
}
// Connect to Microsoft Band.
using (IBandClient bandClient = await BandClientManager.Instance.ConnectAsync(pairedBands[0]))
{
start = DateTime.Now;
this.viewModel.StatusMessage = "Reading ultraviolet sensor";
// Subscribe to Ultraviolet data.
bandClient.SensorManager.UV.ReadingChanged += UV_ReadingChanged;
await bandClient.SensorManager.UV.StartReadingsAsync();
// Receive Accelerometer data for a while.
await Task.Delay(TimeSpan.FromMinutes(5));
await bandClient.SensorManager.UV.StopReadingsAsync();
bandClient.SensorManager.UV.ReadingChanged -= UV_ReadingChanged;
}
this.viewModel.StatusMessage = "Done";
}
catch (Exception ex)
{
this.viewModel.StatusMessage = ex.ToString();
}
}
void UV_ReadingChanged(object sender, Microsoft.Band.Sensors.BandSensorReadingEventArgs<Microsoft.Band.Sensors.IBandUVReading> e)
{
var span = (DateTime.Now - start).TotalSeconds;
IBandUVReading ultra = e.SensorReading;
string text = string.Format("Ultraviolet = {0}\nTime Stamp = {1}\nTime Span = {2}\n", ultra.IndexLevel, ultra.Timestamp, span);
Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { this.viewModel.StatusMessage = text; }).AsTask();
start = DateTime.Now;
}

Tracking location in realtime in Windows phone 8.1

Sorry if this is a dumb question, I'm a beginner to windows phone 8.1 development.
I am using MapControl to display my current location on the map but as I move my position does not get updated automatically in realtime unless I click on a button and re-initialize the position of the pushpin which was earlier created. Is there a better way where this happens in the without the user having to push the button everytime he wants to see his current location.
private async Task setMyLocation()
{
try
{
var gl = new Geolocator() { DesiredAccuracy = PositionAccuracy.High };
Geoposition location = await gl.GetGeopositionAsync(TimeSpan.FromMinutes(5), TimeSpan.FromSeconds(5));
var pin = new MapIcon()
{
Location = location.Coordinate.Point,
Title = "You are here",
NormalizedAnchorPoint = new Point() { X = 0, Y = 0 },
};
myMapView.MapElements.Add(pin);
await myMapView.TrySetViewAsync(location.Coordinate.Point, 20);
}
catch
{
myMapView.Center = new Geopoint(App.centerPin);
myMapView.ZoomLevel = 20;
Debug.WriteLine("GPS NOT FOUND");
}
App.centerPin = myMapView.Center.Position;
}
Thanks in Advance!
Rather than running a timer and polling, handle the Geolocator.PositionChanged event. This will fire each time the position changes and will be significantly more efficient.
You can set the Geolocator.MovementThreshold property so it will only fire if the user has moved a given distance and not do anything if the user stands in the same place. The threshold you pick will probably depend on how far your map is zoomed in.
The way I would do it is to put a Timer that requests information from the server at a given interval.
Take a look onto this answer containing a code snippet : Stackoverflow answer

Categories