📐 Button-to-Wedge Mapping: Visual Explanation

🎯 Problem Statement

Given a circular pie chart divided into colored wedges, we want to overlay a grid of buttons and determine which color each button should display based on which wedge it overlaps the most.

Input: Pie Chart

Circle with radius r divided into wedges

Output: Button Grid

N×M buttons colored by wedge overlap

📊 Key Parameters

Parameter Symbol Description Example
Circle Radius r Radius of the circular pie chart 200 pixels
Grid Rows N Number of button rows (vertical) 15
Grid Columns M Number of button columns (horizontal) 15
Button Width w Width of each button = 2r/M 26.7 px
Button Height h Height of each button = 2r/N 26.7 px
Sample Size S Sample points per button dimension 7 (49 total samples)
Threshold T Minimum overlap fraction for color assignment 0.5 (50%)
Angle Offset θ₀ Rotation of circle (0 = 3 o'clock) π/2 (12 o'clock)

🔢 Core Formulas

1 Button Position

For button at grid location (i, j):

x_min = j × (2r / M)
y_min = i × (2r / N)
x_max = (j+1) × (2r / M)
y_max = (i+1) × (2r / N)

Where i ∈ [0, N-1], j ∈ [0, M-1], and origin is at top-left of bounding box.

2 Sample Point Generation

For each sample index (si, sj) where si, sj ∈ [0, S-1]:

x_sample = x_min + (sj + 0.5) × (x_max - x_min) / S
y_sample = y_min + (si + 0.5) × (y_max - y_min) / S

Sample points at center of each sub-cell (shown as dots)

3 Point-in-Circle Test

Check if sample point is inside the circle:

dx = x_sample - r // Offset from center
dy = y_sample - r
distance = √(dx² + dy²)
inside = (distance ≤ r)
4 Angle Calculation

If inside circle, calculate angle from center:

θ_raw = atan2(dy, dx) // Range: [-π, π]

// Normalize to [0, 2π)
θ_norm = if θ_raw ≥ 0 then θ_raw else θ_raw + 2π

// Apply rotation offset
θ_final = (θ_norm + θ₀) mod 2π

Angle measurement with offset θ₀ = 90° (12 o'clock)

5 Wedge Membership Test

Determine which wedge contains this angle:

For each wedge k with (θ_start[k], θ_end[k]):
if θ_start[k] < θ_end[k]: // Normal case
match = θ_start[k] ≤ θ_final < θ_end[k]
else: // Wraparound case (crosses 0°)
match = θ_final ≥ θ_start[k] OR θ_final < θ_end[k]

if match:
wedge_count[k] += 1
6 Color Assignment

Assign button color based on wedge with maximum overlap:

total_inside = count(samples inside circle)
max_count = max(wedge_count[k] for all k)
overlap_fraction = max_count / total_inside

if total_inside = 0:
button_color = transparent // Outside circle
else if overlap_fraction ≥ T:
button_color = color[k] where wedge_count[k] = max_count
else:
button_color = transparent // No clear majority

📈 Example Calculation

Given:

Step-by-step:

1. Button bounds:
x_min = 7 × (400/15) = 186.67 px
y_min = 7 × (400/15) = 186.67 px
width = height = 26.67 px

2. Sample center point (s=3, middle sample):
x_sample = 186.67 + 3.5 × (26.67/7) = 200 px
y_sample = 186.67 + 3.5 × (26.67/7) = 200 px

3. Point-in-circle test:
dx = 200 - 200 = 0
dy = 200 - 200 = 0
distance = 0 ≤ 200 ✓ (inside)

4. Angle calculation:
θ_raw = atan2(0, 0) = undefined (center point)
Note: Center point touches ALL wedges equally

5. Result for all 49 samples:
Samples distributed across all 8 wedges (≈6 each)
max_count = 6, total_inside = 49
overlap_fraction = 6/49 ≈ 0.12 < 0.5

6. Color assignment:
button_color = transparent (no clear majority)

💡 Key Insights

🎨 Visual Legend

⚡ Power Apps Quick Reference

// Button color formula (paste into Fill property)
With({
btnW: 2 * circleRadius / gridM,
btnH: 2 * circleRadius / gridN,
xMin: j * 2 * circleRadius / gridM,
yMin: i * 2 * circleRadius / gridN
},
/* Use full formula from power_apps_ready_formula.txt */
)