diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 776c79c..5fc7318 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -23,28 +23,31 @@ jobs: - name: Restore dependencies run: dotnet restore - - name: Build Release (library) - run: dotnet build GEffectsLogic/GEffectsLogic.csproj -c Release --no-restore + - name: Build all configurations + run: | + dotnet build GEffectsLogic/GEffectsLogic.csproj -c Release --no-restore + dotnet build GEffectsLogic/GEffectsLogic.csproj -c Debug --no-restore - - name: Build Debug (library) - run: dotnet build GEffectsLogic/GEffectsLogic.csproj -c Debug --no-restore + - name: Collect artifacts + run: | + mkdir -p artifacts/net10.0/release + mkdir -p artifacts/net10.0/debug + mkdir -p artifacts/net481/release + mkdir -p artifacts/net481/debug - - name: Upload Release DLL artifact - uses: actions/upload-artifact@v4 - with: - name: GEffectsLogic.dll - path: GEffectsLogic/bin/Release/net10.0/GEffectsLogic.dll + cp GEffectsLogic/bin/Release/net10.0/GEffectsLogic.dll artifacts/net10.0/release/ + cp GEffectsLogic/bin/Debug/net10.0/GEffectsLogic.dll artifacts/net10.0/debug/ + cp GEffectsLogic/bin/Debug/net10.0/GEffectsLogic.pdb artifacts/net10.0/debug/ - - name: Prepare Debug DLL name - run: | - mkdir -p artifacts/debug - cp GEffectsLogic/bin/Debug/net10.0/GEffectsLogic.dll artifacts/debug/GEffectsLogic.dev.dll + cp GEffectsLogic/bin/Release/net481/GEffectsLogic.dll artifacts/net481/release/ + cp GEffectsLogic/bin/Debug/net481/GEffectsLogic.dll artifacts/net481/debug/ + cp GEffectsLogic/bin/Debug/net481/GEffectsLogic.pdb artifacts/net481/debug/ - - name: Upload Debug DLL artifact + - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: GEffectsLogic.dev.dll - path: artifacts/debug/GEffectsLogic.dev.dll + name: GEffectsLogic + path: artifacts/ test: runs-on: ubuntu-latest diff --git a/.idea/.idea.GEffectsLogic/.idea/workspace.xml b/.idea/.idea.GEffectsLogic/.idea/workspace.xml index 681b253..3291e68 100644 --- a/.idea/.idea.GEffectsLogic/.idea/workspace.xml +++ b/.idea/.idea.GEffectsLogic/.idea/workspace.xml @@ -5,22 +5,11 @@ GEffectsLogic/GEffectsLogic.csproj GraphicLogicTest/GraphicLogicTest.csproj + + - - - - - - - - - - - - - - - + + + + + + { "associatedIndex": 0, @@ -42,25 +41,32 @@ - { + "keyToString": { + ".NET Project.GraphicLogicTest.executor": "Run", + "ModuleVcsDetector.initialDetectionPerformed": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", + "RunOnceActivity.cidr.known.project.marker": "true", + "RunOnceActivity.git.unshallow": "true", + "RunOnceActivity.readMode.enableVisualFormatting": "true", + "RunOnceActivity.typescript.service.memoryLimit.init": "true", + "XThreadsFramesViewSplitterKey": "0.3137255", + "cidr.known.project.marker": "true", + "codeWithMe.voiceChat.enabledByDefault": "false", + "git-widget-placeholder": "develop-GLoCPlot", + "git.auto.fetch.suggestion.counter": "1", + "last_opened_file_path": "/Users/LINBASS/repos/GEffectsLogic", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "vcs.Git", + "vue.rearranger.settings.migration": "true" + }, + "keyToStringList": { + "com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File": [ + "TEXT" + ] } -}]]> +} @@ -134,8 +171,23 @@ + + + diff --git a/GEffectsLogic/GEffectsLogic.csproj b/GEffectsLogic/GEffectsLogic.csproj index 0a2111e..a8429f5 100644 --- a/GEffectsLogic/GEffectsLogic.csproj +++ b/GEffectsLogic/GEffectsLogic.csproj @@ -1,15 +1,15 @@  - net10.0 - enable - enable + net481;net10.0 + latest + enable Debug;Release;PerfDebug False - 0.2.0 + 0.3.0 $(VersionPrefix) - 0.2.0.0 + 0.3.0.0 $(VersionPrefix).0 nogit diff --git a/GEffectsLogic/LogicSettings.cs b/GEffectsLogic/LogicSettings.cs index 3dc2d8f..c38562e 100644 --- a/GEffectsLogic/LogicSettings.cs +++ b/GEffectsLogic/LogicSettings.cs @@ -2,7 +2,7 @@ { public static class LogicSettings { - public static double StabilizationTimeThreshold { get; set; } = 30.0; + public static double StabilizationTimeThreshold { get; set; } = 600.0; // --- Physiological model parameters --- @@ -16,7 +16,6 @@ public static class LogicSettings public static double HydrostaticShiftExponent { get; set; } = 2.2; // Keep these summing to ~1.0 - public static double HeadCoreShiftFraction { get; set; } = 0.45; public static double CoreLowerShiftFraction { get; set; } = 0.55; // Passive return / compensation @@ -98,5 +97,26 @@ public static class LogicSettings public static double GSuitGlobalShiftReductionMax { get; set; } = 0.20; // optional mild global scaling public static double GSuitCoreLowerReductionMax { get; set; } = 0.60; // reduce core->lower pooling public static double GSuitLowerReturnBoostMax { get; set; } = 0.80; // increase lower return + + // --- Fatigue / resistance reduction --- + + // Fraction of GSuitEffectiveness that the suit retains passively (hardware inflation) regardless of fatigue + public static double GSuitPassiveFraction { get; set; } = 0.25; + + // Straining (AGSM) fatigue: rate at which the human straining component degrades + // Build rate is per-second at strainingLevel=1 (quadratic: actual rate = BuildRate * strainingLevel²) + // ~60-90s of max straining to saturate (1/BuildRate ≈ saturation time) + public static double StrainingFatigueBuildRate { get; set; } = 0.015; // saturates ~67s at full strain + public static double StrainingFatigueRecoveryTau { get; set; } = 150.0; // ~2.5 min to recover + + // G-suit mechanical fatigue: slower than straining fatigue (suit outlasts the pilot's AGSM) + // Build rate is per-second at strainingLevel=1 (linear: actual rate = BuildRate * strainingLevel) + public static double GSuitFatigueBuildRate { get; set; } = 0.004; // saturates ~250s at full strain + public static double GSuitFatigueRecoveryTau { get; set; } = 300.0; // ~5 min to recover + + // Cardiovascular fatigue: hrFatigue (0..1) accumulates at CardioFatigueBuildRate × hrElevation per second + public static double CardioFatigueBuildRate { get; set; } = 0.008; // ~125s at max HR elevation to fully fatigue + public static double CardioFatigueRecoveryTau { get; set; } = 240.0; // ~4 min to fully recover + public static double CardioFatigueMaxHRFloor { get; set; } = 1.25; // HR floor when fully fatigued } } \ No newline at end of file diff --git a/GEffectsLogic/PhysiologicalModel.cs b/GEffectsLogic/PhysiologicalModel.cs index 6df7579..cbd5a56 100644 --- a/GEffectsLogic/PhysiologicalModel.cs +++ b/GEffectsLogic/PhysiologicalModel.cs @@ -24,15 +24,17 @@ namespace GEffectsLogic /// public class PhysiologicalModel { - // TODO - fix straining level being a fixed input - // --- Compartment blood volumes (fraction of total, sum = 1.0) --- protected double bloodHead = LogicSettings.RestingBloodHead; protected double bloodCore = LogicSettings.RestingBloodCore; protected double bloodLower = LogicSettings.RestingBloodLower; protected double brainO2 = 1.0; protected double heartRateMultiplier = 1.0; // Baroreceptor reflex: heart rate multiplier (1.0 = resting) - protected double strainingLevel = 0.0; // Straining effort (0..1): pilot anti-G straining maneuver including g suit inflation + protected double strainingLevel = 0.0; // Straining effort (0..1): pilot anti-G straining maneuver including g-suit inflation + protected double strainingFatigue = 0.0; // Accumulated AGSM fatigue (0..1): degrades the human straining component + protected double gSuitFatigue = 0.0; // Accumulated g-suit fatigue (0..1): degrades mechanical suit compression + protected double hrFatigue = 0.0; // Cardiovascular fatigue (0..1): suppresses baroreceptor HR toward fatigueHeartRateFloor + protected double fatigueHeartRateFloor = LogicSettings.CardioFatigueMaxHRFloor; protected double perfusionLevel = 0.0; protected double consciousnessLevel = 1.0; //protected double confusionLevel = 0.0; @@ -42,7 +44,7 @@ public class PhysiologicalModel #region Public read-only state public readonly int UniqueID; - + /// Fraction of total blood in the head compartment. public double BloodHead => bloodHead; @@ -58,6 +60,18 @@ public class PhysiologicalModel /// Current heart rate multiplier from baroreceptor reflex. public double HeartRateMultiplier => heartRateMultiplier; + /// Accumulated AGSM fatigue (0 = fresh, 1 = fully exhausted). + public double StrainingFatigue => strainingFatigue; + + /// Accumulated g-suit mechanical fatigue (0 = full effectiveness, 1 = degraded to passive fraction). + public double GSuitFatigue => gSuitFatigue; + + /// Cardiovascular fatigue accumulator (0 = fresh, 1 = fully fatigued — HR pinned to floor). + public double HrFatigue => hrFatigue; + + /// Fixed HR floor the baroreceptor is suppressed toward when fully fatigued. + public double FatigueHeartRateFloor => fatigueHeartRateFloor; + /// Current straining level (0 = none, 1 = max). //public double StrainingLevel => strainingLevel; @@ -88,6 +102,10 @@ public virtual void Reset() brainO2 = 1.0; heartRateMultiplier = 1.0; strainingLevel = 0.0; + strainingFatigue = 0.0; + gSuitFatigue = 0.0; + hrFatigue = 0.0; + fatigueHeartRateFloor = LogicSettings.CardioFatigueMaxHRFloor; tunnelVisionLevel = 0.0; greyScaleLevel = 0.0; primaryColor = true; @@ -95,9 +113,16 @@ public virtual void Reset() perfusionLevel = 0.0; } +#if NET481 + public static double Clamp(double value, double min, double max) => Math.Max(Math.Min(value, max), min); +#else + public static double Clamp(double value, double min, double max) => Math.Clamp(value, min, max); +#endif + + public static double SmoothStep(double x) { - x = Math.Clamp(x, 0.0, 1.0); + x = Clamp(x, 0.0, 1.0); return x * x * (3.0 - (2.0 * x)); } @@ -145,17 +170,41 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. targetStraining = (gz - LogicSettings.StrainingStartGz) / (LogicSettings.StrainingFullGz - LogicSettings.StrainingStartGz); } - targetStraining = Math.Clamp(targetStraining, 0.0, 1.0); + targetStraining = Clamp(targetStraining, 0.0, 1.0); strainingLevel = StepTowardsLinear(strainingLevel, targetStraining, LogicSettings.StrainingTau, dt); - // Suit effect only for +Gz loading - double suitActivation = Math.Clamp(LogicSettings.GSuitEffectiveness * strainingLevel, 0.0, 1.0); + // Fatigue: straining fatigue fills while strainingLevel is high, drains slowly at rest + double strainingFatigueBuildRate = LogicSettings.StrainingFatigueBuildRate * strainingLevel * strainingLevel; + double strainingFatigueDecayRate = 1.0 / LogicSettings.StrainingFatigueRecoveryTau; + strainingFatigue += strainingLevel > 0.01 + ? strainingFatigueBuildRate * dt + : -strainingFatigueDecayRate * strainingFatigue * dt; + strainingFatigue = Clamp(strainingFatigue, 0.0, 1.0); + + // G-suit fatigue builds more slowly (mechanical, outlasts the pilot's AGSM), also drains slowly + double gSuitFatigueBuildRate = LogicSettings.GSuitFatigueBuildRate * strainingLevel; + double gSuitFatigueDecayRate = 1.0 / LogicSettings.GSuitFatigueRecoveryTau; + gSuitFatigue += strainingLevel > 0.01 + ? gSuitFatigueBuildRate * dt + : -gSuitFatigueDecayRate * gSuitFatigue * dt; + gSuitFatigue = Clamp(gSuitFatigue, 0.0, 1.0); + + // Effective straining: human AGSM component fully degrades with strainingFatigue + double effectiveStraining = strainingLevel * (1.0 - strainingFatigue); + + // Effective g-suit: mechanical suit retains a passive fraction, only the active compression degrades + double gSuitActiveFraction = 1.0 - LogicSettings.GSuitPassiveFraction; + double effectiveGSuit = LogicSettings.GSuitEffectiveness * + (LogicSettings.GSuitPassiveFraction + (gSuitActiveFraction * (1.0 - gSuitFatigue))); + + // Suit effect only for +Gz loading, coupled to effective straining + double suitActivation = Clamp(effectiveGSuit * effectiveStraining, 0.0, 1.0); double suit = gzNet > 0.0 ? suitActivation : 0.0; // Mild global scaling + targeted redistribution double effectiveGzShift = gzNetScaled * (1.0 - (LogicSettings.GSuitGlobalShiftReductionMax * suit)); - double coreLowerFractionEffective = Math.Clamp( + double coreLowerFractionEffective = Clamp( LogicSettings.CoreLowerShiftFraction * (1.0 - (LogicSettings.GSuitCoreLowerReductionMax * suit)), 0.05, 0.95); @@ -171,9 +220,9 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. double returnRate = LogicSettings.PassiveReturnRate * heartRateMultiplier; double lowerReturnRate = returnRate * (1.0 + (LogicSettings.GSuitLowerReturnBoostMax * suit)); - bloodHead = (bloodHead + (shiftHeadRate + (returnRate * LogicSettings.RestingBloodHead)) * dt) / (1.0 + (returnRate * dt)); - bloodCore = (bloodCore + (shiftCoreRate + (returnRate * LogicSettings.RestingBloodCore)) * dt) / (1.0 + (returnRate * dt)); - bloodLower = (bloodLower + (shiftLowerRate + (lowerReturnRate * LogicSettings.RestingBloodLower)) * dt) / (1.0 + (lowerReturnRate * dt)); + bloodHead = (bloodHead + ((shiftHeadRate + (returnRate * LogicSettings.RestingBloodHead)) * dt)) / (1.0 + (returnRate * dt)); + bloodCore = (bloodCore + ((shiftCoreRate + (returnRate * LogicSettings.RestingBloodCore)) * dt)) / (1.0 + (returnRate * dt)); + bloodLower = (bloodLower + ((shiftLowerRate + (lowerReturnRate * LogicSettings.RestingBloodLower)) * dt)) / (1.0 + (lowerReturnRate * dt)); // Enforce conservation (redistribute any numerical drift) double total = bloodHead + bloodCore + bloodLower; @@ -213,23 +262,23 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. // O2 delivery depends on head blood volume relative to resting double perfusionRatio = bloodHead / LogicSettings.RestingBloodHead; - perfusionRatio = Math.Clamp(perfusionRatio, 0.0, 1.0); + perfusionRatio = Clamp(perfusionRatio, 0.0, 1.0); // Perfusion shaping double s = LogicSettings.O2PerfusionCurveStrength; double pivot = LogicSettings.O2PerfusionCurvePivot; double shapedPerfusion = perfusionRatio - (s * perfusionRatio * (1.0 - perfusionRatio) * (perfusionRatio - pivot)); - shapedPerfusion = Math.Clamp(shapedPerfusion, 0.0, 1.0); + shapedPerfusion = Clamp(shapedPerfusion, 0.0, 1.0); // convert perfusion -> effective O2 delivery (non-linear + mild sustained hypoperfusion penalty) double effectiveDelivery = Math.Pow(shapedPerfusion, LogicSettings.BrainO2PerfusionExponent); - double threshold = Math.Clamp(LogicSettings.BrainO2HypoperfusionThreshold, 0.01, 1.0); + double threshold = Clamp(LogicSettings.BrainO2HypoperfusionThreshold, 0.01, 1.0); double hypoperfusion = Math.Max(0.0, threshold - shapedPerfusion) / threshold; double hypoperfusionPenalty = LogicSettings.BrainO2HypoperfusionPenaltyStrength * hypoperfusion * hypoperfusion; - effectiveDelivery = Math.Clamp(effectiveDelivery - hypoperfusionPenalty, 0.0, 1.0); + effectiveDelivery = Clamp(effectiveDelivery - hypoperfusionPenalty, 0.0, 1.0); // Target O2 is bounded by floor, then approached with time constants double targetBrainO2 = LogicSettings.BrainO2Floor + ((1.0 - LogicSettings.BrainO2Floor) * effectiveDelivery); @@ -245,11 +294,25 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. : LogicSettings.BrainO2RecoveryTau; brainO2 = StepTowardsLinear(brainO2, targetBrainO2, o2Tau, dt); - brainO2 = Math.Clamp(brainO2, LogicSettings.BrainO2Floor, 1.0); - - // When head perfusion drops, heart rate increases (delayed response) - double targetHR = 1.0 + (LogicSettings.BaroreceptorGain * Math.Max(0, 1.0 - perfusionRatio)); - targetHR = Math.Min(targetHR, LogicSettings.MaxHeartRateMultiplier); + brainO2 = Clamp(brainO2, LogicSettings.BrainO2Floor, 1.0); + + // Cardiovascular fatigue: hrFatigue (0..1) accumulates with time × HR elevation, + // decays slowly at rest. It is independent of current HR so it always wins eventually. + double hrElevation = Math.Max(0.0, heartRateMultiplier - 1.0); + double hrFatigueBuildRate = LogicSettings.CardioFatigueBuildRate * hrElevation; + hrFatigue += hrElevation > 0.05 + ? hrFatigueBuildRate * dt + : -(hrFatigue / LogicSettings.CardioFatigueRecoveryTau) * dt; + hrFatigue = Clamp(hrFatigue, 0.0, 1.0); + + // fatigueHeartRateFloor is a fixed setting: the resting HR offset the cardiovascular + // system is stuck at once fully fatigued (independent of feedback). + // Baroreceptor target from current perfusion deficit. + double baroTarget = 1.0 + (LogicSettings.BaroreceptorGain * Math.Max(0, 1.0 - perfusionRatio)); + baroTarget = Math.Min(baroTarget, LogicSettings.MaxHeartRateMultiplier); + + // hrFatigue suppresses baroreceptor response: at hrFatigue=1 the target is pinned to the floor. + double targetHR = baroTarget + (hrFatigue * (fatigueHeartRateFloor - baroTarget)); double hrTau = LogicSettings.BaroreceptorTimeConstant; heartRateMultiplier = StepTowardsLinear(heartRateMultiplier, targetHR, hrTau, dt); @@ -258,15 +321,15 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. primaryColor = bloodHead <= LogicSettings.RestingBloodHead; // Map brain O2 to consciousness via smooth step - double o2Normalized = Math.Clamp( + double o2Normalized = Clamp( (BrainO2 - LogicSettings.BrainO2Blackout) / (LogicSettings.BrainO2Full - LogicSettings.BrainO2Blackout), 0.0, 1.0); - double perfRatio = Math.Clamp(bloodHead / LogicSettings.RestingBloodHead, 0.0, 1.0); + double perfRatio = Clamp(bloodHead / LogicSettings.RestingBloodHead, 0.0, 1.0); perfusionLevel = perfRatio; // Use soft minimum for consciousness mapping (not blackout threshold) - double perfNorm = Math.Clamp( + double perfNorm = Clamp( (perfRatio - LogicSettings.ConsciousnessPerfusionSoftMinRatio) / (1.0 - LogicSettings.ConsciousnessPerfusionSoftMinRatio), 0.0, 1.0); @@ -297,10 +360,10 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. ((LogicSettings.ConsciousnessLossTauMin - LogicSettings.ConsciousnessLossTauMax) * lossSeverity); // Critical collapse accelerator (mostly affects extreme +G) - double criticalPerf = 1.0 - Math.Clamp( + double criticalPerf = 1.0 - Clamp( perfNorm / LogicSettings.ConsciousnessCriticalPerfusionNorm, 0.0, 1.0); - double criticalO2 = 1.0 - Math.Clamp( + double criticalO2 = 1.0 - Clamp( o2Normalized / LogicSettings.ConsciousnessCriticalO2Norm, 0.0, 1.0); double critical = Math.Max(criticalPerf, criticalO2); @@ -311,25 +374,25 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. double tau = targetConsciousness < consciousnessLevel ? lossTau : LogicSettings.ConsciousnessRecoveryTau; consciousnessLevel = StepTowardsLinear(consciousnessLevel, targetConsciousness, tau, dt); - consciousnessLevel = Math.Clamp(consciousnessLevel, 0.0, 1.0); + consciousnessLevel = Clamp(consciousnessLevel, 0.0, 1.0); // Visual symptoms should start from physiology, but once consciousness is collapsing // they should continue toward full obscuration even if perfusion briefly rebounds. - double visualPerf = Math.Clamp((perfRatio - 0.45) / 0.55, 0.0, 1.0); - double visualO2 = Math.Clamp((o2Normalized - 0.15) / 0.85, 0.0, 1.0); + double visualPerf = Clamp((perfRatio - 0.45) / 0.55, 0.0, 1.0); + double visualO2 = Clamp((o2Normalized - 0.15) / 0.85, 0.0, 1.0); // Fast visual reserve from physiology. double visualReserve = (0.7 * visualPerf) + (0.3 * visualO2); double visualDeficit = 1.0 - visualReserve; - // Early/mid visual impairment path. + // Early/mid-visual impairment path. // Keeps onset before LOC, but avoids saturating too early. - double physiologicalTunnelTarget = Math.Clamp((visualDeficit - 0.18) / 0.82, 0.0, 1.0); + double physiologicalTunnelTarget = Clamp((visualDeficit - 0.18) / 0.82, 0.0, 1.0); physiologicalTunnelTarget = Math.Pow(physiologicalTunnelTarget, 2.2); // Blackout path: if consciousness gets close to zero, tunnel vision must approach 1. // This also reduces sensitivity to short perfusion recoveries. - double blackoutTunnelTarget = Math.Clamp(1.0 - consciousnessLevel, 0.0, 1.0); + double blackoutTunnelTarget = Clamp(1.0 - consciousnessLevel, 0.0, 1.0); blackoutTunnelTarget = Math.Pow(blackoutTunnelTarget, 2); // Use whichever impairment is worse. @@ -347,11 +410,11 @@ public virtual void Update(double dt, double gz, double gx = 0.0, double gy = 0. tunnelVisionLevel = StepTowardsLinear(tunnelVisionLevel, tunnelTarget, tunnelTau, dt); greyScaleLevel = StepTowardsLinear(greyScaleLevel, greyTarget, greyTau, dt); - tunnelVisionLevel = Math.Clamp(tunnelVisionLevel, 0.0, 1.0); - greyScaleLevel = Math.Clamp(greyScaleLevel, 0.0, 1.0); + tunnelVisionLevel = Clamp(tunnelVisionLevel, 0.0, 1.0); + greyScaleLevel = Clamp(greyScaleLevel, 0.0, 1.0); // Hard guarantee: only enforce near total visual loss when consciousness is very close to zero. - double nearLoc = Math.Clamp((0.12 - consciousnessLevel) / 0.12, 0.0, 1.0); + double nearLoc = Clamp((0.12 - consciousnessLevel) / 0.12, 0.0, 1.0); double tunnelFloorFromConsciousness = SmoothStep(nearLoc); tunnelVisionLevel = Math.Max(tunnelVisionLevel, tunnelFloorFromConsciousness); diff --git a/GraphicLogicTest/GraphicLogicTest.csproj b/GraphicLogicTest/GraphicLogicTest.csproj index c30ab76..2c3c8ea 100644 --- a/GraphicLogicTest/GraphicLogicTest.csproj +++ b/GraphicLogicTest/GraphicLogicTest.csproj @@ -21,4 +21,15 @@ + + + SimulationView.axaml + Code + + + SecondaryView.axaml + Code + + + diff --git a/GraphicLogicTest/MainWindow.axaml b/GraphicLogicTest/MainWindow.axaml index 942814b..2e9d8b0 100644 --- a/GraphicLogicTest/MainWindow.axaml +++ b/GraphicLogicTest/MainWindow.axaml @@ -1,210 +1,40 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -