三点定圆原理与C++实现

article/2025/11/6 22:27:38

文章目录

    • 1 原理
    • 2 C++实现


1 原理

根据我们小学二年级就学过的三点定圆定理:

不 共 线 的 三 个 点 可 唯 一 确 定 一 个 圆 不共线的三个点可唯一确定一个圆 线

且,不共线的三点相互连接必然构成一个三角形,这个三角形称为圆的内接三角形,这个圆称为三角形的外接圆。三角形三边垂直平分线的交点即为三角形外接圆的圆心。

有了以上知识,由不共线的三个点确定一个圆就非常easy了

已知平面中不共线的三点 A ( x 1 , y 1 , z 1 ) A(x_1,y_1,z_1) A(x1,y1,z1) B ( x 2 , y 2 , z 2 ) B(x_2,y_2,z_2) B(x2,y2,z2) C ( x 3 , y 3 , z 3 ) C(x_3,y_3,z_3) C(x3,y3,z3),互相连接构成三角形 ΔABC, L a b L_{ab} Lab L b c L_{bc} Lbc L a c L_{ac} Lac 分别为三条边的垂直平分线,且相交于一点 O O O,该交点即为外接圆圆心。
在这里插入图片描述

三角形三边斜率:

{ k a b = y 2 − y 1 x 2 − x 1 k b c = y 3 − y 2 x 3 − x 2 k a c = y 3 − y 1 x 3 − x 1 \begin{cases} k_{ab}=\cfrac {y_2-y_1}{x_2-x_1}\\ k_{bc}=\cfrac {y_3-y_2}{x_3-x_2}\\ k_{ac}=\cfrac {y_3-y_1}{x_3-x_1}\\ \end{cases} kab=x2x1y2y1kbc=x3x2y3y2kac=x3x1y3y1
三边中点:
P a b ( x 1 + x 2 2 , y 1 + y 2 2 ) , P b c ( x 2 + x 3 2 , y 2 + y 3 2 ) , P a c ( x 1 + x 3 2 , y 1 + y 3 2 ) P_{ab}(\cfrac {x_1+x_2}{2},\cfrac {y_1+y_2}{2}), P_{bc}(\cfrac {x_2+x_3}{2},\cfrac {y_2+y_3}{2}), P_{ac}(\cfrac {x_1+x_3}{2},\cfrac {y_1+y_3}{2}) Pab(2x1+x22y1+y2),Pbc(2x2+x32y2+y3),Pac(2x1+x32y1+y3)

根据直线的点斜式方程,可求三条垂直平分线方程如下:
{ L a b = y − y 1 + y 2 2 + 1 k a b ( x − x 1 + x 2 2 ) = 0 L b c = y − y 2 + y 3 2 + 1 k b c ( x − x 2 + x 3 2 ) = 0 L a c = y − y 1 + y 3 2 + 1 k a c ( x − x 1 + x 3 2 ) = 0 \begin{cases} L_{ab}=y-\cfrac {y_1+y_2}{2}+\cfrac {1}{k_{ab}}(x-\cfrac {x_1+x_2}{2})=0\\ L_{bc}=y-\cfrac {y_2+y_3}{2}+\cfrac {1}{k_{bc}}(x-\cfrac {x_2+x_3}{2})=0\\ L_{ac}=y-\cfrac {y_1+y_3}{2}+\cfrac {1}{k_{ac}}(x-\cfrac {x_1+x_3}{2})=0\\ \end{cases} Lab=y2y1+y2+kab1(x2x1+x2)=0Lbc=y2y2+y3+kbc1(x2x2+x3)=0Lac=y2y1+y3+kac1(x2x1+x3)=0

三个方程,两个未知量,因此任选其中两个方程求解圆心坐标 O ( x 0 , y 0 ) O(x_0,y_0) O(x0,y0),则圆心 O O O到点 A 、 B 、 C A、B、C ABC任一点的距离就是外接圆的半径,即
r = ∣ O A ∣ = ∣ O B ∣ = ∣ O C ∣ = ( x 0 − x 1 ) 2 + ( y 0 − y 1 ) 2 r=|OA|=|OB|=|OC|=\sqrt {{(x_0-x_1)^2}+{(y_0-y_1)^2}} r=OA=OB=OC=(x0x1)2+(y0y1)2
至此,可求得外接圆的方程为
( x − x 0 ) 2 + ( y − y 0 ) 2 = r 2 (x-x_0)^2+(y-y_0)^2=r^2 (xx0)2+(yy0)2=r2

2 C++实现

以圆: ( x − 1 ) 2 + ( y − 1 ) 2 = 1 (x-1)^2+(y-1)^2=1 (x1)2+(y1)2=1为例,选择圆上三点 p 1 ( 0 , 1 ) 、 p 2 ( 1 , 2 ) 、 p 3 ( 1.5 , 0.75 + 1 ) p_1(0,1)、p_2(1,2)、p_3(1.5,\sqrt{0.75}+1) p1(0,1)p2(1,2)p3(1.5,0.75 +1) 进行验证。

大家也可以自行输入其他点进行验证,只需在main.cpp中修改三个点的坐标即可。

注意: 需要用到Eigen库求解二元一次方程组,PointXY类型的点;可自己定义一个结构体PointXY,也可直接使用PCL库里面定义好的结构体

mian.cpp

#include "deifen_circle_with_3points.h"int main()
{PointT p1, p2, p3;				//定义三个点p1.x = 0.0;p1.y = 1.0;p2.x = 1.0;p2.y = 2.0;p3.x = 1.5;p3.y = sqrt(0.75) + 1.0;DefineCircl3Points dc;			//定义三点定圆对象dcdc.setThreePoints(p1, p2, p3);	//设置三点dc.defineCircle();				//执行三点定圆return 0;
}

deifen_circle_with_3points.h

#pragma once
#include <iostream>
#include <pcl/io/pcd_io.h>		//二维点PointXY类型所在头文件;包含Eigen库using namespace std;
using namespace Eigen;typedef pcl::PointXY PointT;class DefineCircl3Points
{
public:/*** @brief   : 输入三点* @param[I]: p1 (x1,y1)* @param[I]: p2 (x2,y2)* @param[I]: p3 (x3,y3)* @param[O]: none* @return  : none* @note    :**/void setThreePoints(PointT &p1, PointT &p2, PointT &p3);/*** @brief   : 三点定圆* @param[I]: none* @param[O]: none* @return  : none* @note    : 输出圆心、半径、圆方程**/void defineCircle();private:PointT m_p1, m_p2, m_p3;		//输入的三点bool is_set3Points = false;		//是否输入三点};

deifen_circle_with_3points.cpp

#include "deifen_circle_with_3points.h"/**
* @brief   : 输入三点
* @param[I]: p1 (x1,y1)
* @param[I]: p2 (x2,y2)
* @param[I]: p3 (x3,y3)
* @param[O]: none
* @return  : none
* @note    :
**/
void DefineCircl3Points::setThreePoints(PointT & p1, PointT & p2, PointT & p3)
{//判断是否三点共线if ((p2.x - p1.x)*(p3.y - p1.y) - (p3.x - p1.x)*(p2.y - p1.y) == 0){PCL_ERROR("->三点共线,无法确定一个圆!\a\n");system("pause");abort();}m_p1 = p1;m_p2 = p2;m_p3 = p3;is_set3Points = true;
}/**
* @brief   : 三点定圆
* @param[I]: none
* @param[O]: none
* @return  : none
* @note    : 输出圆心、半径、圆方程
**/
void DefineCircl3Points::defineCircle()
{if (!is_set3Points){PCL_ERROR("->请输入三个点!\a\n");system("pause");abort();}float kab, kbc, kac;	//三边斜率kab = (m_p2.y - m_p1.y) / (m_p2.x - m_p1.x);kbc = (m_p3.y - m_p2.y) / (m_p3.x - m_p2.x);kac = (m_p3.y - m_p1.y) / (m_p3.x - m_p1.x);PointT Pab, Pbc, Pac;	//三边中点Pab.x = (m_p1.x + m_p2.x) / 2;Pab.y = (m_p1.y + m_p2.y) / 2;Pbc.x = (m_p2.x + m_p3.x) / 2;Pbc.y = (m_p2.y + m_p3.y) / 2;Pac.x = (m_p1.x + m_p3.x) / 2;Pac.y = (m_p1.y + m_p3.y) / 2;//矩阵方程Ga=dMatrix2f G;G << 1 / kab, 1, 1 / kbc, 1;Vector2f d;d << (Pab.y + 1 / kab * Pab.x), (Pbc.y + 1 / kbc * Pbc.x);Vector2f a;a = G.colPivHouseholderQr().solve(d);float r;	//圆半径r = sqrt(pow((a[0, 0] - m_p1.x), 2) + pow((a[1, 0] - m_p1.y), 2));cout << "圆心:" << "(" << a[0, 0] << ", " << a[1, 0] << ")" << endl;cout << "半径:" << r << endl;cout << "->圆方程:"<< "(x - " << a[0, 0] << " )^2 + (y - " << a[1, 0] << " )^2 = " << r << "^2" << endl;
}

输出结果:

圆心:(1, 1)
半径:1
->圆方程:(x - 1 )^2 + (y - 1 )^2 = 1^2

当然,也可以直接调用PCL库RANSAC圆拟合的方式计算圆心和半径,只需将最大迭代次数设置为1即可

ransac.setMaxIterations(1);

相关链接

PCL随机采样一致性:RANSAC 圆拟合(二维圆 + 空间圆)

线性方程组/矩阵方程求解(方法汇总)

Markdown输入公式、符号等语法指令汇总


http://chatgpt.dhexx.cn/article/N8dr7N3j.shtml

相关文章

使用C语言实现简单的PNG图像读取

概述 首先&#xff0c;关于png图像的结构&#xff1a;PNG文件的结构、PNG格式的数据结构。这两篇文章说的比较细。我简单地说一下我使用到的地方&#xff1a; 注&#xff1a;①引于PNG格式的数据结构。②引于PNG文件的结构 “png文件的前8个字节为固定的文件头信息&#xff0…

RK3588平台开发系列讲解(Display篇)开机视频的设置

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、开机视频功能介绍二、使用方法2.1、开启与关闭2.2、视频放置位置2.3、编译结果2.4、视频素材要求2.5、参数控制说明沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍RK3588平台开机视频的使用方法…

NR PUCCH(一) PUCCH format 0/1

欢迎关注同名微信公众号“modem协议笔记”。 NR中PUCCH物理信道用来发送上行控制信息Uplink Control Information(UCI)&#xff0c;当然UCI也可以在PUSCH上发送。UCI 内容包括&#xff1a;CSI,HARQ ACK/NACK ,SR 及上述三者的组合信息。 那先看下PUCCH format &#xff0c;序…

NR PUSCH(三) 频域资源分配方式

微信公众号同步更新欢迎关注同名modem协议笔记 这篇看下频域资源分配&#xff0c;本篇内容主要在38.214 6.1.2.2 resource allocation in frequency domain章节中。 相比于R15&#xff0c;R16 频域资源分配有3种类型 Uplink resource allocation scheme type 0/1/2&#xff08…

NR PUSCH(四) Frequency hopping

微信公众号同步更新&#xff0c;欢迎关注同名modem协议笔记 上篇PUSCH 介绍了频域分配方式resource allocation type0/1/2&#xff0c;其中type 0 RBG位图的分配方式比较灵活&#xff0c;type 2对应的interlaced RB 本身就是一种频域的离散化&#xff0c;都可以实现类似的效果…

halcon中阈值分割算子用法

1.threshold(Image : Region : MinGray, MaxGray : )&#xff1a;通过给定的阈值区间对图像进行分割 效果图&#xff1a; read_image (Audi2, audi2) fill_interlace (Audi2, ImageFilled, odd) threshold (ImageFilled, Region, 0, 90) 2.binary_threshold(Image : Region : …

De-interlace 反交错 简介

<script type"text/javascript"> </script> <script type"text/javascript"> </script> 为了更好的理解新的逐行扫瞄的概念&#xff0c;必须先弄清楚电视传输的一些基本知识&#xff0c;一副图像是如何传输的&#xff0c;它与新的…

pygame加载png出现known incorrect sRGB,Interlace handling should be turned on when using png_read_image问题

使用pygame加载png出现libpng warning: iCCP: known incorrect sRGB profile和Interlace handling should be turned on when using png_read_image警告的问题 一、解决Interlace handling should be turned on when using png_read_image警告 最近使用Python实现强化学习走迷…

计算机视觉之旅(Day3)

对不起大家&#xff0c;opencv的坑我尽量在年底更完&#xff0c;C的坑已经基本更完了&#xff0c;在没有进一步深入学习C之前可能这个系列已经算完了。不多说&#xff0c;我看看机器视觉的基本内容吧。 &#xff08;一&#xff09;基本构成 传统的机器视觉系统是由待测目标、…

交错(拉丝)(Interlace) 与 反胶卷过带

第一部分——交错&#xff08;拉丝&#xff09;&#xff08;Interlace&#xff09;的产生 引用了相当多网友的分析与结论&#xff0c;恕我不能依次注明。分析主要来自“[SilkyBible] 视频知识系列”&#xff0c;就主要概念的主要影响因素进行了一点分析。如果有错误&#xff0c…

二分法之最大子段和

1.问题描述&#xff1a;给定一个数组&#xff0c;找出其中可以构成最大数的子段&#xff0c;子段和是由连续的子段构成的&#xff1b;给定有n个整数(可能为负整数)组成的序列a1,a2,...,an,求该序列连续的子段和的最大值。 2.设计思路&#xff1a;对于一个连续的子段和&#xf…

java动态规划求最大子段和_动态规划-最大子段和

2018-01-14 21:14:58 一、最大子段和问题 问题描述&#xff1a;给定n个整数(可能有负数)组成的序列a1&#xff0c;a2&#xff0c;...&#xff0c;an&#xff0c;求该序列的最大子段和。如果所有整数都是负数&#xff0c;那么定义其最大子段和为0。 方法一、最大子段和的简单算法…

四种方法求解最大子段和问题

题目描述 给定一段长度为n的序列&#xff0c;我们需要找到其中一个连续的子段&#xff0c;使这个子段中各个元素加和最大&#xff0c;如果这个数组中全为负整数&#xff0c;我们就定义这个子段和为0. 题目分析 首先我们的目的是找一个局部的子段但加和是全局最大&#xff0c;…

最大子段和问题(分治法和动态规划)

什么是最大子段和&#xff0c;通俗点讲&#xff1a; 最大子段和就是给了一些数&#xff0c;然后你从中找了几个连续的数&#xff0c;这组连续的数的和比任意一组连续的数的和都大&#xff0c;那么你找的这几个连续的数的和就是这些数的最大子段和。 通俗的听不懂你就看这里&am…

最大子段求和

3种算法&#xff1a;最大子段求和 一、问题分析 问题&#xff1a;给定有n个整数(可能为负整数)组成的序列 a 1 , a 2 , . . . , a n , a_1,a_2,...,a_n, a1​,a2​,...,an​,求该序列连续的子段和的最大值。 如果该子段的所有元素和是负整数时定义其最大子段和为0。 简易算法…

最大子段和问题(3种方法)

给定由n个整数(可能为负整数)组成的序列a1&#xff0c;a2&#xff0c; a3… &#xff0c; an&#xff0c; 寻找它的某个连续子段&#xff0c;使得其和最大。例如( -2,11,-4,13,-5,-2 )最大子段是{ 11,-4,13 }其和为20。 1、最大字段和问题的简单算法 (1)枚举法求解&#xff1…

最大子段和(动态规划算法)

最大子段和&#xff08;动态规划算法&#xff09; 文章目录 最大子段和&#xff08;动态规划算法&#xff09;一、思路二、伪代码三、C代码四、输入实例 一、思路 D[i]表示从i开始的最大字段和。&#xff08;但我们不是从前往后找字段结束位置&#xff09; 根据递推公式&#x…

最大子段和——用蛮力算法,分治策略,动态规划算法三种求法(C语言)

目录 一、题目 二、算法求解 1、蛮力算法 伪代码 算法分析 程序 2、分治策略 伪代码 算法分析 程序 3、动态规划算法 伪代码 算法分析 程序 一、题目 设A<a1,a2,...,an>是n个整数的序列&#xff0c;称<ai,....,aj>为该序列的连续子序列&#xff0c;其…

归并排序 java实现_java实现归并排序

归并排序 归并排序&#xff0c;指的是将两个已经排序的序列合并成一个序列的操作。 归并操作的过程如下&#xff1a; 申请空间&#xff0c;使其大小为两个已经排序序列之和&#xff0c;该空间用来存放合并后的序列 设定两个指针&#xff0c;最初位置分别为两个已经排序序列的起…

Java八大算法:归并排序

一、什么是归并排序&#xff1f; 1.概念 归并排序&#xff08;Merge sort&#xff09;是建立在归并操作上的一种有效的排序算法&#xff0c;归并排序对序列的元素进行逐层折半分组&#xff0c;然后从最小分组开始比较排序&#xff0c;合并成一个大的分组&#xff0c;逐层进行…