From 92c45828d95a7a7bde69219a318786b502f6657d Mon Sep 17 00:00:00 2001 From: mitch Date: Thu, 20 Jan 2022 01:07:29 -0500 Subject: [PATCH] Added hour hand --- clockface.go | 21 +++++++++++++++-- clockface_acceptance_test.go | 24 +++++++++++++++++++ clockface_test.go | 45 ++++++++++++++++++++++++++++++++++-- svgWriter.go | 17 ++++++++++---- 4 files changed, 99 insertions(+), 8 deletions(-) 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) +}