go-by-test/clockface/clockface.go

70 lines
1.7 KiB
Go
Raw Normal View History

2024-09-23 14:49:29 +00:00
package clockface
import (
2024-09-23 15:24:40 +00:00
"fmt"
"io"
2024-09-23 14:49:29 +00:00
"math"
"time"
)
// Point represents a two-dimentional Cartesian coordinate
type Point struct {
X float64
Y float64
}
2024-09-23 15:24:40 +00:00
const (
secondHandLength = 90
clockCentreX = 150
clockCentreY = 150
)
const svgStart = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="100%"
height="100%"
viewBox="0 0 300 300"
version="2.0">`
const bezel = `<circle cx="150" cy="150" r="100" style="fill:#fff;stroke:#000;stroke-width:5px;"/>`
const svgEnd = `</svg>`
func SVGWriter(w io.Writer, t time.Time) {
io.WriteString(w, svgStart)
io.WriteString(w, bezel)
SecondHand(w, t)
io.WriteString(w, svgEnd)
}
2024-09-23 14:49:29 +00:00
// SecondHand is the unit vector of the second hand of an analogue clock at the time `t` represented as a Point
2024-09-23 15:24:40 +00:00
func SecondHand(w io.Writer, t time.Time) {
2024-09-23 14:49:29 +00:00
p := secondHandPoint(t)
2024-09-23 15:24:40 +00:00
p = Point{p.X * secondHandLength, p.Y * secondHandLength} // scale
p = Point{p.X, -p.Y} // flip
p = Point{p.X + clockCentreX, p.Y + clockCentreY} // translate
fmt.Fprintf(
w,
`<line x1="150" y1="150" x2="%f" y2="%f" style="fill:none;stroke:#f00;stroke-width:3px;"/>`,
p.X,
p.Y,
)
2024-09-23 14:49:29 +00:00
}
func secondsInRadians(t time.Time) float64 {
// XXX:Wanted 3.141592653589793 radians, but got 3.1415926535897936
// return float64(t.Second()) * (math.Pi / 30)
return math.Pi / (30 / float64(t.Second()))
}
func secondHandPoint(t time.Time) Point {
angle := secondsInRadians(t)
x := math.Sin(angle)
y := math.Cos(angle)
// XXX: Wanted {0 -1} Point, but got {1.2246467991473515e-16 -1}
return Point{x, y}
}