private void UpdateHistogramDisplay()
 {
     if (_histogramRawCache != null &&
         _histogramDisplayCache != null)
     {
         var graphics2D = _histogramDisplayCache.NewGraphics2D();
         graphics2D.Clear(Color.Transparent);
         _histogramDisplayCache.CopyFrom(_histogramRawCache);
         var rangeStart = RangeStart.Value(this);
         var rangeEnd   = RangeEnd.Value(this);
         graphics2D.FillRectangle(0, 0, rangeStart * _histogramDisplayCache.Width, _histogramDisplayCache.Height, new Color(Color.Red, 100));
         graphics2D.FillRectangle(rangeEnd * _histogramDisplayCache.Width, 0, 255, _histogramDisplayCache.Height, new Color(Color.Red, 100));
         graphics2D.Line(rangeStart * _histogramDisplayCache.Width, 0, rangeStart * _histogramDisplayCache.Width, _histogramDisplayCache.Height, new Color(Color.LightGray, 200));
         graphics2D.Line(rangeEnd * _histogramDisplayCache.Width, 0, rangeEnd * _histogramDisplayCache.Width, _histogramDisplayCache.Height, new Color(Color.LightGray, 200));
     }
 }
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            UpdateHistogramDisplay();
            bool propertyUpdated = false;
            var  minSeparation   = .01;
            var  rangeStart      = RangeStart.Value(this);
            var  rangeEnd        = RangeEnd.Value(this);

            if (rangeStart < 0 ||
                rangeStart > 1 ||
                rangeEnd < 0 ||
                rangeEnd > 1 ||
                rangeStart > rangeEnd - minSeparation)
            {
                rangeStart = Math.Max(0, Math.Min(1 - minSeparation, rangeStart));
                rangeEnd   = Math.Max(0, Math.Min(1, rangeEnd));
                if (rangeStart > rangeEnd - minSeparation)
                {
                    // values are overlapped or too close together
                    if (rangeEnd < 1 - minSeparation)
                    {
                        // move the end up whenever possible
                        rangeEnd = rangeStart + minSeparation;
                    }
                    else
                    {
                        // move the end to the end and the start up
                        rangeEnd   = 1;
                        RangeStart = 1 - minSeparation;
                    }
                }

                propertyUpdated = true;
            }

            var rebuildLock = RebuildLock();

            // now create a long running task to process the image
            return(ApplicationController.Instance.Tasks.Execute(
                       "Calculate Path".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var progressStatus = new ProgressStatus();
                this.GenerateMarchingSquaresAndLines(
                    (progress0to1, status) =>
                {
                    progressStatus.Progress0To1 = progress0to1;
                    progressStatus.Status = status;
                    reporter.Report(progressStatus);
                },
                    Image,
                    ThresholdFunction);

                if (propertyUpdated)
                {
                    UpdateHistogramDisplay();
                    this.Invalidate(InvalidateType.Properties);
                }

                UiThread.RunOnIdle(() =>
                {
                    rebuildLock.Dispose();
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Path));
                });

                return Task.CompletedTask;
            }));
        }