C# 从三个点求圆心的求解方程

C# 从三个点求圆心的求解方程,c#,.net,.net-core,C#,.net,.net Core,我正在寻找一个高精度解决方案,从画布上的3个数据点(x,y)找到圆的中心点。我在上面附带的屏幕截图中找到了这个例子,现在我使用Math.NET软件包来求解这个方程,并将结果与这个在线工具进行比较:https://planetcalc.com/8116/ 然而,当我计算半径时,它是完全偏离的,并且经常是负数 using MathNet.Numerics.LinearAlgebra.Double.Solvers; using MathNet.Numerics.LinearAlgebra.Double

我正在寻找一个高精度解决方案,从画布上的3个数据点(x,y)找到圆的中心点。我在上面附带的屏幕截图中找到了这个例子,现在我使用Math.NET软件包来求解这个方程,并将结果与这个在线工具进行比较:
https://planetcalc.com/8116/

然而,当我计算半径时,它是完全偏离的,并且经常是负数

using MathNet.Numerics.LinearAlgebra.Double.Solvers;
using MathNet.Numerics.LinearAlgebra.Double;
using System;

namespace ConsoleAppTestBed
{
  class Program
  {
    static void Main(string[] args)
    {
        var dataPoints = new double[,]
        {

            { 5, 80 },
            { 20, 100 },
            { 40, 140 }
        };


        var fitter = new CircleFitter();
        var result = fitter.Fit(dataPoints);

        var x = -result[0];
        var y = -result[1];
        var c = result[2];

        Console.WriteLine("Center Point:");
        Console.WriteLine(x);
        Console.WriteLine(y);
        Console.WriteLine(c);

        //// (x^2 + y^2 - c^2)
        var radius = Math.Pow(x, 2) + Math.Pow(y, 2) - Math.Pow(c, 2);
        //// sqrt((x^2 + y^2 - c^2))
        radius =  Math.Sqrt(radius);
        Console.WriteLine("Radius:");
        Console.WriteLine(radius);
        Console.ReadLine();
    }

    public class CircleFitter
    {
        public double[] Fit(double[,] v)
        {
            var xy1 = new double[] { v[0,0], v[0,1] };
            var xy2= new double[] { v[1, 0], v[1, 1] };
            var xy3 = new double[] { v[2, 0], v[2, 1] };

            // Create Left Side Matrix of Equation
            var a = CreateLeftSide_(xy1);
            var b = CreateLeftSide_(xy2);
            var c = CreateLeftSide_(xy3);
            var matrixA = DenseMatrix.OfArray(new[,] 
            {
                { a[0], a[1], a[2] },
                { b[0], b[1], b[2] },
                { c[0], c[1], c[2] }
            });

            // Create Right Side Vector of Equation
            var d = CreateRightSide_(xy1);
            var e = CreateRightSide_(xy2);
            var f = CreateRightSide_(xy3);
            double[] vector = { d, e, f };
            var vectorB =  Vector<double>.Build.Dense(vector);

            // Solve Equation
            var r = matrixA.Solve(vectorB);
            var result = r.ToArray();

            return result;
        }

        //2x, 2y, 1
        public double[] CreateLeftSide_(double[] d) 
        {
            return new double[] { (2 * d[0]), (2 * d[1]) , 1};
        
        }

        // -(x^2 + y^2)
        public double CreateRightSide_(double[] d) 
        { 
            return -(Math.Pow(d[0], 2) + Math.Pow(d[1], 2));

        }
    }
  }

}
使用MathNet.Numerics.LinearAlgebra.Double.solver;
使用MathNet.Numerics.LinearAlgebra.Double;
使用制度;
命名空间控制台桌面
{
班级计划
{
静态void Main(字符串[]参数)
{
var数据点=新的双精度[,]
{
{ 5, 80 },
{ 20, 100 },
{ 40, 140 }
};
var fitter=新的CircleFitter();
var结果=fitter.Fit(数据点);
var x=-结果[0];
变量y=-结果[1];
var c=结果[2];
控制台。写入线(“中心点:”);
控制台写入线(x);
控制台写入线(y);
控制台写入线(c);
////(x^2+y^2-c^2)
变量半径=数学功率(x,2)+数学功率(y,2)-数学功率(c,2);
////sqrt((x^2+y^2-c^2))
半径=数学Sqrt(半径);
控制台。写入线(“半径:”);
控制台写入线(半径);
Console.ReadLine();
}
公共类电路板
{
公共双[]配合(双[,]v)
{
var xy1=新的双精度[]{v[0,0],v[0,1]};
var xy2=新的双精度[]{v[1,0],v[1,1]};
var xy3=新的双精度[]{v[2,0],v[2,1]};
//创建方程的左侧矩阵
var a=CreateLeftSide_u1(xy1);
var b=CreateLeftSide_uxy2;
var c=CreateLeftSide_u3;
var matrixA=阵列密度矩阵(新[,]
{
{a[0],a[1],a[2]},
{b[0],b[1],b[2]},
{c[0],c[1],c[2]}
});
//创建方程的右侧向量
var d=CreateRightSide_u1(xy1);
var e=CreateRightSide_u2;(xy2);
var f=CreateRightSide_uxy3;
双[]向量={d,e,f};
var vectorB=Vector.Build.densite(向量);
//解方程
var r=矩阵解(向量B);
var结果=r.ToArray();
返回结果;
}
//2x,2y,1
公共双精度[]CreateLeftSide_Ud(双精度[]d)
{
返回新的双精度[]{(2*d[0]),(2*d[1]),1};
}
//-(x^2+y^2)
公共双CreateRightSide_uUd(双[]d)
{ 
return-(Math.Pow(d[0],2)+Math.Pow(d[1],2));
}
}
}
}
有什么想法吗


提前感谢。

您的问题解决方案如下:

代码:


请定义“高精度”。。。。你可以在可能的情况下使用小数。我正在wpf画布上画圆圈和三个点。我最初是在寻找垂直线相交的地方。。但是,当计算出的圆的半径穿过某些点时,有时会出现一个或两个像素偏移。我用的是双倍自动取款机,我试试小数。
using System;
using System.Globalization;
namespace ConsoleApp1
{
class Program
{
    static void Main()
    {
        double x1 = 1, y1 = 1;
        double x2 = 2, y2 = 4;
        double x3 = 5, y3 = -3;
        findCircle(x1, y1, x2, y2, x3, y3);
        Console.ReadKey();
    }
    static void findCircle(double x1, double y1,
                           double x2, double y2,
                           double x3, double y3)
    {
        NumberFormatInfo setPrecision = new NumberFormatInfo();
        setPrecision.NumberDecimalDigits = 3; // 3 digits after the double point

        double x12 = x1 - x2;
        double x13 = x1 - x3;

        double y12 = y1 - y2;
        double y13 = y1 - y3;

        double y31 = y3 - y1;
        double y21 = y2 - y1;

        double x31 = x3 - x1;
        double x21 = x2 - x1;

        double sx13 = (double)(Math.Pow(x1, 2) -
                        Math.Pow(x3, 2));

        double sy13 = (double)(Math.Pow(y1, 2) -
                        Math.Pow(y3, 2));

        double sx21 = (double)(Math.Pow(x2, 2) -
                        Math.Pow(x1, 2));

        double sy21 = (double)(Math.Pow(y2, 2) -
                        Math.Pow(y1, 2));

        double f = ((sx13) * (x12)
                + (sy13) * (x12)
                + (sx21) * (x13)
                + (sy21) * (x13))
                / (2 * ((y31) * (x12) - (y21) * (x13)));
        double g = ((sx13) * (y12)
                + (sy13) * (y12)
                + (sx21) * (y13)
                + (sy21) * (y13))
                / (2 * ((x31) * (y12) - (x21) * (y13)));

        double c = -(double)Math.Pow(x1, 2) - (double)Math.Pow(y1, 2) -
                                    2 * g * x1 - 2 * f * y1;
        double h = -g;
        double k = -f;
        double sqr_of_r = h * h + k * k - c;

        // r is the radius
        double r = Math.Round(Math.Sqrt(sqr_of_r), 5);

        Console.WriteLine("Center of a circle: x = " + h.ToString("N", setPrecision) + 
        ", y = " + k.ToString("N", setPrecision));
        Console.WriteLine("Radius: " + r.ToString("N", setPrecision));
        }
        }
        }