diff --git a/clockface.go b/clockface.go
index 00b9b97..10c92bf 100644
--- a/clockface.go
+++ b/clockface.go
@@ -5,17 +5,30 @@ import (
"time"
)
+const (
+ secondsInHalfClock = 30
+ secondsInClock = 2 * secondsInHalfClock
+ minutesInHalfClock = 30
+ minutesInClock = 2 * minutesInHalfClock
+ hoursInHalfClock = 6
+ hoursInClock = 2 * hoursInHalfClock
+)
+
type Point struct {
X float64
Y float64
}
func secondsInRadians(t time.Time) float64 {
- return math.Pi / (30 / (float64(t.Second())))
+ return math.Pi / (secondsInHalfClock / (float64(t.Second())))
}
func minutesInRadians(t time.Time) float64 {
- return secondsInRadians(t)/60 + math.Pi/(30/(float64(t.Minute())))
+ return secondsInRadians(t)/minutesInClock + math.Pi/(minutesInHalfClock/(float64(t.Minute())))
+}
+
+func hoursInRadians(t time.Time) float64 {
+ return (minutesInRadians(t) / hoursInClock) + (math.Pi / (hoursInHalfClock / float64(t.Hour()%hoursInClock)))
}
func angleToPoint(angle float64) Point {
@@ -32,3 +45,7 @@ func secondHandPoint(t time.Time) Point {
func minuteHandPoint(t time.Time) Point {
return angleToPoint(minutesInRadians(t))
}
+
+func hourHandPoint(t time.Time) Point {
+ return angleToPoint(hoursInRadians(t))
+}
diff --git a/clockface_acceptance_test.go b/clockface_acceptance_test.go
index ea89920..b18864c 100644
--- a/clockface_acceptance_test.go
+++ b/clockface_acceptance_test.go
@@ -88,3 +88,27 @@ 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)
+ }
+ })
+ }
+}
diff --git a/clockface_test.go b/clockface_test.go
index 47beb94..f9c0cbc 100644
--- a/clockface_test.go
+++ b/clockface_test.go
@@ -20,7 +20,7 @@ func TestSecondsInRadians(t *testing.T) {
for _, c := range cases {
t.Run(testName(c.time), func(t *testing.T) {
got := secondsInRadians(c.time)
- if got != c.angle {
+ if !roughlyEqualFloat64(got, c.angle) {
t.Fatalf("Wanted %v radians, but got %v", c.angle, got)
}
})
@@ -39,13 +39,34 @@ func TestMinutesInRadians(t *testing.T) {
for _, c := range cases {
t.Run(testName(c.time), func(t *testing.T) {
got := minutesInRadians(c.time)
- if got != c.angle {
+ if !roughlyEqualFloat64(got, c.angle) {
t.Fatalf("Wanted %v radians, but got %v", c.angle, got)
}
})
}
}
+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(got, c.angle) {
+ t.Fatalf("wanted %v radians, but got %v", c.angle, got)
+ }
+ })
+ }
+}
+
func TestSecondHandPoint(t *testing.T) {
cases := []struct {
time time.Time
@@ -84,6 +105,26 @@ func TestMinuteHandPoint(t *testing.T) {
}
}
+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}},
+ {simpleTime(21, 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 roughlyEqualFloat64(a, b float64) bool {
const equalityThreshold = 1e-7
return math.Abs(a-b) < equalityThreshold
diff --git a/svgWriter.go b/svgWriter.go
index dc697c0..ff4c82e 100644
--- a/svgWriter.go
+++ b/svgWriter.go
@@ -6,10 +6,13 @@ import (
"time"
)
-const secondHandLength = 90
-const minuteHandLength = 80
-const clockCentreX = 150
-const clockCentreY = 150
+const (
+ hourHandLength = 50
+ secondHandLength = 90
+ minuteHandLength = 80
+ clockCentreX = 150
+ clockCentreY = 150
+)
const svgStart = `
@@ -29,6 +32,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)
}
@@ -47,3 +51,8 @@ func MinuteHand(w io.Writer, t time.Time) {
p := makeHand(minuteHandPoint(t), minuteHandLength)
fmt.Fprintf(w, ``, p.X, p.Y)
}
+
+func HourHand(w io.Writer, t time.Time) {
+ p := makeHand(hourHandPoint(t), hourHandLength)
+ fmt.Fprintf(w, ``, p.X, p.Y)
+}