Forge
csharpcf25d736
1namespace CascadeIDE.Services.Presentation;
2
3/// <summary>
4/// Единая нормализация долей зон (P/F/M) для одного экрана <c>presentation</c>.
5/// Источник истины для расчёта геометрии зон; UI-представления не должны пересчитывать доли локально.
6/// </summary>
7public static class PresentationZoneWeights
8{
9 private const double SumTolerance = 1e-9;
10
11 /// <summary>
12 /// Нормализованные доли зон для первого экрана (в порядке якорей в группе):
13 /// - без коэффициентов: равные доли;
14 /// - с коэффициентами: нормализация к сумме 1 (устойчиво к погрешности).
15 /// </summary>
16 public static bool TryGetFirstScreenWeights(
17 PresentationParseResult parse,
18 out IReadOnlyList<double> weights)
19 {
20 weights = Array.Empty<double>();
21 if (!parse.IsSuccess || parse.Screens.Count == 0)
22 return false;
23
24 return TryNormalize(parse.Screens[0], out weights);
25 }
26
27 /// <summary>Нормализовать доли в группе якорей одного экрана.</summary>
28 public static bool TryNormalize(
29 IReadOnlyList<PresentationAnchorSlot> screen,
30 out IReadOnlyList<double> weights)
31 {
32 weights = Array.Empty<double>();
33 if (screen.Count == 0)
34 return false;
35
36 // Один якорь => одна зона на экране.
37 if (screen.Count == 1)
38 {
39 weights = [1.0];
40 return true;
41 }
42
43 var any = false;
44 var all = true;
45 for (var i = 0; i < screen.Count; i++)
46 {
47 var has = screen[i].Weight.HasValue;
48 any |= has;
49 all &= has;
50 }
51
52 if (any && !all)
53 return false;
54
55 if (!any)
56 {
57 var equal = 1.0 / screen.Count;
58 var values = new double[screen.Count];
59 for (var i = 0; i < values.Length; i++)
60 values[i] = equal;
61 weights = values;
62 return true;
63 }
64
65 var sum = 0.0;
66 for (var i = 0; i < screen.Count; i++)
67 {
68 var v = screen[i].Weight!.Value;
69 if (v <= 0 || double.IsNaN(v) || double.IsInfinity(v))
70 return false;
71 sum += v;
72 }
73
74 if (sum <= 0 || double.IsNaN(sum) || double.IsInfinity(sum))
75 return false;
76
77 // При нормальной сумме ≈ 1 всё равно нормализуем, чтобы снять накопление погрешностей.
78 var normalized = new double[screen.Count];
79 for (var i = 0; i < screen.Count; i++)
80 normalized[i] = screen[i].Weight!.Value / sum;
81
82 // Защитный фикс хвоста: сумма ровно 1 в double-арифметике текущего кадра.
83 var tail = 0.0;
84 for (var i = 0; i < normalized.Length - 1; i++)
85 tail += normalized[i];
86 normalized[^1] = Math.Max(0, 1.0 - tail);
87
88 // Если хвост "съехал" из-за аномалии, откатываемся на обычную нормализацию.
89 var finalSum = 0.0;
90 for (var i = 0; i < normalized.Length; i++)
91 finalSum += normalized[i];
92 if (Math.Abs(finalSum - 1.0) > SumTolerance)
93 return false;
94
95 weights = normalized;
96 return true;
97 }
98}
99
100
View only · write via MCP/CIDE