public void MoveChessboard(ChessboardMovement direction) { var corner = BoardReprezentation.CornerOfChessboard; var vector1 = BoardReprezentation.FieldVector1; var vector2 = BoardReprezentation.FieldVector2; switch (direction) { case ChessboardMovement.Vector1Plus: BoardReprezentation.CornerOfChessboard = MyVector3DStruct.Addition(corner, vector1); break; case ChessboardMovement.Vector1Minus: BoardReprezentation.CornerOfChessboard = MyVector3DStruct.Difference(ref corner, ref vector1); break; case ChessboardMovement.Vector2Plus: BoardReprezentation.CornerOfChessboard = MyVector3DStruct.Addition(corner, vector2); break; case ChessboardMovement.Vector2Minus: BoardReprezentation.CornerOfChessboard = MyVector3DStruct.Difference(ref corner, ref vector2); break; default: throw new ArgumentOutOfRangeException(nameof(direction), direction, null); } }
/// <summary> /// Finds most suitable chessboard fitting real points /// </summary> public static Chessboard3DReprezentation ChessboardFittingAlgorithm(List <Point2D> contractedPoints, ChessboardTrackingCompleteData chessboardData) { const int takeXNearestNeighbors = 7; var contractedPoints3D = ConvertIntersectionsTo3D(contractedPoints, chessboardData); var contractedPoints3DasStruct = contractedPoints3D.Select(x => new MyVector3DStruct(x.X, x.Y, x.Z)).ToArray(); double lowestError = double.MaxValue; Chessboard3DReprezentation boardRepresentation = null; Parallel.ForEach(contractedPoints3DasStruct, csp => { // take _ nearest neighbors var neighbors = contractedPoints3DasStruct.OrderBy((MyVector3DStruct x) => MyVector3DStruct.Distance(ref x, ref csp)).Take(takeXNearestNeighbors).ToArray(); // take all pairs of neighbors for (int i = 0; i < neighbors.Length; i++) { for (int j = i + 1; j < neighbors.Length; j++) { var first = neighbors[i]; var second = neighbors[j]; var firstPoint = new MyVector3DStruct(first.x, first.y, first.z); var secondPoint = new MyVector3DStruct(second.x, second.y, second.z); // st. point + 2 vectors var initialPoint = new MyVector3DStruct(csp.x, csp.y, csp.z); var firstVector = MyVector3DStruct.Difference(ref firstPoint, ref initialPoint); var secondVector = MyVector3DStruct.Difference(ref secondPoint, ref initialPoint); // perpendicularity check double angleBetweenVectors = MyVector3DStruct.AngleInDeg(ref firstVector, ref secondVector); if (!(angleBetweenVectors < 91.4 && angleBetweenVectors > 88.6)) { break; } // length check double ratio = firstVector.Magnitude() / secondVector.Magnitude(); if (!(ratio > 0.85f && ratio < 1.15f)) { break; } // ensure right mutual position of first and second vector - otherwise switch them if (MyVector3DStruct.CrossProduct(ref firstVector, ref secondVector).z < 0) { var temp = firstVector; firstVector = secondVector; secondVector = temp; } // length normalization of vectors double averageLength = (firstVector.Magnitude() + secondVector.Magnitude()) / 2; firstVector = MyVector3DStruct.MultiplyByNumber(MyVector3DStruct.Normalize(ref firstVector), averageLength); secondVector = MyVector3DStruct.MultiplyByNumber(MyVector3DStruct.Normalize(ref secondVector), averageLength); var negatedFirstVector = MyVector3DStruct.Negate(ref firstVector); var negatedSecondVector = MyVector3DStruct.Negate(ref secondVector); // locate all possible starting points for (int f = 0; f < 9; f++) { for (int s = 0; s < 9; s++) { var startingPoint = MyVector3DStruct.Addition( MyVector3DStruct.Addition( MyVector3DStruct.MultiplyByNumber(negatedFirstVector, f), MyVector3DStruct.MultiplyByNumber(negatedSecondVector, s) ) , initialPoint ); // generate all possible chessboards for given starting point and compute their error double currentError = 0; for (int ff = 0; ff < 9; ff++) { for (int ss = 0; ss < 9; ss++) { var currentPoint = MyVector3DStruct.Addition( startingPoint, MyVector3DStruct.Addition( MyVector3DStruct.MultiplyByNumber(firstVector, ff), MyVector3DStruct.MultiplyByNumber(secondVector, ss) ) ); var closestPointDistance = contractedPoints3DasStruct.Min(x => MyVector3DStruct.Distance(ref currentPoint, new MyVector3DStruct(x.x, x.y, x.z))); // clipping of max error per point var clippingDistance = chessboardData.UserParameters.ClippedDistanecInChessboardFittingMetric / 1000f; closestPointDistance = closestPointDistance > clippingDistance ? clippingDistance : closestPointDistance; if (chessboardData.UserParameters.IsDistanceMetricInChessboardFittingExperimental) { closestPointDistance = closestPointDistance * closestPointDistance; } currentError += closestPointDistance; } } if (currentError < lowestError) { lowestError = currentError; boardRepresentation = new Chessboard3DReprezentation(startingPoint, firstVector, secondVector); } } } } } }); return(boardRepresentation); }