计算矩阵中每个点的坐标
给定左上角、左下角和右上角三个点的坐标,以及矩阵的行数、列数、行间距和列间距,我们可以计算出所有点的坐标。
在项目中有一个运动装置,只可按照x或y方向移动。目标是在96孔板的96个孔,而这些孔是排列整齐有序的,那么我们就可通过该方案计算出剩余的点,来简化示教人员的工作。
代码实现
public class PlateWellPoint
{
public double X { get; }
public double Y { get; }
public int RowIndex { get; set; }
public int ColumnIndex { get; set; }
public PlateWellPoint(double x, double y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"R{RowIndex}C{ColumnIndex}({X:F2}, {Y:F2})";
}
}
public class PlatePointMatrixGenerator
{
public static List<PlateWellPoint> GeneratePoints(PlateWellPoint topLeft, PlateWellPoint bottomLeft, PlateWellPoint topRight, int rows, int cols, double rowSpacing, double colSpacing)
{
// 计算右下角点坐标
PlateWellPoint bottomRight = CalculateBottomRightPoint(topLeft, bottomLeft, topRight);
// 验证输入的四个点是否形成矩形
if (!IsRectangle(topLeft, bottomLeft, topRight, bottomRight))
{
Console.WriteLine("警告:输入的三个点无法形成矩形,计算结果可能不准确。");
}
// 计算矩阵中所有点的坐标
List<PlateWellPoint> allPoints = CalculateAllPoints(topLeft, topRight, bottomLeft, rows, cols);
// 输出所有点的坐标
Console.WriteLine("\n矩阵中所有点的坐标:");
int index = 0;
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
Console.WriteLine($"点[{r},{c}]: {allPoints[index]}");
index++;
}
}
// 验证间距
VerifySpacing(allPoints, rows, cols, rowSpacing, colSpacing);
return allPoints;
}
// 计算右下角的点坐标
static PlateWellPoint CalculateBottomRightPoint(PlateWellPoint topLeft, PlateWellPoint bottomLeft, PlateWellPoint topRight)
{
// 右下角的坐标可以通过向量加法计算
// 从左上角到右上角的位移 + 从左上角到左下角的位移 = 从左上角到右下角的位移
double bottomRightX = topLeft.X + (topRight.X - topLeft.X) + (bottomLeft.X - topLeft.X);
double bottomRightY = topLeft.Y + (topRight.Y - topLeft.Y) + (bottomLeft.Y - topLeft.Y);
return new PlateWellPoint(bottomRightX, bottomRightY);
}
// 检查四个点是否构成矩形
static bool IsRectangle(PlateWellPoint topLeft, PlateWellPoint bottomLeft, PlateWellPoint topRight, PlateWellPoint bottomRight)
{
// 计算对角线长度是否相等
double diagonal1 = Math.Sqrt(Math.Pow(topLeft.X - bottomRight.X, 2) + Math.Pow(topLeft.Y - bottomRight.Y, 2));
double diagonal2 = Math.Sqrt(Math.Pow(topRight.X - bottomLeft.X, 2) + Math.Pow(topRight.Y - bottomLeft.Y, 2));
// 对角线长度应该近似相等
return Math.Abs(diagonal1 - diagonal2) < 0.001;
}
// 计算矩阵中所有点的坐标
static List<PlateWellPoint> CalculateAllPoints(PlateWellPoint topLeft, PlateWellPoint topRight, PlateWellPoint bottomLeft, int rows, int cols)
{
List<PlateWellPoint> points = new List<PlateWellPoint>();
// 计算行方向和列方向的单位向量
double rowVectorX = (bottomLeft.X - topLeft.X) / (rows - 1);
double rowVectorY = (bottomLeft.Y - topLeft.Y) / (rows - 1);
double colVectorX = (topRight.X - topLeft.X) / (cols - 1);
double colVectorY = (topRight.Y - topLeft.Y) / (cols - 1);
// 计算每个点的坐标
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
double x = topLeft.X + r * rowVectorX + c * colVectorX;
double y = topLeft.Y + r * rowVectorY + c * colVectorY;
points.Add(new PlateWellPoint(x, y) { RowIndex = r, ColumnIndex = c });
}
}
return points;
}
// 验证计算的点是否符合给定的行间距和列间距
static void VerifySpacing(List<PlateWellPoint> points, int rows, int cols, double expectedRowSpacing, double expectedColSpacing)
{
double totalRowSpacingError = 0;
int rowSpacingCount = 0;
double totalColSpacingError = 0;
int colSpacingCount = 0;
// 检查行间距
for (int r = 0; r < rows - 1; r++)
{
for (int c = 0; c < cols; c++)
{
int idx1 = r * cols + c;
int idx2 = ((r + 1) * cols) + c;
double distance = Math.Sqrt(Math.Pow(points[idx1].X - points[idx2].X, 2) + Math.Pow(points[idx1].Y - points[idx2].Y, 2));
totalRowSpacingError += Math.Abs(distance - expectedRowSpacing);
rowSpacingCount++;
}
}
// 检查列间距
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols - 1; c++)
{
int idx1 = r * cols + c;
int idx2 = r * cols + c + 1;
double distance = Math.Sqrt(Math.Pow(points[idx1].X - points[idx2].X, 2) + Math.Pow(points[idx1].Y - points[idx2].Y, 2));
totalColSpacingError += Math.Abs(distance - expectedColSpacing);
colSpacingCount++;
}
}
// 打印平均误差
if (rowSpacingCount > 0)
{
double avgRowError = totalRowSpacingError / rowSpacingCount;
Console.WriteLine($"\n行间距平均误差: {avgRowError:F4} mm");
}
if (colSpacingCount > 0)
{
double avgColError = totalColSpacingError / colSpacingCount;
Console.WriteLine($"列间距平均误差: {avgColError:F4} mm");
}
}
}
案例图
矩阵模拟图" />
调用验证
var leftTop = new PlateWellPoint(2, 2);
var rightTop = new PlateWellPoint(6, 6);
var leftButtom = new PlateWellPoint(4, 0);
int rowCount = 3;
int columnCount = 5;
var points = PlatePointMatrixGenerator.GeneratePoints(leftTop, leftButtom, rightTop, rowCount, columnCount, 1, 1);
运行结果
注意:行列序号从0开始的。
从上述结果中随便选一个点,在案例图中找到进行坐标验证
例如:取索引为13的点,是R2C3即第三行第四列,在案例图中核对坐标是否为x:7,y:3。
从案例图中任选一个坐标点,在上述结果中查找,是否为指定的行和列。