mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-09-04 00:17:37 +00:00
feat(misc): rotate wheel beta labels
This commit is contained in:
@@ -386,13 +386,32 @@ func TestWheelOfNamesBeta_DrawsOptionLabelsInsideSlices(t *testing.T) {
|
||||
segment := 2 * math.Pi / float64(len(options))
|
||||
angle := rotation + segment/2
|
||||
centerX := wheelBetaSize/2 + int(math.Round(math.Cos(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
baselineY := wheelBetaSize/2 + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius))) + wheelBetaSliceLabelBaselineOffset
|
||||
bounds := image.Rect(centerX-28, baselineY-14, centerX+28, baselineY+2)
|
||||
centerY := wheelBetaSize/2 + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
bounds := image.Rect(centerX-28, centerY-28, centerX+28, centerY+28)
|
||||
if got := countColorIndex(img, bounds, 1); got == 0 {
|
||||
t.Fatalf("slice label dark pixels = %d, want > 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWheelOfNamesBeta_RotatesOptionLabelsWithSlices(t *testing.T) {
|
||||
options := []string{"Rotate", "Teacher", "Parent", "Staff"}
|
||||
rotation := -3 * math.Pi / 4
|
||||
img := renderWheelBetaFrame(options, 0, rotation, false)
|
||||
|
||||
segment := 2 * math.Pi / float64(len(options))
|
||||
angle := rotation + segment/2
|
||||
centerX := wheelBetaSize/2 + int(math.Round(math.Cos(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
centerY := wheelBetaSize/2 + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
searchBounds := image.Rect(centerX-28, centerY-32, centerX+28, centerY+32)
|
||||
labelBounds, ok := colorIndexBounds(img, searchBounds, wheelBetaInkColorIndex)
|
||||
if !ok {
|
||||
t.Fatalf("slice label dark pixels missing in %v", searchBounds)
|
||||
}
|
||||
if labelBounds.Dy() <= labelBounds.Dx() {
|
||||
t.Fatalf("slice label bounds = %v, want taller than wide for rotated label", labelBounds)
|
||||
}
|
||||
}
|
||||
|
||||
func countColorIndex(img *image.Paletted, bounds image.Rectangle, colorIndex byte) int {
|
||||
bounds = bounds.Intersect(img.Bounds())
|
||||
count := 0
|
||||
@@ -406,6 +425,37 @@ func countColorIndex(img *image.Paletted, bounds image.Rectangle, colorIndex byt
|
||||
return count
|
||||
}
|
||||
|
||||
func colorIndexBounds(img *image.Paletted, bounds image.Rectangle, colorIndex byte) (image.Rectangle, bool) {
|
||||
bounds = bounds.Intersect(img.Bounds())
|
||||
minX, minY := bounds.Max.X, bounds.Max.Y
|
||||
maxX, maxY := bounds.Min.X, bounds.Min.Y
|
||||
found := false
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
if img.ColorIndexAt(x, y) != colorIndex {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
if x < minX {
|
||||
minX = x
|
||||
}
|
||||
if y < minY {
|
||||
minY = y
|
||||
}
|
||||
if x+1 > maxX {
|
||||
maxX = x + 1
|
||||
}
|
||||
if y+1 > maxY {
|
||||
maxY = y + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return image.Rectangle{}, false
|
||||
}
|
||||
return image.Rect(minX, minY, maxX, maxY), true
|
||||
}
|
||||
|
||||
func TestWheelOfNamesBeta_SendsAnimationWithoutSpoilingCaption(t *testing.T) {
|
||||
rb, _ := installMisc(t, 999)
|
||||
rb.Bot.ProcessUpdate(context.Background(), testutil.NewPrivateMessage(7, "/wheelofnamesbeta Alice"))
|
||||
|
||||
@@ -2,6 +2,7 @@ package misc
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
@@ -11,8 +12,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
wheelBetaSliceLabelRadius = 64
|
||||
wheelBetaSliceLabelBaselineOffset = 5
|
||||
wheelBetaSliceLabelRadius = 64
|
||||
)
|
||||
|
||||
func drawWheelSliceLabels(img *image.Paletted, options []string, rotation float64) {
|
||||
@@ -25,10 +25,10 @@ func drawWheelSliceLabels(img *image.Paletted, options []string, rotation float6
|
||||
for idx, option := range options {
|
||||
angle := rotation + (float64(idx)+0.5)*segment
|
||||
centerX := cx + int(math.Round(math.Cos(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
baselineY := cy + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius))) + wheelBetaSliceLabelBaselineOffset
|
||||
centerY := cy + int(math.Round(math.Sin(angle)*float64(wheelBetaSliceLabelRadius)))
|
||||
text := asciiWheelText(option, limit)
|
||||
drawCenteredTextAt(img, text, centerX+1, baselineY+1, 2)
|
||||
drawCenteredTextAt(img, text, centerX, baselineY, 1)
|
||||
drawRotatedCenteredTextAt(img, text, centerX+1, centerY+1, angle, wheelBetaPaperColorIndex)
|
||||
drawRotatedCenteredTextAt(img, text, centerX, centerY, angle, wheelBetaInkColorIndex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +215,38 @@ func drawCenteredTextAt(img *image.Paletted, text string, centerX, baselineY int
|
||||
drawer.DrawString(text)
|
||||
}
|
||||
|
||||
func drawRotatedCenteredTextAt(img *image.Paletted, text string, centerX, centerY int, angle float64, colorIndex byte) {
|
||||
face := basicfont.Face7x13
|
||||
padding := 2
|
||||
metrics := face.Metrics()
|
||||
textWidth := font.MeasureString(face, text).Ceil()
|
||||
textHeight := metrics.Height.Ceil()
|
||||
mask := image.NewAlpha(image.Rect(0, 0, textWidth+padding*2, textHeight+padding*2))
|
||||
drawer := font.Drawer{
|
||||
Dst: mask,
|
||||
Src: image.NewUniform(color.Alpha{A: 255}),
|
||||
Face: face,
|
||||
Dot: fixed.P(padding, padding+metrics.Ascent.Ceil()),
|
||||
}
|
||||
drawer.DrawString(text)
|
||||
|
||||
sourceCenterX := float64(mask.Bounds().Dx()-1) / 2
|
||||
sourceCenterY := float64(mask.Bounds().Dy()-1) / 2
|
||||
sin, cos := math.Sin(angle), math.Cos(angle)
|
||||
for y := mask.Bounds().Min.Y; y < mask.Bounds().Max.Y; y++ {
|
||||
for x := mask.Bounds().Min.X; x < mask.Bounds().Max.X; x++ {
|
||||
if mask.AlphaAt(x, y).A == 0 {
|
||||
continue
|
||||
}
|
||||
localX := float64(x) - sourceCenterX
|
||||
localY := float64(y) - sourceCenterY
|
||||
targetX := centerX + int(math.Round(localX*cos-localY*sin))
|
||||
targetY := centerY + int(math.Round(localX*sin+localY*cos))
|
||||
setWheelBetaPixel(img, targetX, targetY, colorIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func asciiWheelText(s string, limit int) string {
|
||||
var b strings.Builder
|
||||
for _, r := range s {
|
||||
|
||||
Reference in New Issue
Block a user