已知两圆圆心坐标及半径求两圆交点 (C语言|参数方程求解)

在一个二维平面上给定两个圆的圆心横纵坐标、半径共6个参数, 求交点. 这个问题无非是解二元二次方程组.普通二元二次方程联立消元求解的困难在于, 中间过程里的系数会变得非常复杂, 从而导致容易出错—因为公式毕竟还是要人来推导,人的出错率比计算机要高得多得多—改用圆的参数方程求解, 可以在显著地减轻这个负担.
现在谈谈这问题的求解过程. 选择圆的参数方程的好处是方程是一次的, 化简方便, 虽然是三角函数方程并且既有正弦也有余弦, 不过到最后可以很方便地求出来.
(下面分析中x^y表示x的y次方)
大家还记得圆的参数方程吧, 圆心 (x0, y0), 半径为 r 的圆的参数方程是:
x = r * cosθ + x0
y = r * sinθ + y0
假设现在两圆参数x1, y1, r1, x2, y2, r2(这些分别表示, 咳, 有谁看不出来它们分别表示什么吗?), 设交点为 (x, y), 代入其中一个圆中的参数方程有
x = r1 * cosθ + x1 且 y = r1 * sinθ + y1
代入另一圆的标准方程, 得到
(r1 * cosθ + x1 - x2)^2 + (r1 * sinθ + y1 - y2)^2 = r2^2
是的, 看起来有关于正余弦二次项, 不过不要惊慌, 展开合并同类项之后, 正好这两项会合并成常数:
左边 = (r1 * cosθ)^2 + (r1 * sinθ)^2 + 2 * r1 * (x1 - x2) * cosθ + 2 * r1 * (y1 - y2) * sinθ
= r2^2 - (x1 - x2)^2 - (y1 - y2)^2 = 右边
这样就好办了, 把 r1^2 转移到等式右边, 令:
a = 2 * r1 * (x1 - x2)
b = 2 * r1 * (y1 - y2)
c = r2^2 - r1^2 - (x1 - x2)^2 - (y1 - y2)^2
那么方程便成为:
a * cosθ + b * sinθ = c
用 (1 - (cosθ)^2)^(1 / 2) 表示sinθ, 令:
p = a^2 + b^2
q = -2 * a * c
r = c^2 - b^2
便化为一个一元二次方程, 解得:
cosθ = (±(q^2 - 4 * p * r)^(1 / 2) - q) / (2 * p)
然而到此为止还没有结束, 因为刚才将三角方程转化为二次方程时, 等式两边平方了一次, 如果直接这样求对应角的正弦值, 符号总会为正.为了将纵坐标正确解出, 必须变角. 那么如何变角?方法当然很多, 诱导公式, 或者反过头去把方程变一下, 以正弦作为未知数,但是这些方法都比较复杂. 在这里可以选择另一种方案, 那就是用验证代替求解: 验证所得的解是不是根, 如果不是, 将纵坐标反号便可以了.最后注意一下两解的横坐标相同的情况, 这样要先输出正的再输出负的.

下面上代码
#include<math.h> // sqrt fabs// 点
struct point_t {double x, y;
};// 圆
struct circle_t {struct point_t center;double r;
};// 浮点数判同
int double_equals(double const a, double const b)
{static const double ZERO = 1e-9;return fabs(a - b) < ZERO;
}// 两点之间距离的平方
double distance_sqr(struct point_t const* a, struct point_t const* b)
{return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
}// 两点之间的距离
double distance(struct point_t const* a, struct point_t const* b)
{return sqrt(distance_sqr(a, b));
}/*
* 两圆相交函数
* 参数:
*    circles[0] 和 circles[1] 分别是两个圆.
*    points[0] 和 points[1] 用来存放交点数值, 虽然有些情况下两个不都会用上;
*        如果用到了两个交点, 那么返回后, 横坐标大的在前, 如果横坐标一样, 则纵坐标大的在前.
* 返回值:
*    -1 如果两个圆一模一样;
*    其它整数值: 交点个数.
*/
int insect(struct circle_t circles[], struct point_t points[])
{double d, a, b, c, p, q, r; // a, b, c, p, q, r 与上面分析中的量一致double cos_value[2], sin_value[2]; // 交点的在 circles[0] 上对应的正余弦取值// 余弦值 cos_value 就是分析中的 cosθif (double_equals(circles[0].center.x, circles[1].center.x)&& double_equals(circles[0].center.y, circles[1].center.y)&& double_equals(circles[0].r, circles[1].r)) {return -1;}d = distance(&circles[0].center, &circles[1].center); // 圆心距离if (d > circles[0].r + circles[1].r|| d < fabs(circles[0].r - circles[1].r)) {return 0;}a = 2.0 * circles[0].r * (circles[0].center.x - circles[1].center.x);b = 2.0 * circles[0].r * (circles[0].center.y - circles[1].center.y);c = circles[1].r * circles[1].r - circles[0].r * circles[0].r- distance_sqr(&circles[0].center, &circles[1].center);p = a * a + b * b;q = -2.0 * a * c;// 如果交点仅一个if (double_equals(d, circles[0].r + circles[1].r)|| double_equals(d, fabs(circles[0].r - circles[1].r))) {cos_value[0] = -q / p / 2.0;sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;// 在这里验证解是否正确, 如果不正确, 则将纵坐标符号进行变换if(!double_equals(distance_sqr(&points[0], &circles[1].center),circles[1].r * circles[1].r)) {points[0].y = circles[0].center.y - circles[0].r * sin_value[0];}return 1;}r = c * c - b * b;cos_value[0] = (sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;cos_value[1] = (-sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);sin_value[1] = sqrt(1 - cos_value[1] * cos_value[1]);points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;points[1].x = circles[0].r * cos_value[1] + circles[0].center.x;points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;points[1].y = circles[0].r * sin_value[1] + circles[0].center.y;// 验证解是否正确, 两个解都需要验证.if (!double_equals(distance_sqr(&points[0], &circles[1].center),circles[1].r * circles[1].r)) {points[0].y = circles[0].center.y - circles[0].r * sin_value[0];}if (!double_equals(distance_sqr(&points[1], &circles[1].center),circles[1].r * circles[1].r)) {points[1].y = circles[0].center.y - circles[0].r * sin_value[1];}// 如果求得的两个点坐标相同, 则必然其中一个点的纵坐标反号可以求得另一点坐标if (double_equals(points[0].y, points[1].y)&& double_equals(points[0].x, points[1].x)) {if(points[0].y > 0) {points[1].y = -points[1].y;} else {points[0].y = -points[0].y;}}return 2;
}

NP 问题的启示
NP 问题教导我们, 验证比求解要简单! 虽然这一道题, 无论怎么看, 都是一个普通的 P 问题, 但是我们还是可以贯彻这一思想, 用最简易的手法获得答案.
一个完整的程序:

[cpp] view plaincopy
<span style="font-family:SimSun;">#include<stdio.h>
#include<math.h>  struct point_t {  double x, y;
};  struct circle_t {  struct point_t center;  double r;
};  int double_equals(double const a, double const b)
{  static const double ZERO = 1e-9;  return fabs(a - b) < ZERO;
}  double distance_sqr(struct point_t const* a, struct point_t const* b)
{  return (a->x - b->x) * (a->x - b->x) + (a->y - b->y) * (a->y - b->y);
}  double distance(struct point_t const* a, struct point_t const* b)
{  return sqrt(distance_sqr(a, b));
}  int insect(struct circle_t circles[], struct point_t points[])
{  double d, a, b, c, p, q, r;  double cos_value[2], sin_value[2];  if (double_equals(circles[0].center.x, circles[1].center.x)  && double_equals(circles[0].center.y, circles[1].center.y)  && double_equals(circles[0].r, circles[1].r)) {  return -1;  }  d = distance(&circles[0].center, &circles[1].center);  if (d > circles[0].r + circles[1].r  || d < fabs(circles[0].r - circles[1].r)) {  return 0;  }  a = 2.0 * circles[0].r * (circles[0].center.x - circles[1].center.x);  b = 2.0 * circles[0].r * (circles[0].center.y - circles[1].center.y);  c = circles[1].r * circles[1].r - circles[0].r * circles[0].r  - distance_sqr(&circles[0].center, &circles[1].center);  p = a * a + b * b;  q = -2.0 * a * c;  if (double_equals(d, circles[0].r + circles[1].r)  || double_equals(d, fabs(circles[0].r - circles[1].r))) {  cos_value[0] = -q / p / 2.0;  sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);  points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;  points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;  if (!double_equals(distance_sqr(&points[0], &circles[1].center),  circles[1].r * circles[1].r)) {  points[0].y = circles[0].center.y - circles[0].r * sin_value[0];  }  return 1;  }  r = c * c - b * b;  cos_value[0] = (sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;  cos_value[1] = (-sqrt(q * q - 4.0 * p * r) - q) / p / 2.0;  sin_value[0] = sqrt(1 - cos_value[0] * cos_value[0]);  sin_value[1] = sqrt(1 - cos_value[1] * cos_value[1]);  points[0].x = circles[0].r * cos_value[0] + circles[0].center.x;  points[1].x = circles[0].r * cos_value[1] + circles[0].center.x;  points[0].y = circles[0].r * sin_value[0] + circles[0].center.y;  points[1].y = circles[0].r * sin_value[1] + circles[0].center.y;  if (!double_equals(distance_sqr(&points[0], &circles[1].center),  circles[1].r * circles[1].r)) {  points[0].y = circles[0].center.y - circles[0].r * sin_value[0];  }  if (!double_equals(distance_sqr(&points[1], &circles[1].center),  circles[1].r * circles[1].r)) {  points[1].y = circles[0].center.y - circles[0].r * sin_value[1];  }  if (double_equals(points[0].y, points[1].y)  && double_equals(points[0].x, points[1].x)) {  if (points[0].y > 0) {  points[1].y = -points[1].y;  } else {  points[0].y = -points[0].y;  }  }  return 2;
}  int main()
{  struct circle_t circles[2];  struct point_t points[2];  printf("请输入两圆x,y,半径(以逗号分开):");  while (EOF != scanf("%lf,%lf,%lf,%lf,%lf,%lf",  &circles[0].center.x, &circles[0].center.y, &circles[0].r,  &circles[1].center.x, &circles[1].center.y, &circles[1].r)) {  switch (insect(circles, points)) {  case -1:  printf("THE CIRCLES ARE THE SAME/n");  break;  case 0:  printf("NO INTERSECTION/n");  break;  case 1:  printf("(%.3lf %.3lf)\n", points[0].x, points[0].y);  break;  case 2:  printf("(%.3lf %.3lf) (%.3lf %.3lf)\n",  points[0].x, points[0].y,  points[1].x, points[1].y);  }  }  return 0;
}
</span>  

已知两圆圆心坐标及半径求两圆交点 (C语言|参数方程求解)相关推荐

  1. 转 已知两点坐标和半径求圆心坐标程序C++

    数学思想:利用圆方程和直线方程 已知两点坐标和半径求圆心坐标程序 #include <iostream> #include <fstream> #include <cma ...

  2. 两圆圆心距离计算及位置关系判断(C++实现)

    实验目的 学习友元函数的定义与调用,理解友元函数的意义. 实验原理 友元函数时在类中用关键字 friend修饰的函数,是类的非成员函数,但是它可以通过对象名访问类的私有和保护成员 利用圆心距与两圆半径 ...

  3. 分别已知两直线上的两点,求两直线交点

    分别已知两直线上的两点,求两直线交点 求两直线的交点是初中数学的简单问题了,在直角坐标系中直线有很多种表示方式.同时我们知道两点确定一条直线,已知两点坐标自然能求出直线坐标,已知两直线坐标自然能求出两 ...

  4. 在平面内,已知矩形的中心点坐标、长、宽和倾斜角度,求矩形四个角点的坐标

    实现思路: 1.已知矩形的中心点坐标.长和宽,求矩形在不旋转的情况下矩形的四个顶点坐标: 2.再求按逆时针旋转一定角度后的四个点坐标: (在平面内,已知一个矩形的四个角坐标,将矩形绕中心点转动一个角度 ...

  5. 已知三角形三点坐标, 求三角形的面积

    摘自:http://blog.sina.com.cn/s/blog_4cddcaa3010008u7.html 已知三角形三点坐标, 求三角形的面积 发表时间:2004-8-10 作者:未知[获得此文 ...

  6. 据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高,请你计算其标准体重应该是多少?(顺便也悄悄给自己算一下吧……)

    #include<stdio.h> int main() {     double H;     double weight; scanf("%lf",&H); ...

  7. C语言练习题:据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。已知市斤的数值是公斤数值的两倍。现给定某人身高,请你计算其标准体重应该是多少?

    题目内容: 据说一个人的标准体重应该是其身高(单位:厘米)减去100.再乘以0.9所得到的公斤数.已知市斤的数值是公斤数值的两倍.现给定某人身高,请你计算其标准体重应该是多少?(顺便也悄悄给自己算一下 ...

  8. 已知点的经纬度坐标计算/读取DEM高程信息/海拔高度

    已知点的经纬度坐标计算/读取DEM高程信息/海拔高度 思路 环境 依赖 安装GDAL 安装依赖包 测试GDAL 数据依赖 python代码 参考 思路 实现条件 1.GDAL库 2.DEM数据 开发语 ...

  9. 已知三角形三边长求面积java_已知三角形三点坐标求三角形面积.java

    已知三角形三点坐标求三角形面积 主程序代码如下: import java.util.*; public class Tringle { public static void main(String[] ...

最新文章

  1. Python是不是被严重高估了(转载)
  2. 简简单单的正则表单验证练习
  3. java的初始,Java初始
  4. C++直接初始化与复制初始化的区别深入解析
  5. Java 版本、语言规范、API、JDK、IDE、Java 源程序编译、执行原理(跨平台性根本原因)、特殊字符用法、8 大数据类型小结
  6. Java之设计模式详解 (转)
  7. SQL之SQL99语法 没错就这么简单
  8. 使用Sencha cmd安装extjs6
  9. 墨画子卿第三章第8节:第三元素
  10. MATLAB 图像处理 将图层随机组合合成图片
  11. Linux中的preempt_count
  12. iPhone12或再引领轻薄时尚风潮,半斤机将被抛弃
  13. 阿里巴巴大数据之路-维度设计
  14. ios 裁剪框大小_ios 图片裁剪修改尺寸的方法总结
  15. seacms_locoy.php,seacms_v6.6
  16. Python中ArcPy读取Excel表格数据创建矢量要素图层并生成属性表字段与内容
  17. promise.then返回结果几种情况
  18. VS2017 新建项目没有MFC项目选项
  19. 6.Spring学习笔记_Bean之间的关系 (by尚硅谷_佟刚)
  20. python 判断节假日,Python3自动签到 定时任务 判断节假日的实例

热门文章

  1. Anaconda 安装清华源文件
  2. Matlab+YALMIP+CPLEX解决带储能的微电网调度优化
  3. 数学建模workflow
  4. 虚拟化技术KVM和XEN概述
  5. Linux -- 银河麒麟如何开通 snmp
  6. 什么是模拟IC设计?
  7. 几种常见无线摄像头的传输距离比较
  8. (Web of Science)SCI论文检索教程
  9. oracle数据库序列码,oracle 数据库中的序列
  10. 老项目复盘:抖音老照片修复项目思路分享