clockface: add hours
This commit is contained in:
parent
c6ef156d88
commit
6837cd9fc1
@ -14,6 +14,7 @@ type Point struct {
|
||||
}
|
||||
|
||||
const (
|
||||
hourHandLength = 50
|
||||
minuteHandLength = 80
|
||||
secondHandLength = 90
|
||||
clockCentreX = 150
|
||||
@ -37,6 +38,7 @@ func SVGWriter(w io.Writer, t time.Time) {
|
||||
io.WriteString(w, bezel)
|
||||
secondHand(w, t)
|
||||
minuteHand(w, t)
|
||||
hourHand(w, t)
|
||||
io.WriteString(w, svgEnd)
|
||||
}
|
||||
|
||||
@ -52,6 +54,12 @@ func minuteHand(w io.Writer, t time.Time) {
|
||||
makeHand(w, minuteHandLength, p)
|
||||
}
|
||||
|
||||
// MinuteHand is the unit vector of the minute hand of an analogue clock at the time `t` represented as a Point
|
||||
func hourHand(w io.Writer, t time.Time) {
|
||||
p := hourHandPoint(t)
|
||||
makeHand(w, hourHandLength, p)
|
||||
}
|
||||
|
||||
func makeHand(w io.Writer, length float64, p Point) {
|
||||
p = Point{p.X * length, p.Y * length} // scale
|
||||
p = Point{p.X, -p.Y} // flip
|
||||
@ -64,6 +72,14 @@ func makeHand(w io.Writer, length float64, p Point) {
|
||||
)
|
||||
}
|
||||
|
||||
func hoursInRadians(t time.Time) float64 {
|
||||
return (minutesInRadians(t) / 12) + math.Pi/(6/float64(t.Hour()%12))
|
||||
}
|
||||
|
||||
func hourHandPoint(t time.Time) Point {
|
||||
return angleToPoint(hoursInRadians(t))
|
||||
}
|
||||
|
||||
func minutesInRadians(t time.Time) float64 {
|
||||
return (secondsInRadians(t) / 60) + math.Pi/(30/float64(t.Minute()))
|
||||
}
|
||||
|
@ -65,7 +65,6 @@ func TestSVGWriterMinuteHand(t *testing.T) {
|
||||
line Line
|
||||
}{
|
||||
{simpleTime(0, 0, 0), Line{150, 150, 150, 70}},
|
||||
// {simpleTime(0, 0, 30), Line{150, 150, 150, 240}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
@ -87,6 +86,33 @@ func TestSVGWriterMinuteHand(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSVGWriterHourHand(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
line Line
|
||||
}{
|
||||
{simpleTime(6, 0, 0), Line{150, 150, 150, 200}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(testName(c.time), func(t *testing.T) {
|
||||
b := bytes.Buffer{}
|
||||
SVGWriter(&b, c.time)
|
||||
|
||||
svg := Svg{}
|
||||
xml.Unmarshal(b.Bytes(), &svg)
|
||||
|
||||
if !containsLine(c.line, svg.Line) {
|
||||
t.Errorf(
|
||||
"Expected to find the hour hand line %+v in the SVG lines %v",
|
||||
c.line,
|
||||
svg.Line,
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func containsLine(l Line, ls []Line) bool {
|
||||
for _, line := range ls {
|
||||
if line == l {
|
||||
|
@ -6,6 +6,47 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestHoursInRadians(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
angle float64
|
||||
}{
|
||||
{simpleTime(6, 0, 0), math.Pi},
|
||||
{simpleTime(0, 0, 0), 0},
|
||||
{simpleTime(21, 0, 0), math.Pi * 1.5},
|
||||
{simpleTime(0, 1, 30), math.Pi / ((6 * 60 * 60) / 90)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(testName(c.time), func(t *testing.T) {
|
||||
got := hoursInRadians(c.time)
|
||||
|
||||
if !roughlyEqualFloat64(c.angle, got) {
|
||||
t.Fatalf("Wanted %v radians, but got %v", c.angle, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHourHandPoint(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
point Point
|
||||
}{
|
||||
{simpleTime(6, 0, 0), Point{0, -1}},
|
||||
{simpleTime(9, 0, 0), Point{-1, 0}},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(testName(c.time), func(t *testing.T) {
|
||||
got := hourHandPoint(c.time)
|
||||
if !roughlyEqualPoint(got, c.point) {
|
||||
t.Fatalf("Wanted %v Point, but got %v", c.point, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinutesInRadians(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
@ -26,28 +67,6 @@ func TestMinutesInRadians(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecondsInRadians(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
angle float64
|
||||
}{
|
||||
{simpleTime(0, 0, 30), math.Pi},
|
||||
{simpleTime(0, 0, 0), 0},
|
||||
{simpleTime(0, 0, 45), (math.Pi / 2) * 3},
|
||||
{simpleTime(0, 0, 7), (math.Pi / 30) * 7},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(testName(c.time), func(t *testing.T) {
|
||||
got := secondsInRadians(c.time)
|
||||
|
||||
if c.angle != got {
|
||||
t.Fatalf("Wanted %v radians, but got %v", c.angle, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMinuteHandPoint(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
@ -67,6 +86,28 @@ func TestMinuteHandPoint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecondsInRadians(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
angle float64
|
||||
}{
|
||||
{simpleTime(0, 0, 30), math.Pi},
|
||||
{simpleTime(0, 0, 0), 0},
|
||||
{simpleTime(0, 0, 45), (math.Pi / 2) * 3},
|
||||
{simpleTime(0, 0, 7), (math.Pi / 30) * 7},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(testName(c.time), func(t *testing.T) {
|
||||
got := secondsInRadians(c.time)
|
||||
|
||||
if c.angle != got {
|
||||
t.Fatalf("Wanted %v radians, but got %v", c.angle, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecondHandPoint(t *testing.T) {
|
||||
cases := []struct {
|
||||
time time.Time
|
||||
|
Loading…
Reference in New Issue
Block a user