Rotating a Signature: Part 1
August 7, 2012 Leave a comment
For the next step of my signature analysis, I need to rotate the signatures so that both the compared and the comparee signatures are on the same horizontal plain. To rotate the signatures, I need to find the center line (which I did in this blog post) and then rotate that line to horizontal with all of the signature’s points keeping the exact same relationship to the center line.
To that end, I need to find the center point of the signature. I created my first unit test like this:
[TestMethod()] [DeploymentItem("Tff.Signature.Comparison.dll")] public void GetCenterPoint_OddNumberOfPoints_ReturnsCenterPoint() { ScatterplotComparisonFactory_Accessor target = new ScatterplotComparisonFactory_Accessor(); List<Point> points = new List<Point>(); points.Add(new Point(0, 0)); points.Add(new Point(1, 1)); points.Add(new Point(2, 2)); Point expected = new Point(1,1); Point actual = target.GetCenterPoint(points); Assert.AreEqual(expected, actual); }
I then wrote enough production to pass this test:
private Point GetCenterPoint(List<Point> comparePoints) { Int32 totalX = 0; Int32 totalY = 0; Int32 totalCount = 0; foreach (Point point in comparePoints) { totalX += point.X; totalY += point.Y; totalCount += 1; } Int32 averageX = (Int32)(totalX / totalCount); Int32 averageY = (Int32)(totalY / totalCount); return new Point(averageX, averageY); }
Sure enough: GreenToGo:
I then wrote a test for a list of 4 points and quickly realize that I can’t calculate the center point for a list that contains an even-number of points:
Sounds like an exception to me. I altered the test like so
[TestMethod()] [DeploymentItem("Tff.Signature.Comparison.dll")] [ExpectedException(typeof(ArgumentException))] public void GetCenterPoint_EvenNumberOfPoints_ThrowsArgumentException() { ScatterplotComparisonFactory_Accessor target = new ScatterplotComparisonFactory_Accessor(); List<Point> points = new List<Point>(); points.Add(new Point(0, 0)); points.Add(new Point(1, 1)); points.Add(new Point(2, 2)); points.Add(new Point(3, 3)); Point actual = target.GetCenterPoint(points); Assert.Fail("Should not get here."); }
and then the production code:
private Point GetCenterPoint(List<Point> comparePoints) { if (comparePoints.Count % 2 == 0) { throw new ArgumentException("comparePoints must have an even number."); } Int32 totalX = 0; Int32 totalY = 0; Int32 totalCount = 0; foreach (Point point in comparePoints) { totalX += point.X; totalY += point.Y; totalCount += 1; } Int32 averageX = (Int32)(totalX / totalCount); Int32 averageY = (Int32)(totalY / totalCount); return new Point(averageX, averageY); }
And I was greentogo.
So then I thought – what about a line where the center point is not included in the list?
[TestMethod()] [DeploymentItem("Tff.Signature.Comparison.dll")] [ExpectedException(typeof(ArgumentException))] public void GetCenterPoint_OddNumberOfNonConsecutivePoints_ReturnsCenterPoint() { ScatterplotComparisonFactory_Accessor target = new ScatterplotComparisonFactory_Accessor(); List<Point> points = new List<Point>(); points.Add(new Point(0, 0)); points.Add(new Point(1, 1)); points.Add(new Point(2, 2)); points.Add(new Point(5, 5)); points.Add(new Point(6, 6)); Point expected = new Point(3, 3); Point actual = target.GetCenterPoint(points); Assert.AreEqual(expected, actual); }
I got Red
The problem is that list of points that I am using to represent the line may or may not include the true center point. But that is not the center points problem – its only job is to tell me the center point for an odd number of points. The problem is that there is a rounding assumption in the code – 1/2 way between 0 and 6 is three – the values of the other numbers are irrelevant. I then refactored the GetCenterPoint like so:
private Point GetCenterPoint(List<Point> comparePoints) { if (comparePoints.Count % 2 == 0) { throw new ArgumentException("comparePoints must have an odd number."); } Point lowestPoint = comparePoints.Min(); Point highestPoint = comparePoints.Max(); Double MidX = (highestPoint.X + lowestPoint.X)/2; Double MidY = (highestPoint.Y + lowestPoint.Y)/2; Int32 MidXRounded = (Int32)MidX; Int32 MidYRounded = (Int32)MidY; return new Point(MidXRounded, MidYRounded); }
And I was GreenToGo.
I then realized that GetCenterPoint implicitly violates the SRP – it doesn’t matter if there is a even or odd number in the compare points – just as long as there is at least 1 point. The even/odd is only if I want to see if the center point of the line is in the list of points that I am using to represent the line. That is another function – and another set of tests. I refactored the GetCenterPoint like this:
if (comparePoints.Count == 0) { throw new ArgumentException("comparePoints has no points."); }
And changed my ArguementExceptionTest:
[TestMethod()] [DeploymentItem("Tff.Signature.Comparison.dll")] [ExpectedException(typeof(ArgumentException))] public void GetCenterPoint_NoPointsInArgument_ThrowsArgumentException() { ScatterplotComparisonFactory_Accessor target = new ScatterplotComparisonFactory_Accessor(); List<Point> points = new List<Point>(); Point actual = target.GetCenterPoint(points); Assert.Fail("Should not get here."); }
And I was still green everywhere. With the center point established, I was ready to tackle the rotation of the points around that center point.