Changeset - a1bd6e3474d6
[Not reviewed]
default
0 1 0
Tess Snider (Malkyne) - 3 years ago 2021-07-24 10:55:15
this@malkyne.org
Should now extraplate white reactions if any of the channels didn't clip.
1 file changed with 39 insertions and 1 deletions:
0 comments (0 inline, 0 general)
Models/ReactionTest.cs
Show inline comments
...
 
@@ -84,240 +84,278 @@ namespace DesertPaintCodex.Models
 

	
 
        public bool IsAllCatalysts { get; }
 

	
 
        private Reaction? _reaction;
 
        public Reaction? Reaction { get => _reaction; set { _reaction = value; NotifyPropertyChanged(nameof(Reaction)); } }
 

	
 
        private Reaction? _badReaction;
 
        public Reaction? BadReaction { get => _badReaction; set { _badReaction = value; NotifyPropertyChanged(nameof(BadReaction)); } }
 

	
 
        private int _scanProgress;
 
        public int ScanProgress { get => _scanProgress; set { _scanProgress = value; NotifyPropertyChanged(nameof(ScanProgress)); } }
 
        
 
        
 
        private TestState _state;
 

	
 
        public TestState State
 
        {
 
            get => _state;
 
            set
 
            {
 
                _state = value;
 
                NotifyPropertyChanged(nameof(State));
 
                NotifyPropertyChanged(nameof(Requires3Way));
 
                NotifyPropertyChanged(nameof(CanScan));
 
                NotifyPropertyChanged(nameof(IsScanning));
 
                NotifyPropertyChanged(nameof(HasResults));
 
                NotifyPropertyChanged(nameof(HasReaction));
 
                NotifyPropertyChanged(nameof(CanClear));
 
                NotifyPropertyChanged(nameof(CanSave));
 
                NotifyPropertyChanged(nameof(NoLab));
 
                NotifyPropertyChanged(nameof(CanPickBuffer));
 
                NotifyPropertyChanged(nameof(ShowFirstBuffer));
 
                NotifyPropertyChanged(nameof(ShowLastBuffer));
 
            }
 
        }
 

	
 
        public bool Requires3Way =>
 
            (State == TestState.ClippedResult) || IsAllCatalysts;
 

	
 
        public bool CanScan => (State is TestState.Untested or TestState.LabNotFound) || ((State == TestState.ClippedResult) && BufferIsSelected);
 
        
 
        public bool IsScanning => State == TestState.Scanning;
 

	
 
        public bool HasResults => (ObservedColor != null) && (State is TestState.ClippedResult or TestState.GoodResult or TestState.LabNotFound);
 

	
 
        public bool HasReaction => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
 
        
 
        public bool CanClear => State is TestState.ClippedResult or TestState.GoodResult or TestState.Saved;
 
        
 
        public bool CanSave => State == TestState.GoodResult;
 

	
 
        public bool NoLab => State == TestState.LabNotFound;
 

	
 
        public bool CanPickBuffer => (State == TestState.ClippedResult) || IsAllCatalysts;
 

	
 
        public bool ShowFirstBuffer => Requires3Way && UseFirstBuffer;
 

	
 
        public bool ShowLastBuffer => Requires3Way && !UseFirstBuffer;
 

	
 

	
 
        private PaintColor? _hypotheticalColor;
 
        public PaintColor? HypotheticalColor { get => _hypotheticalColor; set { _hypotheticalColor = value; NotifyPropertyChanged(nameof(HypotheticalColor)); } }
 

	
 
        private PaintColor? _observedColor;
 
        public PaintColor? ObservedColor { get => _observedColor; set { _observedColor = value; NotifyPropertyChanged(nameof(ObservedColor)); } }
 

	
 
        private readonly PaintRecipe _recipe = new();
 

	
 
        public bool IsStub { get; }
 

	
 

	
 
        public ReactionTest(Reagent reagent1, Reagent reagent2, Reaction? reaction, ClipType clipType, bool isStub = false)
 
        {
 
            Reagent1 = reagent1;
 
            Reagent2 = reagent2;
 
            UseFirstBuffer = true;
 
            IsAllCatalysts = reagent1.IsCatalyst && reagent2.IsCatalyst;
 
            Clipped = clipType;
 
            Reaction = reaction;
 
            State = (reaction != null) ? TestState.Saved :
 
                (clipType == ClipType.None) ? TestState.Untested : TestState.ClippedResult;
 
            _recipe.AddReagent(reagent1.Name);
 
            _recipe.AddReagent(reagent2.Name);
 
            IsStub = isStub;
 
            UpdateHypotheticalColor();
 
        }
 

	
 
        
 
        #region Actions
 
        public async Task StartScan()
 
        {
 
            Clipped = ClipType.None;
 
            ScanProgress = 0;
 
            Reaction = null;
 
            BadReaction = null;
 
            State = TestState.Scanning;
 
            bool testing3Way = Requires3Way && BufferIsSelected;
 
            bool foundLab = await ReactionScannerService.Instance.CaptureReactionAsync(this);
 
            if (foundLab)
 
            {
 
                ObservedColor = ReactionScannerService.Instance.RecordedColor;
 
                if (_observedColor != null)
 
                {
 
                    // Handle the normal case.
 
                    Clipped = _observedColor.Red switch
 
                        {
 
                            0   => ClipType.RedLow,
 
                            255 => ClipType.RedHigh,
 
                            _   => ClipType.None
 
                        }
 
                        | _observedColor.Green switch
 
                        {
 
                            0   => ClipType.GreenLow,
 
                            255 => ClipType.GreenHigh,
 
                            _   => ClipType.None
 
                        }
 
                        | _observedColor.Blue switch
 
                        {
 
                            0   => ClipType.BlueLow,
 
                            255 => ClipType.BlueHigh,
 
                            _   => ClipType.None
 
                        };
 

	
 
                    if (Clipped == ClipType.None)
 
                    {
 
                        State = TestState.GoodResult;
 
                        Reaction = CalculateReaction();
 
                    }
 
                    else
 
                    {
 
                        State = TestState.ClippedResult;
 
                        BadReaction = CalculateReaction();
 

	
 
                        // SPECIAL CASE:
 
                        // Check to see if we've got a white-shift reaction that's partially clipped, where we can
 
                        // still extrapolate the reaction, based on the available information.
 
                        if (!testing3Way && (BadReaction != null))
 
                        {
 
                            PaintColor baseColor = _recipe.BaseColor;
 
                            if ((BadReaction.Red < baseColor.Red) &&
 
                                (BadReaction.Green < baseColor.Green) &&
 
                                (BadReaction.Blue < baseColor.Blue))
 
                            {
 
                                // White-shift down clip.
 
                                bool extrapolated               = ExtrapolateWhiteFromOneChannel(_observedColor.Red,   0, BadReaction.Red);
 
                                if (!extrapolated) extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Green, 0, BadReaction.Green);
 
                                if (!extrapolated)                ExtrapolateWhiteFromOneChannel(_observedColor.Blue,  0, BadReaction.Blue);
 
                            }
 
                            else if ((BadReaction.Red > baseColor.Red) &&
 
                                (BadReaction.Green > baseColor.Green) &&
 
                                (BadReaction.Blue > baseColor.Blue))
 
                            {
 
                                // White-shift up clip.
 
                                bool extrapolated               = ExtrapolateWhiteFromOneChannel(_observedColor.Red,   255, BadReaction.Red);
 
                                if (!extrapolated) extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Green, 255, BadReaction.Green);
 
                                if (!extrapolated)                ExtrapolateWhiteFromOneChannel(_observedColor.Blue,  255, BadReaction.Blue);
 
                            }
 
                        }
 
                    }
 
                    
 
                    PlayerProfile? profile = ProfileManager.CurrentProfile;
 
                    profile?.SetPairClipStatus(Reagent1, Reagent2, Clipped);
 
                }
 
            }
 
            else
 
            {
 
                Debug.WriteLine("ERROR: Lab UI not found.");
 
                State = TestState.LabNotFound;
 
            }
 
        }
 

	
 
        private bool ExtrapolateWhiteFromOneChannel(int result, int clipBound, int reaction)
 
        {
 
            if (result == clipBound) return false;
 
            
 
            Clipped  = ClipType.None;
 
            Reaction = new Reaction(reaction, reaction, reaction);
 
            BadReaction = null;
 
            State    = TestState.GoodResult;
 
            return true;
 
        }
 

	
 

	
 
        public void CancelScan()
 
        {
 
            ReactionScannerService.Instance.CancelScan();
 
            State = TestState.Untested;
 
        }
 

	
 
        public void MarkInert()
 
        {
 
            Reaction = new Reaction(0, 0, 0);
 
            State = TestState.GoodResult;
 
        }
 

	
 
        public void ClearReaction()
 
        {
 
            PlayerProfile? profile = ProfileManager.CurrentProfile;
 
            if (profile == null) return;
 
            profile.Reactions.Remove(Reagent1, Reagent2);
 
            profile.SetPairClipStatus(Reagent1, Reagent2, ClipType.None);
 
            if (State == TestState.Saved)
 
            {
 
                profile.Save();
 
            }
 
            
 
            Reaction = null;
 
            BadReaction = null;
 
            Clipped = ClipType.None;
 
            State = TestState.Untested;
 
        }
 

	
 
        public void SaveReaction()
 
        {
 
            PlayerProfile? profile = ProfileManager.CurrentProfile;
 
            if (profile == null) return;
 
            profile.Reactions.Set(Reagent1, Reagent2, Reaction);
 
            profile.Save();
 
            State = TestState.Saved;
 
        }
 

	
 
        #endregion
 
        
 
        #region Internals
 

	
 
        private Reaction? CalculateReaction()
 
        {
 
            if (ProfileManager.CurrentProfile == null) return null;
 
            if (HypotheticalColor == null) return null;
 
            if (ObservedColor == null) return null;
 

	
 
            if (_useFirstBuffer)
 
            {
 
                if (BufferReagentFirst != null)
 
                {
 
                    return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
 
                        ObservedColor, BufferReagentFirst, Reagent1, Reagent2, true);
 
                }
 
            }
 
            else
 
            {
 
                if (BufferReagentLast != null)
 
                {
 
                    return ReactionScannerService.Calculate3WayReaction(ProfileManager.CurrentProfile, HypotheticalColor,
 
                        ObservedColor, Reagent1, Reagent2, BufferReagentLast, false);
 
                }
 
            }
 
            
 
            return ReactionScannerService.CalculateReaction(HypotheticalColor, ObservedColor);
 
        }
 

	
 

	
 
        private void UpdateHypotheticalColor()
 
        {
 
            HypotheticalColor = null;
 
            HypotheticalColor = (IsAllCatalysts && !BufferIsSelected) ? null : _recipe.BaseColor;
 
        }
 

	
 
        private bool BufferIsSelected => UseFirstBuffer ? (BufferReagentFirst != null) : (BufferReagentLast != null);
 

	
 

	
 
        private void UpdateRecipe()
 
        {
 
            _recipe.Clear();
 
            if (_useFirstBuffer)
 
            {
 
                if (_bufferReagentFirst == null)
 
                {
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                }
 
                else
 
                {
 
                    _recipe.AddReagent(_bufferReagentFirst.Name);
 
                    _recipe.AddReagent(Reagent1.Name);
 
                    _recipe.AddReagent(Reagent2.Name);
 
                } 
 
            }
 
            else
0 comments (0 inline, 0 general)