File size: 24,136 Bytes
a8ced59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
classdef RC_SRP_Calculator < handle
    % This application provides a modern, peach-themed interface
    % to calculate singly reinforced sections step-by-step.
    % We avoid heavy plots and focus purely on real-time equation updates.
    
    properties
        % Window and main grid
        UIFigure
        GridLayout
        
        % The three main sections
        LeftPanel       % Sidebar for configurable settings
        CenterPanel     % Main panel for step-by-step equations
        RightPanel      % Right sidebar for our activity log
        
        % Left Panel Inputs (using f(c)', f(y), A(s) etc. for UI labels)
        ModeDropdown
        TitleFc, FieldFc
        TitleFy, FieldFy
        TitleB, FieldB
        TitleH, FieldH
        TitleBars, FieldBars
        TitleArea, FieldArea
        TitleCover, FieldCover
        
        % Extra Inputs for Double Layer
        TitleBars2, FieldBars2
        TitleArea2, FieldArea2
        TitleSpacing, FieldSpacing
        
        % Center Panel Output
        EquationHTML
        
        % Right Panel Output
        LogTextArea
        
        % Keep track of our log messages
        LogHistory = {}
    end
    
    methods (Access = public)
        % Constructor. This runs when we launch the calculator.
        function app = RC_SRP_Calculator()
            app.createApp();
            app.addLog('Calculator app initialized! Welcome.');
            app.updateEquations(); % trigger first calculation
        end
        
        % Clean up when the app is nicely closed
        function delete(app)
            if isvalid(app.UIFigure)
                delete(app.UIFigure);
            end
        end
    end
    
    methods (Access = private)
        % Let's build our user interface step-by-step
        function createApp(app)
            % Define our peach color palette (very warm, minimalistic aesthetic)
            peachBase  = [1.00, 0.89, 0.80];  % Main background
            peachDark  = [0.95, 0.76, 0.65];  % Panels
            peachLight = [1.00, 0.95, 0.90];  % Highlights
            peachText  = [0.20, 0.20, 0.20];  % Text color for readability
            
            % Setup the main application window
            app.UIFigure = uifigure('Name', 'RC-SRP Calculator', 'Position', [100, 100, 1200, 750]);
            app.UIFigure.Color = peachBase;
            
            % Setup a 3-column layout
            app.GridLayout = uigridlayout(app.UIFigure);
            app.GridLayout.ColumnWidth = {300, '1x', 280}; 
            app.GridLayout.RowHeight = {'1x'};
            app.GridLayout.BackgroundColor = peachBase;
            
            % --- 1. LEFT SIDEBAR: Configurable Settings ---
            app.LeftPanel = uipanel(app.GridLayout);
            app.LeftPanel.Layout.Row = 1;
            app.LeftPanel.Layout.Column = 1;
            app.LeftPanel.BackgroundColor = peachDark;
            app.LeftPanel.Title = 'Configurable Settings';
            app.LeftPanel.ForegroundColor = peachText;
            app.LeftPanel.FontWeight = 'bold';
            
            % Grid inside the left panel to align our inputs beautifully
            leftGrid = uigridlayout(app.LeftPanel);
            leftGrid.ColumnWidth = {'1x', '1x'};
            leftGrid.RowHeight = repmat({32}, 1, 15); % 15 rows of 32px height
            leftGrid.BackgroundColor = peachDark;
            
            % Calculation mode dropdown
            uilabel(leftGrid, 'Text', 'Mode:', 'FontWeight', 'bold', 'FontColor', peachText);
            app.ModeDropdown = uidropdown(leftGrid, ...
                'Items', {'Singly Reinforced', 'Single Layer', 'Double Layer'}, ...
                'ValueChangedFcn', @(src, event) app.onInputChanged(), ...
                'FontColor', peachText, 'BackgroundColor', peachLight);
                
            % f(c)' input (concrete compressive strength)
            app.TitleFc = uilabel(leftGrid, 'Text', 'f(c)'' (psi):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldFc = uieditfield(leftGrid, 'numeric', 'Value', 4000, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % f(y) input (steel yield strength)
            app.TitleFy = uilabel(leftGrid, 'Text', 'f(y) (psi):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldFy = uieditfield(leftGrid, 'numeric', 'Value', 60000, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % Beam width
            app.TitleB = uilabel(leftGrid, 'Text', 'b (in):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldB = uieditfield(leftGrid, 'numeric', 'Value', 12, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % Beam height
            app.TitleH = uilabel(leftGrid, 'Text', 'h (in):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldH = uieditfield(leftGrid, 'numeric', 'Value', 20, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % Bars configuration
            app.TitleBars = uilabel(leftGrid, 'Text', 'Number of Bars:', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldBars = uieditfield(leftGrid, 'numeric', 'Value', 4, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            app.TitleArea = uilabel(leftGrid, 'Text', 'Area per A(s):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldArea = uieditfield(leftGrid, 'numeric', 'Value', 0.79, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            app.TitleCover = uilabel(leftGrid, 'Text', 'Cover (in):', 'FontColor', peachText, 'FontWeight', 'bold');
            app.FieldCover = uieditfield(leftGrid, 'numeric', 'Value', 2.5, 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % Double layer specific fields (hidden by default)
            app.TitleBars2 = uilabel(leftGrid, 'Text', 'L2 Bars:', 'FontColor', peachText, 'Visible', 'off');
            app.FieldBars2 = uieditfield(leftGrid, 'numeric', 'Value', 2, 'Visible', 'off', 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            app.TitleArea2 = uilabel(leftGrid, 'Text', 'L2 Area A(s):', 'FontColor', peachText, 'Visible', 'off');
            app.FieldArea2 = uieditfield(leftGrid, 'numeric', 'Value', 1.00, 'Visible', 'off', 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            app.TitleSpacing = uilabel(leftGrid, 'Text', 'Spacing (in):', 'FontColor', peachText, 'Visible', 'off');
            app.FieldSpacing = uieditfield(leftGrid, 'numeric', 'Value', 2.13, 'Visible', 'off', 'ValueChangedFcn', @(src, event) app.onInputChanged());
            
            % --- 2. CENTER PANEL: Step-by-Step Equations ---
            app.CenterPanel = uipanel(app.GridLayout);
            app.CenterPanel.Layout.Row = 1;
            app.CenterPanel.Layout.Column = 2;
            app.CenterPanel.BackgroundColor = peachLight;
            app.CenterPanel.Title = 'Formula & Equations';
            app.CenterPanel.ForegroundColor = peachText;
            app.CenterPanel.FontWeight = 'bold';
            
            % We use an HTML view to render nice Math/LaTeX-like output with CSS animations
            centerGrid = uigridlayout(app.CenterPanel);
            centerGrid.ColumnWidth = {'1x'};
            centerGrid.RowHeight = {'1x'};
            
            app.EquationHTML = uihtml(centerGrid);
            
            % --- 3. RIGHT SIDEBAR: Activity Log ---
            app.RightPanel = uipanel(app.GridLayout);
            app.RightPanel.Layout.Row = 1;
            app.RightPanel.Layout.Column = 3;
            app.RightPanel.BackgroundColor = peachDark;
            app.RightPanel.Title = 'Log & Summary';
            app.RightPanel.ForegroundColor = peachText;
            app.RightPanel.FontWeight = 'bold';
            
            rightGrid = uigridlayout(app.RightPanel);
            rightGrid.ColumnWidth = {'1x'};
            rightGrid.RowHeight = {'1x'};
            
            app.LogTextArea = uitextarea(rightGrid);
            app.LogTextArea.Editable = 'off';
            app.LogTextArea.BackgroundColor = peachLight;
            app.LogTextArea.FontColor = peachText;
            app.LogTextArea.FontName = 'Courier New';
        end
        
        % Whenever the user touches a variable, we update instantly
        function onInputChanged(app)
            % Gently check if we need to show Double Layer inputs
            if strcmp(app.ModeDropdown.Value, 'Double Layer')
                app.TitleBars2.Visible = 'on'; app.FieldBars2.Visible = 'on';
                app.TitleArea2.Visible = 'on'; app.FieldArea2.Visible = 'on';
                app.TitleSpacing.Visible = 'on'; app.FieldSpacing.Visible = 'on';
            else
                app.TitleBars2.Visible = 'off'; app.FieldBars2.Visible = 'off';
                app.TitleArea2.Visible = 'off'; app.FieldArea2.Visible = 'off';
                app.TitleSpacing.Visible = 'off'; app.FieldSpacing.Visible = 'off';
            end
            
            app.addLog('Settings modified, recalculating formulas...');
            app.updateEquations();
        end
        
        % This is the core logic where all the math happens, gracefully formatting results
        function updateEquations(app)
            % 1. Grab variables from the visual fields
            fc = app.FieldFc.Value;
            fy = app.FieldFy.Value;
            b  = app.FieldB.Value;
            h  = app.FieldH.Value;
            n_bars = app.FieldBars.Value;
            a_bar  = app.FieldArea.Value;
            cover  = app.FieldCover.Value;
            mode   = app.ModeDropdown.Value;
            
            % Convert stress to ksi for smaller, readable numbers
            fc_ksi = fc / 1000;
            fy_ksi = fy / 1000;
            Es_ksi = 29000;
            E_cu   = 0.003; % standard concrete strain parameter
            
            % 2. Setup our HTML framework with a lovely peach CSS style and transition animations
            html = [ ...
                '<html><head><style>' ...
                'body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; ' ...
                'color: #4A3B32; background-color: #FFF2E6; padding: 20px; line-height: 1.6; } ' ...
                'h2 { color: #D35400; border-bottom: 2px solid #FAD7A1; padding-bottom: 5px; } ' ...
                'h3 { color: #E67E22; margin-top: 25px; } ' ...
                '@keyframes popup { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: translateY(0); } } ' ...
                '.equation { background-color: #FFE6CC; padding: 15px; border-radius: 12px; ' ...
                'margin: 12px 0; font-family: "Courier New", Courier, monospace; font-weight: bold; ' ...
                'box-shadow: 0 4px 6px rgba(0,0,0,0.06); animation: popup 0.4s ease-out; } ' ...
                '.highlight { color: #C0392B; font-size: 1.1em; } ' ...
                '.success { color: #27AE60; font-weight: bold; } ' ...
                '.danger { color: #E74C3C; font-weight: bold; } ' ...
                '</style></head><body>' ...
            ];
            
            html = [html, '<h2>Analysis Mode: ', mode, '</h2>'];
            html = [html, '<h3>Given Variables</h3>'];
            html = [html, '<div class="equation">', ...
                                'f_c'' = ', num2str(fc), ' psi &nbsp;&nbsp;&nbsp; f_y = ', num2str(fy), ' psi<br>', ...
                                'b = ', num2str(b), ' in &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; h = ', num2str(h), ' in<br>', ...
                                'Bars = ', num2str(n_bars), ' (A_b = ', num2str(a_bar), ' in&sup2;)<br>', ...
                                'Cover = ', num2str(cover), ' in</div>'];
            
            % 3. Common mathematical terms
            % Beta_1 decreases gently for higher strength concrete
            beta1 = 0.85;
            if fc > 4000
                beta1 = 0.85 - 0.05 * ((fc - 4000) / 1000);
            end
            beta1 = max(beta1, 0.65); % Never drops below this rule
            
            % Steel minimum base requirement
            limit_val = 3 * sqrt(fc);
            As_min_factor = max(limit_val, 200); % chooses the dominating rule automatically
            
            % 4. Logic splits neatly based on chosen calculation mode
            if strcmp(mode, 'Singly Reinforced') || strcmp(mode, 'Single Layer')
                % Simple straightforward geometry
                d = h - cover;
                html = [html, '<h3>1. Solve Effective Depth (d)</h3>'];
                html = [html, '<div class="equation">d = h - cover<br>', ...
                              '= ', num2str(h), ' - ', num2str(cover), '<br>', ...
                              '= <span class="highlight">', num2str(d), ' in</span></div>'];
                
                As = n_bars * a_bar;
                html = [html, '<h3>2. Solve Steel Area (A_s)</h3>'];
                html = [html, '<div class="equation">A_s = bars &times; a_bar<br>', ...
                              '= ', num2str(n_bars), ' &times; ', num2str(a_bar), '<br>', ...
                              '= <span class="highlight">', num2str(As), ' in&sup2;</span></div>'];
                
                % Standard assumption: the steel is already yielding
                T = As * fy_ksi;
                html = [html, '<h3>3. Assume steel yields (T = A_s &middot; f_y)</h3>'];
                html = [html, '<div class="equation">T = ', num2str(As), ' &times; ', num2str(fy_ksi), ' ksi<br>', ...
                              '= <span class="highlight">', num2str(T), ' kips</span></div>'];
                
                % Concrete compression block depth
                a = T / (0.85 * fc_ksi * b);
                html = [html, '<h3>4. Solve Compression Block (a &amp; c)</h3>'];
                html = [html, 'By matching concrete volume force to tension:<br>'];
                html = [html, '<div class="equation">a = T / (0.85 &middot; f_c'' &middot; b)<br>', ...
                              '= <span class="highlight">', num2str(a, '%.2f'), ' in</span></div>'];
                                    
                c = a / beta1;
                html = [html, '<div class="equation">c = a / &beta;&sub1; = ', num2str(a, '%.2f'), ' / ', num2str(beta1, '%.2f'), '<br>', ...
                              '= <span class="highlight">', num2str(c, '%.2f'), ' in</span></div>'];
                                    
                % Strain compatibility check
                eps_y = fy_ksi / Es_ksi;
                eps_s = ((d - c) / c) * E_cu;
                html = [html, '<h3>5. Strain Compatibility Check (&epsilon;_s &ge; &epsilon;_y)</h3>'];
                html = [html, '<div class="equation">&epsilon;_y = f_y / E_s = ', num2str(eps_y, '%.5f'), '<br>', ...
                              '&epsilon;_s = ((d - c) / c) &middot; &epsilon;_cu<br>', ...
                              '= <span class="highlight">', num2str(eps_s, '%.5f'), '</span></div>'];
                                    
                if eps_s >= eps_y
                    html = [html, '<p class="success">Tension steel yielded. Assumption confirmed gracefully.</p>'];
                else
                    html = [html, '<p class="danger">Assumption failed! Steel did not yield.</p>'];
                end
                
                % Calculate the raw moment capacity
                Mn = T * (d - a/2) / 12;
                html = [html, '<h3>6. Nominal Moment (M_n)</h3>'];
                html = [html, '<div class="equation">M_n = T &middot; (d - a/2) / 12<br>', ...
                              '= <span class="highlight">', num2str(Mn, '%.2f'), ' kip-ft</span></div>'];
                                    
                % Checking code requirements for minimum reinforcements
                As_min = (As_min_factor / fy) * b * d;
                html = [html, '<h3>7. Check Minimum Code Rules</h3>'];
                html = [html, '<div class="equation">A_s,min = (', num2str(As_min_factor), ' / f_y) &middot; b &middot; d<br>', ...
                              '= <span class="highlight">', num2str(As_min, '%.2f'), ' in&sup2;</span></div>'];
                if As >= As_min
                    html = [html, '<p class="success">A_s exceeds minimum rules. Wonderful.</p>'];
                else
                    html = [html, '<p class="danger">A_s falls short of required minimum!</p>'];
                end
                
                % Extra steps for single layer reduction factor calculation
                if strcmp(mode, 'Single Layer')
                    eps_t = eps_s; 
                    if eps_t >= 0.005
                        phi = 0.90;
                    elseif eps_t <= 0.002
                        phi = 0.65;
                    else
                        phi = 0.65 + (eps_t - 0.002) * (250/3);
                    end
                    phi_Mn = phi * Mn;
                    
                    html = [html, '<h3>8. Strength Reduction Factor (&phi;)</h3>'];
                    html = [html, '<div class="equation">&epsilon;_t = ', num2str(eps_t, '%.5f'), '<br>', ...
                                  '&phi; = <span class="highlight">', num2str(phi, '%.2f'), '</span></div>'];
                                        
                    html = [html, '<h3>9. Designed Maximum Moment (&phi;M_n)</h3>'];
                    html = [html, '<div class="equation">&phi;M_n = ', num2str(phi, '%.2f'), ' &times; ', num2str(Mn, '%.2f'), '<br>', ...
                                  '= <span class="highlight">', num2str(phi_Mn, '%.2f'), ' kip-ft</span></div>'];
                end
                
            elseif strcmp(mode, 'Double Layer')
                % --- Advanced Multiple Layers processing ---
                n_bars2 = app.FieldBars2.Value;
                a_bar2  = app.FieldArea2.Value;
                spacing = app.FieldSpacing.Value;
                
                % Centroid gymnastics for double layers
                As1 = n_bars * a_bar;
                As2 = n_bars2 * a_bar2;
                As = As1 + As2;
                
                dist1 = cover; 
                dist2 = cover + spacing;
                
                g = (As1 * dist1 + As2 * dist2) / As;
                d = h - g;
                d_t = h - cover; 
                
                html = [html, '<h3>1. Resolve the Steel Centroids</h3>'];
                html = [html, '<div class="equation">g = (A_s1 &middot; y1 + A_s2 &middot; y2) / A_s<br>', ...
                              '= (', num2str(As1), ' &times; ', num2str(dist1), ' + ', num2str(As2), ' &times; ', num2str(dist2), ') / ', num2str(As), '<br>', ...
                              '= ', num2str(g, '%.2f'), ' in</div>'];
                                    
                html = [html, '<div class="equation">d = h - g = ', num2str(h), ' - ', num2str(g, '%.2f'), '<br>', ...
                              '= <span class="highlight">', num2str(d, '%.2f'), ' in</span></div>'];
                
                % Assume Yield again
                T = As * fy_ksi;
                a = T / (0.85 * fc_ksi * b);
                c = a / beta1;
                
                html = [html, '<h3>2. Solve Basic Block (Assuming Yield)</h3>'];
                html = [html, '<div class="equation">T = ', num2str(T, '%.2f'), ' kips<br>', ...
                              'a = ', num2str(a, '%.2f'), ' in<br>', ...
                              'c = <span class="highlight">', num2str(c, '%.2f'), ' in</span></div>'];
                                    
                eps_y = fy_ksi / Es_ksi;
                eps_s = ((d - c) / c) * E_cu;
                
                html = [html, '<h3>3. Verify the Yield Strain</h3>'];
                html = [html, '<div class="equation">&epsilon;_s = ', num2str(eps_s, '%.5f'), ' | &epsilon;_y = ', num2str(eps_y, '%.5f'), '</div>'];
                                    
                % More complex quadratic solving requested for over-reinforced double layers
                if eps_s < eps_y
                    html = [html, '<p class="danger">Assumption Failed! Solving via Quadratic Exact Match...</p>'];
                    
                    A_quad = 0.85 * fc_ksi * b * beta1;
                    B_quad = As * Es_ksi * E_cu;
                    C_quad = -1 * As * Es_ksi * E_cu * d;
                    
                    % Find actual real root
                    roots_c = roots([A_quad, B_quad, C_quad]);
                    c_new = max(roots_c(roots_c > 0));
                    a_new = beta1 * c_new;
                    
                    html = [html, '<div class="equation">Quadratic Form Evaluated for c:<br>', ...
                                  'c = <span class="highlight">', num2str(c_new, '%.2f'), ' in</span><br>', ...
                                  'a = <span class="highlight">', num2str(a_new, '%.2f'), ' in</span></div>'];
                                        
                    c = c_new;
                    a = a_new;
                    
                    % Recalculate accurately
                    T = As * Es_ksi * ((d - c)/c) * E_cu;
                    html = [html, '<div class="equation">Accurate Balance Tension T = C_c = <span class="highlight">', num2str(T, '%.2f'), ' kips</span></div>'];
                else
                    html = [html, '<p class="success">Assumption smoothly verified.</p>'];
                end
                
                % Compute derived raw moment
                Mn = T * (d - a/2) / 12;
                html = [html, '<h3>4. Base Moment Geometry (M_n)</h3>'];
                html = [html, '<div class="equation">M_n = T &middot; (d - a/2) / 12<br>', ...
                              '= <span class="highlight">', num2str(Mn, '%.2f'), ' kip-ft</span></div>'];
                                    
                % For double layers, compute reduction on the most extreme layer strain
                eps_t = ((d_t - c) / c) * E_cu;
                if eps_t >= 0.005
                    phi = 0.90;
                elseif eps_t <= 0.002
                    phi = 0.65;
                else
                    phi = 0.65 + (eps_t - 0.002) * (250/3);
                end
                
                html = [html, '<h3>5. Reduction Factor for Design Result</h3>'];
                html = [html, '<div class="equation">&epsilon;_t (extreme) = ', num2str(eps_t, '%.5f'), '<br>', ...
                              '&phi; = ', num2str(phi, '%.2f'), '<br>', ...
                              '&phi;M_n = <span class="highlight">', num2str(phi*Mn, '%.2f'), ' kip-ft</span></div>'];
            end
            
            % Close and assign to the beautiful HTML widget
            html = [html, '</body></html>'];
            app.EquationHTML.HTMLSource = html;
            
            % Add to our active log so we have a trace
            app.addLog(sprintf('Computed [%s] cleanly. End M_n: %.2f k-ft.', mode, Mn));
        end
        
        % This simple helper lets us comfortably add logs with timestamps
        function addLog(app, msg)
            timestamp = datestr(now, 'HH:MM:SS');
            logEntry = sprintf('[%s] %s', timestamp, msg);
            app.LogHistory = [app.LogHistory; {logEntry}];
            
            % Keep logs fairly recent to keep memory efficient
            if length(app.LogHistory) > 40
                app.LogHistory(1) = [];
            end
            
            app.LogTextArea.Value = app.LogHistory;
        end
        
    end
end