Пример #1
0
 public void MovieExportMovie(string path, ProcessingOptionsMovieExport options)
 {
     if (!SendCommand(new NamedSerializableObject("MovieExportMovie",
                                                  path,
                                                  options)))
     {
         throw new Exception("Couldn't export the movie!");
     }
 }
Пример #2
0
        private void UpdateTracker()
        {
            if (ActiveItem != null && RowItems.Count > 0 && AllItems != null && RowItems.IndexOf(ActiveItem) >= 0)
            {
                if (!IsMinimized)
                {
                    PathPosition.Visibility         = Visibility.Visible;
                    PathPositionInverted.Visibility = Visibility.Collapsed;
                    CheckCurrentName.Visibility     = Visibility.Visible;
                    TextCurrentName.Visibility      = Visibility.Visible;
                }
                else
                {
                    PathPosition.Visibility         = Visibility.Collapsed;
                    PathPositionInverted.Visibility = Visibility.Visible;
                    CheckCurrentName.Visibility     = Visibility.Collapsed;
                    TextCurrentName.Visibility      = Visibility.Collapsed;
                }

                int PositionIndex = RowItems.IndexOf(ActiveItem);

                double IdealOffset = (PositionIndex + 0.5) * ItemWidth;
                PathPosition.Margin =
                    new Thickness(Math.Max(0, Math.Min(IdealOffset - PathPosition.ActualWidth / 2, ActualWidth - PathPosition.ActualWidth)),
                                  0, 0, 0);
                PathPositionInverted.Margin =
                    new Thickness(Math.Max(0, Math.Min(IdealOffset - PathPosition.ActualWidth / 2, ActualWidth - PathPosition.ActualWidth)),
                                  0, 0, 0);

                string TextString = $"{ActiveItem.RootName} ({AllItems.IndexOf(ActiveItem) + 1}/{AllItems.Count})";
                Size   TextSize   = MeasureString(TextString);
                CheckCurrentName.Margin =
                    new Thickness(Math.Max(0, Math.Min(IdealOffset - TextSize.Width / 2, ActualWidth - TextSize.Width) - 24),
                                  6, 0, 7);
                TextCurrentName.Text = TextString;

                ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
                ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
                ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
                ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

                PenCurrentName.Brush = StatusBar.StatusToBrush(StatusBar.GetMovieProcessingStatus(ActiveItem, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options));
                //PenCurrentName.Brush.Opacity = 0.3;
            }
            else
            {
                PathPosition.Visibility         = Visibility.Collapsed;
                PathPositionInverted.Visibility = Visibility.Collapsed;
                CheckCurrentName.Visibility     = Visibility.Collapsed;
                TextCurrentName.Visibility      = Visibility.Collapsed;
            }
        }
Пример #3
0
        public void ApplyFilter()
        {
            if (!IsFilterEnabled)
            {
                FilteredItems = Items.ToList();
            }
            else
            {
                List <Movie> Result = Items.ToList();

                if (!string.IsNullOrEmpty(FilterSearchPattern))
                {
                    try
                    {
                        Regex Expression = new Regex(FilterSearchPattern);
                        Result = Result.Where(m => Expression.IsMatch(m.Name)).ToList();
                    }
                    catch { }
                }

                if (!FilterIncludeProcessed || !FilterIncludeOutdated || !FilterIncludeUnprocessed || !FilterIncludeFilteredOut || !FilterIncludeDeselected)
                {
                    ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
                    ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
                    ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
                    ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

                    List <Tuple <Movie, ProcessingStatus> > WithStatus = new List <Tuple <Movie, ProcessingStatus> >(Items.Count);
                    foreach (var item in Result)
                    {
                        WithStatus.Add(new Tuple <Movie, ProcessingStatus>(item, GetMovieProcessingStatus(item, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options)));
                    }

                    Result = WithStatus.Where(t =>
                    {
                        return((t.Item2 == ProcessingStatus.Processed && FilterIncludeProcessed) ||
                               (t.Item2 == ProcessingStatus.Outdated && FilterIncludeOutdated) ||
                               (t.Item2 == ProcessingStatus.Unprocessed && FilterIncludeUnprocessed) ||
                               (t.Item2 == ProcessingStatus.FilteredOut && FilterIncludeFilteredOut) ||
                               (t.Item2 == ProcessingStatus.LeaveOut && FilterIncludeDeselected));
                    }).Select(t => t.Item1).ToList();
                }

                FilteredItems = Result;
            }
        }
Пример #4
0
        private void UpdateTracker()
        {
            if (ActiveItem != null && Items.Count > 0)
            {
                PathPosition.Visibility     = Visibility.Visible;
                CheckCurrentName.Visibility = Visibility.Visible;
                TextCurrentName.Visibility  = Visibility.Visible;

                double StepLength = ActualWidth / Items.Count;

                int PositionIndex = Items.IndexOf(ActiveItem);
                if (PositionIndex < 0)  // Can't find it in Items, hide everything
                {
                    PathPosition.Visibility     = Visibility.Hidden;
                    CheckCurrentName.Visibility = Visibility.Hidden;
                    TextCurrentName.Visibility  = Visibility.Hidden;
                    return;
                }

                double IdealOffset = (PositionIndex + 0.5) * StepLength;
                PathPosition.Margin =
                    new Thickness(Math.Max(0, Math.Min(IdealOffset - PathPosition.ActualWidth / 2, ActualWidth - PathPosition.ActualWidth)),
                                  0, 0, 0);

                string TextString = $"{ActiveItem.RootName} ({PositionIndex + 1}/{Items.Count})";
                Size   TextSize   = MeasureString(TextString);
                CheckCurrentName.Margin =
                    new Thickness(Math.Max(0, Math.Min(IdealOffset - TextSize.Width / 2, ActualWidth - TextSize.Width) - 24),
                                  0, 0, 0);
                TextCurrentName.Text = TextString;

                ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
                ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
                ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
                ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

                PenCurrentName.Brush = StatusToBrush(GetMovieProcessingStatus(ActiveItem, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options));
                //PenCurrentName.Brush.Opacity = 0.3;
            }
            else
            {
                PathPosition.Visibility     = Visibility.Hidden;
                CheckCurrentName.Visibility = Visibility.Hidden;
                TextCurrentName.Visibility  = Visibility.Hidden;
            }
        }
Пример #5
0
        static void Main(string[] args)
        {
            CultureInfo.DefaultThreadCurrentCulture   = CultureInfo.InvariantCulture;
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

            //if (!Debugger.IsAttached)
            //    Debugger.Launch();

            if (args.Length < 3)
            {
                return;
            }

            DeviceID = int.Parse(args[0]) % GPU.GetDeviceCount();
            PipeName = args[1];
            bool DebugMode = bool.Parse(args[2]);

            GPU.SetDevice(DeviceID);

            Console.WriteLine($"Running on GPU #{DeviceID} ({GPU.GetFreeMemory(DeviceID)} MB free) through {PipeName}\n");

            Formatter = new BinaryFormatter();

            Heartbeat = new Thread(new ThreadStart(() =>
            {
                if (!DebugMode)
                {
                    while (true)
                    {
                        try
                        {
                            NamedPipeClientStream PipeHeartbeat = new NamedPipeClientStream(".", PipeName + "_heartbeat", PipeDirection.In);
                            PipeHeartbeat.Connect(5000);

                            PipeHeartbeat.Dispose();
                        }
                        catch
                        {
                            if (!Terminating)
                            {
                                Process.GetCurrentProcess().Kill();
                            }
                        }
                    }
                }
            }));
            Heartbeat.Start();

            while (true)
            {
                PipeReceive = new NamedPipeClientStream(".", PipeName + "_out", PipeDirection.In);
                PipeReceive.Connect();

                NamedSerializableObject Command = (NamedSerializableObject)Formatter.Deserialize(PipeReceive);

                PipeReceive.Dispose();

                Console.WriteLine($"Received \"{Command.Name}\", with {Command.Content.Length} arguments, for GPU #{GPU.GetDevice()}, {GPU.GetFreeMemory(DeviceID)} MB free");

                try
                {
                    Stopwatch Watch = new Stopwatch();
                    Watch.Start();

                    if (Command.Name == "Exit")
                    {
                        Movie.WriteAverageAsync?.Wait();

                        SendSuccessStatus(true);
                        Process.GetCurrentProcess().Kill();

                        return;
                    }
                    else if (Command.Name == "Ping")
                    {
                        Console.WriteLine("Ping!");
                    }
                    else if (Command.Name == "SetHeaderlessParams")
                    {
                        HeaderlessDims   = (int2)Command.Content[0];
                        HeaderlessOffset = (long)Command.Content[1];
                        HeaderlessType   = (string)Command.Content[2];

                        Console.WriteLine($"Set headerless parameters to {HeaderlessDims}, {HeaderlessOffset}, {HeaderlessType}");
                    }
                    else if (Command.Name == "LoadGainRef")
                    {
                        GainRef?.Dispose();
                        DefectMap?.Dispose();

                        string GainPath    = (string)Command.Content[0];
                        bool   FlipX       = (bool)Command.Content[1];
                        bool   FlipY       = (bool)Command.Content[2];
                        bool   Transpose   = (bool)Command.Content[3];
                        string DefectsPath = (string)Command.Content[4];

                        if (!string.IsNullOrEmpty(GainPath))
                        {
                            GainRef = LoadAndPrepareGainReference(GainPath, FlipX, FlipY, Transpose);
                        }
                        if (!string.IsNullOrEmpty(DefectsPath))
                        {
                            DefectMap = LoadAndPrepareDefectMap(DefectsPath, FlipX, FlipY, Transpose);
                        }

                        Console.WriteLine($"Loaded gain reference and defect map: {GainRef}, {FlipX}, {FlipY}, {Transpose}, {DefectsPath}");
                    }
                    else if (Command.Name == "LoadStack")
                    {
                        OriginalStack?.Dispose();

                        string  Path           = (string)Command.Content[0];
                        decimal ScaleFactor    = (decimal)Command.Content[1];
                        int     EERGroupFrames = (int)Command.Content[2];

                        HeaderEER.GroupNFrames = EERGroupFrames;

                        OriginalStack      = LoadAndPrepareStack(Path, ScaleFactor);
                        OriginalStackOwner = Helper.PathToNameWithExtension(Path);

                        Console.WriteLine($"Loaded stack: {OriginalStack}, {ScaleFactor}");
                    }
                    else if (Command.Name == "MovieProcessCTF")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsMovieCTF Options = (ProcessingOptionsMovieCTF)Command.Content[1];

                        if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner)
                        {
                            throw new Exception("Currently loaded stack doesn't match the movie requested for processing!");
                        }

                        Movie M = new Movie(Path);
                        M.ProcessCTF(OriginalStack, Options);
                        M.SaveMeta();

                        Console.WriteLine($"Processed CTF for {Path}");
                    }
                    else if (Command.Name == "MovieProcessMovement")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsMovieMovement Options = (ProcessingOptionsMovieMovement)Command.Content[1];

                        if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner)
                        {
                            throw new Exception("Currently loaded stack doesn't match the movie requested for processing!");
                        }

                        Movie M = new Movie(Path);
                        M.ProcessShift(OriginalStack, Options);
                        M.SaveMeta();

                        Console.WriteLine($"Processed movement for {Path}");
                    }
                    else if (Command.Name == "MovieExportMovie")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsMovieExport Options = (ProcessingOptionsMovieExport)Command.Content[1];

                        if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner)
                        {
                            throw new Exception("Currently loaded stack doesn't match the movie requested for processing!");
                        }

                        Movie M = new Movie(Path);
                        M.ExportMovie(OriginalStack, Options);
                        M.SaveMeta();

                        Console.WriteLine($"Exported movie for {Path}");
                    }
                    else if (Command.Name == "MovieExportParticles")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsParticlesExport Options = (ProcessingOptionsParticlesExport)Command.Content[1];
                        float2[] Coordinates = (float2[])Command.Content[2];

                        if (Helper.PathToNameWithExtension(Path) != OriginalStackOwner)
                        {
                            throw new Exception("Currently loaded stack doesn't match the movie requested for processing!");
                        }

                        Movie M = new Movie(Path);
                        M.ExportParticles(OriginalStack, Coordinates, Options);
                        M.SaveMeta();

                        Console.WriteLine($"Exported {Coordinates.Length} particles for {Path}");
                    }
                    else if (Command.Name == "TomoProcessCTF")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsMovieCTF Options = (ProcessingOptionsMovieCTF)Command.Content[1];

                        TiltSeries T = new TiltSeries(Path);
                        T.ProcessCTFSimultaneous(Options);
                        T.SaveMeta();

                        Console.WriteLine($"Processed CTF for {Path}");
                    }
                    else if (Command.Name == "TomoExportParticles")
                    {
                        string Path = (string)Command.Content[0];
                        ProcessingOptionsTomoSubReconstruction Options = (ProcessingOptionsTomoSubReconstruction)Command.Content[1];
                        float3[] Coordinates = (float3[])Command.Content[2];
                        float3[] Angles      = Command.Content[3] != null ? (float3[])Command.Content[3] : null;

                        TiltSeries T = new TiltSeries(Path);
                        T.ReconstructSubtomos(Options, Coordinates, Angles);
                        T.SaveMeta();

                        Console.WriteLine($"Exported {Coordinates.Length} particles for {Path}");
                    }
                    else if (Command.Name == "MPAPreparePopulation")
                    {
                        string Path = (string)Command.Content[0];

                        MPAPopulation = new Population(Path);

                        foreach (var species in MPAPopulation.Species)
                        {
                            Console.Write($"Preparing {species.Name} for refinement... ");

                            species.PrepareRefinementRequisites(true, DeviceID);

                            Console.WriteLine("Done.");
                        }
                    }
                    else if (Command.Name == "MPARefine")
                    {
                        string Path                        = (string)Command.Content[0];
                        string WorkingDirectory            = (string)Command.Content[1];
                        string LogPath                     = (string)Command.Content[2];
                        ProcessingOptionsMPARefine Options = (ProcessingOptionsMPARefine)Command.Content[3];
                        DataSource Source                  = (DataSource)Command.Content[4];

                        Movie Item = null;

                        if (Helper.PathToExtension(Path).ToLower() == ".tomostar")
                        {
                            Item = new TiltSeries(Path);
                        }
                        else
                        {
                            Item = new Movie(Path);
                        }

                        GPU.SetDevice(DeviceID);

                        Item.PerformMultiParticleRefinement(WorkingDirectory, Options, MPAPopulation.Species.ToArray(), Source, GainRef, DefectMap, (message) =>
                        {
                            Console.WriteLine(message);

                            bool Success = false;
                            int Tries    = 0;
                            while (!Success && Tries < 10)
                            {
                                try
                                {
                                    using (TextWriter Writer = File.AppendText(LogPath))
                                        Writer.WriteLine(message);
                                    Success = true;
                                }
                                catch
                                {
                                    Thread.Sleep(100);
                                    Tries++;
                                }
                            }
                        });

                        Item.SaveMeta();

                        GPU.CheckGPUExceptions();

                        Console.WriteLine($"Finished refining {Item.Name}");
                    }
                    else if (Command.Name == "MPASaveProgress")
                    {
                        string Path = (string)Command.Content[0];

                        MPAPopulation.SaveRefinementProgress(Path);
                    }
                    else if (Command.Name == "TryAllocatePinnedMemory")
                    {
                        long[]   ChunkSizes = (long[])Command.Content[0];
                        IntPtr[] Chunks     = new IntPtr[ChunkSizes.Length];

                        for (int i = 0; i < ChunkSizes.Length; i++)
                        {
                            Chunks[i] = GPU.MallocHostPinned(ChunkSizes[i] / sizeof(float));
                            //Dummies.Add(Helper.ArrayOfSequence(0, (int)(ChunkSizes[i] / sizeof(float) / 2), 1));
                        }

                        GPU.CheckGPUExceptions();

                        //for (int i = 0; i < ChunkSizes.Length; i++)
                        //    GPU.FreeHostPinned(Chunks[i]);

                        Console.WriteLine($"Successfully allocated {ChunkSizes.Sum()} bytes of pinned memory");
                    }

                    Watch.Stop();
                    Console.WriteLine((Watch.ElapsedMilliseconds / 1000f).ToString("F3"));

                    Console.WriteLine("");

                    SendSuccessStatus(true);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.ToString());

                    File.WriteAllText($"worker_{DeviceID}_crash.txt", e.ToString());

                    //Console.Read();

                    SendSuccessStatus(false);
                }
            }
        }
Пример #6
0
        public static ProcessingStatus GetMovieProcessingStatus(Movie movie, ProcessingOptionsMovieCTF optionsCTF, ProcessingOptionsMovieMovement optionsMovement, ProcessingOptionsBoxNet optionsBoxNet, ProcessingOptionsMovieExport optionsExport, Options options, bool considerFilter = true)
        {
            bool DoCTF      = options.ProcessCTF;
            bool DoMovement = options.ProcessMovement && movie.GetType() == typeof(Movie);
            bool DoBoxNet   = options.ProcessPicking && movie.GetType() == typeof(Movie);
            bool DoExport   = (optionsExport.DoAverage || optionsExport.DoStack || optionsExport.DoDeconv) && movie.GetType() == typeof(Movie);

            ProcessingStatus Status = ProcessingStatus.Processed;

            if (movie.UnselectManual != null && (bool)movie.UnselectManual)
            {
                Status = ProcessingStatus.LeaveOut;
            }
            else if (movie.OptionsCTF == null && movie.OptionsMovement == null && movie.OptionsMovieExport == null)
            {
                Status = ProcessingStatus.Unprocessed;
            }
            else
            {
                if (DoCTF && (movie.OptionsCTF == null || movie.OptionsCTF != optionsCTF))
                {
                    Status = ProcessingStatus.Outdated;
                }
                else if (DoMovement && (movie.OptionsMovement == null || movie.OptionsMovement != optionsMovement))
                {
                    Status = ProcessingStatus.Outdated;
                }
                else if (DoBoxNet && (movie.OptionsBoxNet == null || movie.OptionsBoxNet != optionsBoxNet))
                {
                    Status = ProcessingStatus.Outdated;
                }
                else if (DoExport && (movie.OptionsMovieExport == null || movie.OptionsMovieExport != optionsExport))
                {
                    Status = ProcessingStatus.Outdated;
                }
            }

            if (Status == ProcessingStatus.Processed && movie.UnselectFilter && movie.UnselectManual == null && considerFilter)
            {
                Status = ProcessingStatus.FilteredOut;
            }

            return(Status);
        }
Пример #7
0
        public void UpdateElements()
        {
            PanelRows.Children.Clear();

            foreach (var row in RowControls)
            {
                row.ActiveItemStatusChanged -= RowActiveItemStatusChanged;
                row.ActiveItemChanged       -= RowActiveItemChanged;
                row.HighlightItemChanged    -= RowHighlightItemChanged;
            }
            RowControls.Clear();

            ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
            ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
            ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
            ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

            List <Tuple <Movie, ProcessingStatus> > WithStatus = new List <Tuple <Movie, ProcessingStatus> >(FilteredItems.Count);

            foreach (var item in FilteredItems)
            {
                WithStatus.Add(new Tuple <Movie, ProcessingStatus>(item, GetMovieProcessingStatus(item, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options)));
            }

            // Update number of processed movies.
            int NProcessed   = WithStatus.Sum(m => m.Item2 == ProcessingStatus.Processed || m.Item2 == ProcessingStatus.FilteredOut ? 1 : 0);
            int NProcessable = WithStatus.Sum(m => m.Item2 != ProcessingStatus.LeaveOut ? 1 : 0);

            TextNumberProcessed.Text = $"Processed {NProcessed}/{NProcessable}.";

            if (FilteredItems.Count == 0 || ActualWidth == 0) // Hide unnecessary elements.
            {
                HideElements();
            }
            else
            {
                ShowElements();

                // Create colored navigation bar.
                double StepLength  = Math.Max(2, ActualWidth / FilteredItems.Count);
                int    ItemsPerRow = (int)(ActualWidth / StepLength + 1e-3);
                int    NRows       = (FilteredItems.Count + ItemsPerRow - 1) / ItemsPerRow;

                for (int r = 0; r < NRows; r++)
                {
                    List <Movie> RowSubset = FilteredItems.Skip(r * ItemsPerRow).Take(ItemsPerRow).ToList();
                    StatusBarRow Row       = new StatusBarRow();
                    Row.HorizontalAlignment      = HorizontalAlignment.Stretch;
                    Row.ItemWidth                = StepLength;
                    Row.AllItems                 = FilteredItems;
                    Row.RowItems                 = RowSubset;
                    Row.ActiveItem               = ActiveItem;
                    Row.ActiveItemStatusChanged += RowActiveItemStatusChanged;
                    Row.ActiveItemChanged       += RowActiveItemChanged;
                    Row.HighlightItemChanged    += RowHighlightItemChanged;

                    PanelRows.Children.Add(Row);
                    RowControls.Add(Row);
                }
            }
        }
Пример #8
0
        private async void ButtonAddLocal_OnClick(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog OpenDialog = new System.Windows.Forms.OpenFileDialog();
            OpenDialog.Filter = "Warp Folder Settings|*.settings|Warp Data Source|*.source";
            System.Windows.Forms.DialogResult OpenResult = OpenDialog.ShowDialog();

            if (OpenResult.ToString() == "OK")
            {
                FileInfo Info = new FileInfo(OpenDialog.FileName);

                #region Check if user wants to use an existing source file instead

                //if (Info.Extension.ToLower() == ".settings" &&
                //    File.Exists(OpenDialog.FileName.Substring(0, OpenDialog.FileName.LastIndexOf(".")) + ".source"))
                //{
                //    var Result = await ((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Similar source file found",
                //                                                                                     $"Would you like to use {Helper.PathToName(Info.Name) + ".source"} instead?",
                //                                                                                     MessageDialogStyle.AffirmativeAndNegativeAndSingleAuxiliary,
                //                                                                                     new MetroDialogSettings
                //                                                                                     {
                //                                                                                         AffirmativeButtonText = "Use existing source",
                //                                                                                         NegativeButtonText = "Replace with new source from settings",
                //                                                                                         FirstAuxiliaryButtonText = "Cancel"
                //                                                                                     });

                //    if (Result == MessageDialogResult.FirstAuxiliary)   // Cancel
                //    {
                //        return;
                //    }
                //    else if (Result == MessageDialogResult.Affirmative) // Use existing .source
                //    {
                //        OpenDialog.FileName = OpenDialog.FileName.Substring(0, OpenDialog.FileName.LastIndexOf(".")) + ".source";
                //        Info = new FileInfo(OpenDialog.FileName);
                //    }
                //}

                #endregion

                if (Info.Extension.ToLower() == ".settings")
                {
                    #region Load preprocessing options

                    Warp.Options Options = new Warp.Options();
                    try
                    {
                        Options.Load(OpenDialog.FileName);
                    }
                    catch
                    {
                        await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                           $"An error was encountered when reading {Info.Name}.",
                                                                                           MessageDialogStyle.Affirmative);
                        return;
                    }

                    #endregion

                    #region Load items with metadata

                    string FileExtension  = Options.Import.Extension;
                    var    AvailableFiles = Directory.EnumerateFiles(Info.DirectoryName, FileExtension).ToArray();

                    Movie[] Items = new Movie[AvailableFiles.Length];

                    string[] MatchingStarNames = null;
                    if (FileExtension != "*.tomostar" && AvailableFiles.Length > 0)
                    {
                        Movie First = new Movie(AvailableFiles[0]);
                        MatchingStarNames = Directory.EnumerateFiles(First.MatchingDir, "*.star").ToArray();
                    }

                    {
                        var ProgressDialog = await((MainWindow)Application.Current.MainWindow).ShowProgressAsync("Loading metadata...", "");
                        ProgressDialog.Maximum = AvailableFiles.Count();

                        await Task.Run(() =>
                        {
                            int Done = 0;
                            Parallel.For(0, AvailableFiles.Length, i =>
                            {
                                string file    = AvailableFiles[i];
                                string XmlPath = file.Substring(0, file.LastIndexOf(".")) + ".xml";
                                if (File.Exists(XmlPath))
                                {
                                    Items[i] = (FileExtension == "*.tomostar" ? new TiltSeries(file) : new Movie(file, MatchingStarNames));
                                }

                                lock (Items)
                                    ProgressDialog.SetProgress(++Done);
                            });
                        });

                        await ProgressDialog.CloseAsync();
                    }

                    if (Items.Length == 0)
                    {
                        await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                           $"No micrographs or tilt series found to match these settings.",
                                                                                           MessageDialogStyle.Affirmative);
                        return;
                    }

                    #endregion

                    #region Figure out filtering status

                    #region Astigmatism statistics

                    Movie[]       ItemsWithCTF      = Items.Where(v => v.OptionsCTF != null && v.CTF != null).ToArray();
                    List <float2> AstigmatismPoints = new List <float2>(ItemsWithCTF.Length);
                    foreach (var item in ItemsWithCTF)
                    {
                        AstigmatismPoints.Add(new float2((float)Math.Cos((float)item.CTF.DefocusAngle * 2 * Helper.ToRad) * (float)item.CTF.DefocusDelta,
                                                         (float)Math.Sin((float)item.CTF.DefocusAngle * 2 * Helper.ToRad) * (float)item.CTF.DefocusDelta));
                    }

                    float2 AstigmatismMean = new float2();
                    float  AstigmatismStd  = 0.1f;

                    if (AstigmatismPoints.Count > 0)
                    {
                        AstigmatismMean = new float2();
                        foreach (var point in AstigmatismPoints)
                        {
                            AstigmatismMean += point;
                        }
                        AstigmatismMean /= AstigmatismPoints.Count;

                        AstigmatismStd = 0;
                        foreach (var point in AstigmatismPoints)
                        {
                            AstigmatismStd += (point - AstigmatismMean).LengthSq();
                        }
                        AstigmatismStd = (float)Math.Max(1e-4, Math.Sqrt(AstigmatismStd / AstigmatismPoints.Count));
                    }

                    #endregion

                    int[] ParticleCounts = Items.Select(item => item.GetParticleCount(Options.Filter.ParticlesSuffix)).ToArray();
                    bool  HaveParticles  = ParticleCounts.Any(v => v > 0);

                    foreach (var item in Items)
                    {
                        bool FilterStatus = true;

                        if (item.OptionsCTF != null)
                        {
                            FilterStatus &= item.CTF.Defocus >= Options.Filter.DefocusMin && item.CTF.Defocus <= Options.Filter.DefocusMax;
                            float AstigmatismDeviation = (new float2((float)Math.Cos((float)item.CTF.DefocusAngle * 2 * Helper.ToRad) * (float)item.CTF.DefocusDelta,
                                                                     (float)Math.Sin((float)item.CTF.DefocusAngle * 2 * Helper.ToRad) * (float)item.CTF.DefocusDelta) - AstigmatismMean).Length() / AstigmatismStd;
                            FilterStatus &= AstigmatismDeviation <= (float)Options.Filter.AstigmatismMax;

                            FilterStatus &= item.CTFResolutionEstimate <= Options.Filter.ResolutionMax;

                            FilterStatus &= item.CTF.PhaseShift >= Options.Filter.PhaseMin && item.CTF.PhaseShift <= Options.Filter.PhaseMax;

                            FilterStatus &= item.GetParticleCount(Options.Filter.ParticlesSuffix) >= Options.Filter.ParticlesMin;
                        }

                        if (item.OptionsMovement != null)
                        {
                            FilterStatus &= item.MeanFrameMovement <= Options.Filter.MotionMax;
                        }

                        item.UnselectFilter = !FilterStatus;
                    }

                    ProcessingOptionsMovieCTF      OptionsCTF      = Options.GetProcessingMovieCTF();
                    ProcessingOptionsMovieMovement OptionsMovement = Options.GetProcessingMovieMovement();
                    ProcessingOptionsBoxNet        OptionsBoxNet   = Options.GetProcessingBoxNet();
                    ProcessingOptionsMovieExport   OptionsExport   = Options.GetProcessingMovieExport();

                    List <Movie> ItemsProcessed   = new List <Movie>();
                    List <Movie> ItemsFilteredOut = new List <Movie>();
                    List <Movie> ItemsUnselected  = new List <Movie>();

                    foreach (Movie item in Items)
                    {
                        ProcessingStatus Status = GetMovieProcessingStatus(item, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, Options);

                        if (Status == ProcessingStatus.Processed || (Status == ProcessingStatus.Outdated && !item.UnselectFilter))
                        {
                            ItemsProcessed.Add(item);
                        }
                        else if (Status == ProcessingStatus.FilteredOut || (Status == ProcessingStatus.Outdated && item.UnselectFilter))
                        {
                            ItemsFilteredOut.Add(item);
                        }
                        else if (Status == ProcessingStatus.LeaveOut)
                        {
                            ItemsUnselected.Add(item);
                        }
                    }

                    #endregion

                    #region Figure out how many frames/tilts there are to use

                    int UsableFrames = 1;
                    if (Items[0].GetType() == typeof(Movie))
                    {
                        UsableFrames = MapHeader.ReadFromFile(Items[0].Path).Dimensions.Z;
                    }
                    else
                    {
                        UsableFrames = ((TiltSeries)Items[0]).NTilts;
                    }

                    #endregion

                    #region Show dialog

                    CustomDialog Dialog = new CustomDialog();
                    Dialog.HorizontalContentAlignment = HorizontalAlignment.Center;

                    DialogCreateSourceFromSettings DialogContent = new DialogCreateSourceFromSettings();
                    DialogContent.TextTitle.Text = $"Create data source from\n{Info.Name}";
                    DialogContent.StatsSeriesStatusProcessed.Values = new ChartValues <ObservableValue> {
                        new ObservableValue(ItemsProcessed.Count)
                    };
                    DialogContent.StatsSeriesStatusUnfiltered.Values = new ChartValues <ObservableValue> {
                        new ObservableValue(ItemsFilteredOut.Count)
                    };
                    DialogContent.StatsSeriesStatusUnselected.Values = new ChartValues <ObservableValue> {
                        new ObservableValue(ItemsUnselected.Count)
                    };
                    DialogContent.SliderFrames.Value    = UsableFrames;
                    DialogContent.SliderFrames.MaxValue = UsableFrames;

                    DialogContent.Close += () =>
                    {
                        ((MainWindow)Application.Current.MainWindow).HideMetroDialogAsync(Dialog);
                    };

                    DialogContent.Create += async() =>
                    {
                        #region Create source metadata and check if one with the same path already exists

                        DataSource NewSource = new DataSource
                        {
                            PixelSizeX     = Options.PixelSizeX,
                            PixelSizeY     = Options.PixelSizeY,
                            PixelSizeAngle = Options.PixelSizeAngle,

                            DimensionsX = Options.Tomo.DimensionsX,
                            DimensionsY = Options.Tomo.DimensionsY,
                            DimensionsZ = Options.Tomo.DimensionsZ,
                            FrameLimit  = (int)DialogContent.SliderFrames.Value,

                            GainPath      = Options.Import.CorrectGain ? Options.Import.GainPath : "",
                            GainFlipX     = Options.Import.GainFlipX,
                            GainFlipY     = Options.Import.GainFlipY,
                            GainTranspose = Options.Import.GainTranspose,

                            DosePerAngstromFrame = Options.Import.DosePerAngstromFrame,

                            Name = DialogContent.TextSourceName.Text,
                            Path = Info.DirectoryName + "\\" + Helper.RemoveInvalidChars(DialogContent.TextSourceName.Text) + ".source"
                        };

                        if (Population.Sources.Any(s => s.Path == NewSource.Path))
                        {
                            await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                               $"{Helper.PathToNameWithExtension(NewSource.Path)} already exists in this population. Please choose a different name.",
                                                                                               MessageDialogStyle.Affirmative);
                            return;
                        }

                        await((MainWindow)Application.Current.MainWindow).HideMetroDialogAsync(Dialog);

                        #endregion

                        #region Add all items and their data hashes

                        List <Movie> AllItems = new List <Movie>(ItemsProcessed);
                        if ((bool)DialogContent.CheckFilter.IsChecked)
                        {
                            AllItems.AddRange(ItemsFilteredOut);
                        }
                        if ((bool)DialogContent.CheckManual.IsChecked)
                        {
                            AllItems.AddRange(ItemsUnselected);
                        }

                        if (AllItems.Count == 0)
                        {
                            await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                               $"No micrographs or tilt series found to match these settings.",
                                                                                               MessageDialogStyle.Affirmative);
                            return;
                        }

                        {
                            var ProgressDialog = await((MainWindow)Application.Current.MainWindow).ShowProgressAsync("Calculating data hashes...", "");
                            ProgressDialog.Maximum = AllItems.Count;

                            await Task.Run(() =>
                            {
                                int Done = 0;
                                foreach (var item in AllItems)
                                {
                                    NewSource.Files.Add(item.GetDataHash(), item.Name);

                                    ProgressDialog.SetProgress(++Done);
                                }
                            });

                            await ProgressDialog.CloseAsync();
                        }

                        #endregion

                        #region Check for overlapping hashes

                        string[] Overlapping = Helper.Combine(Population.Sources.Select(s => s.Files.Where(f => NewSource.Files.ContainsKey(f.Key)).Select(f => f.Value).ToArray()));
                        if (Overlapping.Length > 0)
                        {
                            string Offenders = "";
                            for (int o = 0; o < Math.Min(5, Overlapping.Length); o++)
                            {
                                Offenders += "\n" + Overlapping[o];
                            }
                            if (Overlapping.Length > 5)
                            {
                                Offenders += $"\n... and {Overlapping.Length - 5} more.";
                            }

                            await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                               "The new source contains files that are already used in this population:" + Offenders,
                                                                                               MessageDialogStyle.Affirmative);
                            return;
                        }

                        #endregion

                        {
                            var ProgressDialog = await((MainWindow)Application.Current.MainWindow).ShowProgressAsync("Committing initial version...", "");
                            ProgressDialog.Maximum = AllItems.Count;

                            await Task.Run(() =>
                            {
                                NewSource.Commit();
                            });

                            await ProgressDialog.CloseAsync();
                        }

                        Population.Sources.Add(NewSource);

                        UpdateGridItems();
                    };

                    Dialog.Content = DialogContent;
                    await((MainWindow)Application.Current.MainWindow).ShowMetroDialogAsync(Dialog, new MetroDialogSettings()
                    {
                    });

                    #endregion
                }
                else
                {
                    try
                    {
                        if (Population.Sources.Any(s => s.Path == OpenDialog.FileName))
                        {
                            await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                               "This data source is already part of this population.",
                                                                                               MessageDialogStyle.Affirmative);
                            return;
                        }

                        DataSource NewSource = DataSource.FromFile(OpenDialog.FileName);
                        Population.Sources.Add(NewSource);

                        UpdateGridItems();
                    }
                    catch
                    {
                        await((MainWindow)Application.Current.MainWindow).ShowMessageAsync("Oopsie",
                                                                                           $"An error was encountered when reading {Info.Name}.",
                                                                                           MessageDialogStyle.Affirmative);
                        return;
                    }
                }
            }
        }
Пример #9
0
        private void UpdateHighlightTracker()
        {
            if (HighlightItem != null && Items.Count > 0)
            {
                PathPosition.Opacity     = 0.3;
                CheckCurrentName.Opacity = 0.5;
                BlurCurrentName.Radius   = 6;

                PathHighlightPosition.Visibility     = Visibility.Visible;
                CheckHighlightCurrentName.Visibility = Visibility.Visible;

                double StepLength = ActualWidth / Items.Count;

                int PositionIndex = Items.IndexOf(HighlightItem);
                if (PositionIndex < 0)  // Can't find it in Items, hide everything
                {
                    PathHighlightPosition.Visibility     = Visibility.Hidden;
                    CheckHighlightCurrentName.Visibility = Visibility.Hidden;
                    return;
                }

                double IdealOffset = (PositionIndex + 0.5) * StepLength;
                PathHighlightPosition.Margin = new Thickness(Math.Max(0, Math.Min(IdealOffset - PathPosition.ActualWidth / 2, ActualWidth - PathPosition.ActualWidth)),
                                                             0, 0, 0);

                string TextString = $"{HighlightItem.RootName} ({PositionIndex + 1}/{Items.Count})";
                Size   TextSize   = MeasureString(TextString);
                CheckHighlightCurrentName.Margin = new Thickness(Math.Max(0, Math.Min(IdealOffset - TextSize.Width / 2, ActualWidth - TextSize.Width) - 24),
                                                                 0, 0, 0);
                TextHighlightCurrentName.Text       = TextString;
                CheckHighlightCurrentName.IsChecked = HighlightItem.UnselectManual != null ? !(bool)HighlightItem.UnselectManual : (bool?)null;

                ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
                ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
                ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
                ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

                PenHighlightCurrentName.Brush = StatusToBrush(GetMovieProcessingStatus(HighlightItem, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options));

                PanelSegmentHighlight.Children.Clear();
                Rectangle Segment = new Rectangle
                {
                    Width               = StepLength,
                    Height              = 12,
                    Fill                = new SolidColorBrush(Colors.Transparent),
                    Stroke              = PathHighlightPosition.Fill,
                    StrokeThickness     = 1,
                    SnapsToDevicePixels = false
                };
                PanelSegmentHighlight.Children.Add(Segment);
                Canvas.SetLeft(Segment, PositionIndex * StepLength);

                if (File.Exists(HighlightItem.ThumbnailsPath))
                {
                    ImageSource Image = new BitmapImage(new Uri(HighlightItem.ThumbnailsPath));
                    ImageThumbnail.Source = Image;

                    PopupThumbnail.HorizontalOffset = Mouse.GetPosition(PanelSegments).X - Image.Width / 2;
                    ImageThumbnail.Visibility       = Visibility.Visible;
                }
                else
                {
                    PopupThumbnail.HorizontalOffset = Mouse.GetPosition(PanelSegments).X;
                    ImageThumbnail.Visibility       = Visibility.Collapsed;
                }

                #region Figure out processing status

                bool DoCTF      = MainWindow.Options.ProcessCTF;
                bool DoMovement = MainWindow.Options.ProcessMovement;
                bool DoPicking  = MainWindow.Options.ProcessPicking;
                bool DoExport   = OptionsExport.DoAverage || OptionsExport.DoStack || OptionsExport.DoDeconv || DoPicking;

                bool NeedsNewCTF     = OptionsCTF != HighlightItem.OptionsCTF;
                bool NeedsNewMotion  = OptionsMovement != HighlightItem.OptionsMovement;
                bool NeedsNewPicking = (OptionsBoxNet != HighlightItem.OptionsBoxNet ||
                                        NeedsNewMotion);
                bool NeedsNewExport = (DoMovement && NeedsNewMotion) ||
                                      OptionsExport != HighlightItem.OptionsMovieExport ||
                                      (OptionsExport.DoDeconv && NeedsNewCTF && DoCTF);

                if (HighlightItem.OptionsCTF != null)
                {
                    IndicatorCTF.Foreground = NeedsNewCTF ? (DoCTF ? BrushOutdatedOpaque : BrushDeselected) : BrushProcessedOpaque;
                }
                else if (DoCTF)
                {
                    IndicatorCTF.Foreground = BrushUnprocessedOpaque;
                }
                else
                {
                    IndicatorCTF.Foreground = BrushDeselected;
                }

                if (HighlightItem.OptionsMovement != null)
                {
                    IndicatorMotion.Foreground = NeedsNewMotion ? (DoMovement ? BrushOutdatedOpaque : BrushDeselected) : BrushProcessedOpaque;
                }
                else if (DoMovement)
                {
                    IndicatorMotion.Foreground = BrushUnprocessedOpaque;
                }
                else
                {
                    IndicatorMotion.Foreground = BrushDeselected;
                }

                if (HighlightItem.OptionsBoxNet != null)
                {
                    IndicatorPicking.Foreground = NeedsNewPicking ? (DoPicking ? BrushOutdatedOpaque : BrushDeselected) : BrushProcessedOpaque;
                }
                else if (DoPicking)
                {
                    IndicatorPicking.Foreground = BrushUnprocessedOpaque;
                }
                else
                {
                    IndicatorPicking.Foreground = BrushDeselected;
                }

                if (HighlightItem.OptionsMovieExport != null)
                {
                    IndicatorExport.Foreground = NeedsNewExport ? (DoExport ? BrushOutdatedOpaque : BrushDeselected) : BrushProcessedOpaque;
                }
                else if (DoExport)
                {
                    IndicatorExport.Foreground = BrushUnprocessedOpaque;
                }
                else
                {
                    IndicatorExport.Foreground = BrushDeselected;
                }

                #endregion

                PopupThumbnail.PlacementTarget = PanelSegments;
                PopupThumbnail.VerticalOffset  = -12;
                PopupThumbnail.IsOpen          = true;
            }
            else
            {
                PathPosition.Opacity     = 1;
                CheckCurrentName.Opacity = 1;
                BlurCurrentName.Radius   = 0;

                PathHighlightPosition.Visibility     = Visibility.Hidden;
                CheckHighlightCurrentName.Visibility = Visibility.Hidden;

                PanelSegmentHighlight.Children.Clear();

                PopupThumbnail.IsOpen = false;
            }
        }
Пример #10
0
        public void UpdateElements()
        {
            PanelSegments.Children.Clear();

            ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
            ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
            ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
            ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

            List <Tuple <Movie, ProcessingStatus> > WithStatus = new List <Tuple <Movie, ProcessingStatus> >(Items.Count);

            foreach (var item in Items)
            {
                WithStatus.Add(new Tuple <Movie, ProcessingStatus>(item, GetMovieProcessingStatus(item, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options)));
            }

            // Update number of processed movies.
            int NProcessed   = WithStatus.Sum(m => m.Item2 == ProcessingStatus.Processed || m.Item2 == ProcessingStatus.FilteredOut ? 1 : 0);
            int NProcessable = WithStatus.Sum(m => m.Item2 != ProcessingStatus.LeaveOut ? 1 : 0);

            TextNumberProcessed.Text = $"Processed {NProcessed}/{NProcessable}.";

            if (Items.Count == 0) // Hide unnecessary elements.
            {
                HideElements();
            }
            else
            {
                ShowElements();

                // Create colored navigation bar.
                double           StepLength    = ActualWidth / Items.Count;
                ProcessingStatus CurrentStatus = WithStatus[0].Item2;
                int    CurrentSteps            = 0;
                double OverallOffset           = 0;
                foreach (var movie in WithStatus)
                {
                    if (movie.Item2 != CurrentStatus)
                    {
                        Rectangle Segment = new Rectangle
                        {
                            Width  = CurrentSteps * StepLength + 0.3,
                            Height = 12,
                            Fill   = StatusToBrush(CurrentStatus),
                            SnapsToDevicePixels = false
                        };
                        PanelSegments.Children.Add(Segment);
                        Canvas.SetLeft(Segment, OverallOffset);

                        CurrentStatus  = movie.Item2;
                        OverallOffset += CurrentSteps * StepLength;
                        CurrentSteps   = 0;
                    }

                    CurrentSteps++;
                }
                if (CurrentSteps > 0)
                {
                    Rectangle Segment = new Rectangle
                    {
                        Width  = CurrentSteps * StepLength,
                        Height = 12,
                        Fill   = StatusToBrush(CurrentStatus),
                        SnapsToDevicePixels = false
                    };
                    PanelSegments.Children.Add(Segment);
                    Canvas.SetLeft(Segment, OverallOffset);
                }

                UpdateTracker();
            }
        }
Пример #11
0
        public void UpdateElements()
        {
            PanelSegments.Children.Clear();

            ProcessingOptionsMovieCTF      OptionsCTF      = MainWindow.Options.GetProcessingMovieCTF();
            ProcessingOptionsMovieMovement OptionsMovement = MainWindow.Options.GetProcessingMovieMovement();
            ProcessingOptionsBoxNet        OptionsBoxNet   = MainWindow.Options.GetProcessingBoxNet();
            ProcessingOptionsMovieExport   OptionsExport   = MainWindow.Options.GetProcessingMovieExport();

            List <Tuple <Movie, ProcessingStatus> > WithStatus = new List <Tuple <Movie, ProcessingStatus> >(RowItems.Count);

            foreach (var item in RowItems)
            {
                WithStatus.Add(new Tuple <Movie, ProcessingStatus>(item, StatusBar.GetMovieProcessingStatus(item, OptionsCTF, OptionsMovement, OptionsBoxNet, OptionsExport, MainWindow.Options)));
            }


            if (RowItems.Count == 0 || AllItems == null || ActualWidth == 0 || ItemWidth == 0) // Hide unnecessary elements.
            {
                HideElements();
            }
            else
            {
                ShowElements();

                // Create colored navigation bar.

                ProcessingStatus CurrentStatus = WithStatus[0].Item2;
                int    CurrentSteps            = 0;
                double OverallOffsetX          = 0;

                foreach (var movie in WithStatus)
                {
                    if (movie.Item2 != CurrentStatus)
                    {
                        Rectangle Segment = new Rectangle
                        {
                            Width  = CurrentSteps * ItemWidth + 0.3,
                            Height = 12,
                            Fill   = StatusBar.StatusToBrush(CurrentStatus),
                            SnapsToDevicePixels = false
                        };
                        PanelSegments.Children.Add(Segment);
                        Canvas.SetLeft(Segment, OverallOffsetX);

                        CurrentStatus   = movie.Item2;
                        OverallOffsetX += CurrentSteps * ItemWidth;
                        CurrentSteps    = 0;
                    }

                    CurrentSteps++;
                }
                if (CurrentSteps > 0)
                {
                    Rectangle Segment = new Rectangle
                    {
                        Width  = CurrentSteps * ItemWidth,
                        Height = 12,
                        Fill   = StatusBar.StatusToBrush(CurrentStatus),
                        SnapsToDevicePixels = false
                    };
                    PanelSegments.Children.Add(Segment);
                    Canvas.SetLeft(Segment, OverallOffsetX);
                }

                UpdateTracker();
            }
        }