Beispiel #1
0
            public void OnAnimationUpdate(ValueAnimator animation)
            {
                float progress = transport.Progress + (transport.NextProgress - transport.Progress) * animation.AnimatedFraction;
                int   index    = transport.Step.Trajectory.TakeWhile(s => s.Index <= progress).Count();

                bool           last = index >= transport.Step.Trajectory.Length;
                TrajectoryStep from = transport.Step.Trajectory[index - 1];
                TrajectoryStep to   = last ? transport.TimeStep.Step.Trajectory.First() : transport.Step.Trajectory[index];

                progress = (progress - from.Index) / ((last ? 1 : to.Index) - from.Index);
                LatLng position = new LatLng(from.Position.Latitude + (to.Position.Latitude - from.Position.Latitude) * progress, from.Position.Longitude + (to.Position.Longitude - from.Position.Longitude) * progress);

                positionUpdater(position);
            }
Beispiel #2
0
        private void UpdatePositions()
        {
            TimeStep[] currentTimeSteps;
            DateTime   now = DateTime.Now;

            // Take time steps snapshot
            lock (timeSteps)
                currentTimeSteps = timeSteps.ToArray();

            // Sort time steps by step
            Dictionary <Step, TimeStep> steps = currentTimeSteps.GroupBy(s => s.Step)
                                                .ToDictionary(g => g.Key, g => g.OrderBy(s => s.Date).First());

            // For each route, find transport positions
            List <Transport> transports = new List <Transport>();

            foreach (Line line in TramUrWayApplication.Lines)
            {
                foreach (Route route in line.Routes)
                {
                    for (int i = 0; i < route.Steps.Length - 1; i++)
                    {
                        Step step     = route.Steps[i];
                        Step nextStep = route.Steps[i + 1];

                        TimeStep timeStep, nextTimeStep;
                        if (!steps.TryGetValue(nextStep, out nextTimeStep))
                        {
                            continue;
                        }
                        steps.TryGetValue(step, out timeStep);

                        if (timeStep != null && timeStep.Date < nextTimeStep.Date)
                        {
                            continue;
                        }

                        TimeSpan diff     = nextTimeStep.Date - now;
                        TimeSpan duration = step.Duration ?? TimeSpan.Zero;

                        if (duration == TimeSpan.Zero)
                        {
                            duration = TimeSpan.FromMinutes(2);
                        }

                        float progress = (float)(1 - Math.Min(diff.TotalMinutes, duration.TotalMinutes) / duration.TotalMinutes);
                        if (progress < 0)
                        {
                            progress = 0;
                        }
                        if (progress > 1)
                        {
                            progress = 1;
                        }

                        float nextProgress = (float)(1 - Math.Min(diff.Subtract(TimeSpan.FromSeconds(1)).TotalMinutes, duration.TotalMinutes) / duration.TotalMinutes);
                        if (nextProgress < 0)
                        {
                            nextProgress = 0;
                        }
                        if (nextProgress > 1)
                        {
                            nextProgress = 1;
                        }

                        Transport transport = new Transport()
                        {
                            Route        = route,
                            Step         = step,
                            TimeStep     = nextTimeStep,
                            Progress     = step.Speed.Evaluate(progress),
                            NextProgress = step.Speed.Evaluate(nextProgress)
                        };

                        transports.Add(transport);
                    }
                }
            }

            // Sort markers
            Dictionary <Step, Marker> stepMarkers       = transportMarkers.ToDictionary(p => p.Key.Step, p => p.Value);
            List <Marker>             unusedMarkers     = stepMarkers.Where(p => !transports.Any(t => t.Step == p.Key)).Select(p => p.Value).ToList();
            List <Transport>          missingTransports = transports.Where(t => !stepMarkers.Keys.Contains(t.Step)).ToList();
            Dictionary <Step, Marker> reusableMarkers   = stepMarkers.Where(p => transports.Any(t => t.Step == p.Key) && !missingTransports.Any(t => t.Step == p.Key)).ToDictionary();

            // Adjust markers diff
            while (unusedMarkers.Count > missingTransports.Count)
            {
                Marker marker = unusedMarkers.Last();
                unusedMarkers.RemoveAt(unusedMarkers.Count - 1);
                Activity.RunOnUiThread(marker.Remove);
            }
            while (missingTransports.Count > unusedMarkers.Count)
            {
                ManualResetEvent resetEvent = new ManualResetEvent(false);

                Activity.RunOnUiThread(() =>
                {
                    MarkerOptions markerOptions = new MarkerOptions()
                                                  .Anchor(0.5f, 0.5f)
                                                  .SetPosition(new LatLng(0, 0));

                    Marker marker = googleMap.AddMarker(markerOptions);
                    unusedMarkers.Add(marker);

                    resetEvent.Set();
                });

                resetEvent.WaitOne();
            }

            // Use existing markers to match current transports
            transportMarkers = reusableMarkers.Select(p => new KeyValuePair <Transport, Marker>(transports.First(t => t.Step == p.Key), p.Value))
                               .Concat(missingTransports.Zip(unusedMarkers, (t, m) => new KeyValuePair <Transport, Marker>(t, m)))
                               .ToDictionary();

            foreach (var pair in transportMarkers)
            {
                Transport transport = pair.Key;
                Marker    marker    = pair.Value;

                // Compute quick position
                Position quickFrom     = transport.Step.Stop.Position;
                Position quickTo       = transport.TimeStep.Step.Stop.Position;
                LatLng   quickPosition = new LatLng(quickFrom.Latitude + (quickTo.Latitude - quickFrom.Latitude) * transport.Progress, quickFrom.Longitude + (quickTo.Longitude - quickFrom.Longitude) * transport.Progress);

                // Update marker
                Activity.RunOnUiThread(() => marker.SetIcon(lineIcons[transport.Route.Line]));
                bool visible;
                if (markersVisibility.TryGetValue(marker, out visible) && !visible)
                {
                    continue;
                }

                // Use animation only if zoomed enough
                if (cameraPosition.Zoom >= AnimationZoomLimit)
                {
                    ValueAnimator valueAnimator = new ValueAnimator();
                    valueAnimator.AddUpdateListener(new MarkerAnimator(Activity, marker, transport, p => SetMarkerPosition(transport, marker, p)));
                    valueAnimator.SetFloatValues(0, 1); // Ignored.
                    valueAnimator.SetInterpolator(new LinearInterpolator());
                    valueAnimator.SetDuration(1000);
                    Activity.RunOnUiThread(valueAnimator.Start);
                }
                else
                {
                    float progress = transport.Progress;
                    int   index    = transport.Step.Trajectory.TakeWhile(s => s.Index <= progress).Count();

                    bool           last = index >= transport.Step.Trajectory.Length;
                    TrajectoryStep from = transport.Step.Trajectory[index - 1];
                    TrajectoryStep to   = last ? transport.TimeStep.Step.Trajectory.First() : transport.Step.Trajectory[index];

                    progress = (progress - from.Index) / ((last ? 1 : to.Index) - from.Index);
                    LatLng position = new LatLng(from.Position.Latitude + (to.Position.Latitude - from.Position.Latitude) * transport.Progress, from.Position.Longitude + (to.Position.Longitude - from.Position.Longitude) * transport.Progress);

                    SetMarkerPosition(transport, marker, position);
                }

                // Follow selected transport
                Activity.RunOnUiThread(() =>
                {
                    if (marker.Id == selectedMarkerId)
                    {
                        googleMap.AnimateCamera(CameraUpdateFactory.NewLatLng(quickPosition));
                    }
                });
            }
        }