最近想画两球水滴效果所有在网上找两圆外切点和内切点的算法,找了很久没有找到所以自己写了一个工具类来计算两圆的公切线点。具体效果如下图:

根据CircleUtils类的getCircleTangentPointOut方法返回外切点坐标[r1p1, r1p2, r2p1, r2p2],依次为左边圆的两个切点坐标和右边两个切点坐标。

根据CircleUtils类的getCircleTangentPointIn方法返回外切点坐标[r1p1, r1p2, r2p1, r2p2],依次为左边圆的两个切点坐标和右边两个切点坐标。

根据获取坐标绘制线段和点,如下代码

@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);mPaint.setColor(0XFF00FF00);mPaint.setStyle(Paint.Style.FILL);float r1 = 300;float r2 = 200;canvas.drawCircle(mDownX, mDownY, r1, mPaint);canvas.drawCircle(mCurrentX, mCurrentY, r2, mPaint);PointF[] points2 = CircleUtils.getCircleTangentPointOut(new PointF(mDownX, mDownY), r1, new PointF(mCurrentX, mCurrentY), r2);if (points2 != null) {mPaint.setColor(0XFF0000FF);mPaint.setStyle(Paint.Style.STROKE);canvas.drawLine(points2[0].x, points2[0].y, points2[2].x, points2[2].y, mPaint);canvas.drawLine(points2[1].x, points2[1].y, points2[3].x, points2[3].y, mPaint);}PointF[] points1 = CircleUtils.getCircleTangentPointIn(new PointF(mDownX, mDownY), r1, new PointF(mCurrentX, mCurrentY), r2);if (points1 != null) {mPaint.setColor(0XFF0000FF);mPaint.setStyle(Paint.Style.STROKE);canvas.drawLine(points1[0].x, points1[0].y, points1[3].x, points1[3].y, mPaint);canvas.drawLine(points1[1].x, points1[1].y, points1[2].x, points1[2].y, mPaint);}if (points2 != null) {mPaint.setColor(0XFFFF0000);mPaint.setStyle(Paint.Style.FILL);for (PointF p : points2) {canvas.drawCircle(p.x, p.y, 5, mPaint);}}if (points1 != null) {mPaint.setColor(0XFFFF0000);mPaint.setStyle(Paint.Style.FILL);for (PointF p : points1) {canvas.drawCircle(p.x, p.y, 5, mPaint);}}}

CircleUtils工具类如下代码


public class CircleUtils {//返回两圆外切点坐标public static PointF[] getCircleTangentPointOut(PointF c1, float r1, PointF c2, float r2){float centerLine = getPointDistance(c1, c2);if(centerLine > Math.abs(r1-r2)){//计算外切PointF[] points = new PointF[8];//圆心连线与圆1的交点PointF r1Point = ratioPoint(c1, c2, r1/centerLine);points[6] = r1Point;//圆心连线与圆2的交点PointF r2Point = ratioPoint(c1, c2, (centerLine-r2)/centerLine);points[7] = r2Point;//两元交点连线和两圆焦点在左边圆的角度float angleR1 = getAngle(r1, centerLine, r2);//两元交点连线和两圆焦点在右边圆的角度float angleR2 = getAngle(r2, centerLine, r1);//外切线与圆心连线的角度(0~90度之间的角度)float angle = (float) Math.acos(Math.abs(r1-r2)/centerLine);//两圆的交点points[4] = rotatePoint(r1Point, c1, angleR1);points[5] = rotatePoint(r2Point, c2, angleR2);if(r1>=r2){//切线与第一个圆的交点points[0] = rotatePoint(r1Point, c1, angle);points[1] = rotatePoint(r1Point, c1, -angle);//切线与第二个圆的交点points[2] = rotatePoint(r2Point, c2, -(float) (Math.PI-angle));points[3] = rotatePoint(r2Point, c2, (float) (Math.PI-angle));}else{//切线与第一个圆的交点points[0] = rotatePoint(r1Point, c1, (float) (Math.PI-angle));points[1] = rotatePoint(r1Point, c1, -(float) (Math.PI-angle));//切线与第二个圆的交点points[2] = rotatePoint(r2Point, c2, -angle);points[3] = rotatePoint(r2Point, c2, angle);}return points;}return null;}//返回两圆内切点坐标public static PointF[] getCircleTangentPointIn(PointF c1, float r1, PointF c2, float r2){float centerLine = getPointDistance(c1, c2);if(centerLine > r1+r2){//计算内切PointF[] points = new PointF[7];//内切线焦点points[4] = new PointF((c1.x*r2+c2.x*r1)/(r1+r2), (c1.y*r2+c2.y*r1)/(r1+r2));float l1 = centerLine*r1/(r1+r2);float l2 = centerLine*r2/(r1+r2);//圆心连线与圆1的交点points[5] = ratioPoint(c1, points[4], r1/l1);float angle = (float) Math.acos(r1/l1);//第1个圆的切点points[0] = rotatePoint(points[5], c1, angle);points[1] = rotatePoint(points[5], c1, -angle);//圆心连线与圆2的交点points[6] = ratioPoint(points[4], c2, (l2-r2)/l2);//第2个圆的切点points[2] = rotatePoint(points[6], c2, -angle);points[3] = rotatePoint(points[6], c2, angle);return points;}return null;}//根据点 a, b, c位置距离为ab, bc, ac获取b点在ac上的垂点d,返回垂点dpublic static PointF getVerticalPoint( PointF a, PointF b, PointF c){float ab =getPointDistance(a, b);float ac =getPointDistance(a, c);float bc =getPointDistance(b, c);return getVerticalPoint(ab, ac, bc, a, c);}public static PointF getVerticalPoint(float ab,float ac, float bc, PointF a, PointF c){float angle = getAngle(ab, ac, bc);float ratio = (float) (Math.cos(angle)*ab)/ac;return ratioPoint(a, c, ratio);}//返回两点之间的距离public static float getPointDistance(PointF a, PointF b){return (float) Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y, 2));}//根据点 a, b, c位置距离为ab, bc, ac获取a点角度public static float getAngle(float ab,float ac, float bc){return (float) Math.acos((ab*ab+ac*ac-bc*bc)/(2*ab*ac));}//获取一个点,起始点到该点长度除以起始点到结束点长度的比例为ratiopublic static PointF ratioPoint(PointF startPoint, PointF endPoint, float ratio){if(startPoint == null){startPoint = new PointF(0, 0);}PointF ret = new PointF();float x = endPoint.x-startPoint.x;float y = endPoint.y-startPoint.y;ret.x = x*ratio+startPoint.x;ret.y = y*ratio+startPoint.y;return ret;}//空间一个点围绕center点旋转angle角度后的位置public static PointF rotatePoint(PointF point, PointF center, float angle){if(center == null){center = new PointF(0, 0);}PointF ret = new PointF();//获取相对位置float x = point.x-center.x;float y = point.y-center.y;//根据选择矩阵旋转后加上中心点位置ret.x = (float) ((x*Math.cos(angle)-y*Math.sin(angle))+center.x);ret.y = (float) ((x*Math.sin(angle)+y*Math.cos(angle))+center.y);return ret;}
}

两圆的外切线与内切线的切点算法相关推荐

  1. VMware EXSI 配置两个网卡(外网和内网)

    近端时间被服务器之间通信卡住了,折腾了良久,总算是搞定了,这里记录一下一些坑. [背景] 服务器 使用VMware EXSI进行了虚拟化,服务器端登录界面类似如下: 登录进去,"F2&quo ...

  2. 两个圆公切线求法_两圆的公切线教案

    两圆的公切线教案 第一课时 两圆的公切线(一) 教学目标: (1)理解两圆相切长等有关概念,掌握两圆外公切线长的求法: (2)培养学生的归纳.总结能力: (3)通过两圆外公切线长的求法向学生渗透&qu ...

  3. c++ 判断两圆位置关系

    对于两圆的位置一般有五种关系: (1) 外离:两圆的半径之和小于两圆圆心距离 (2) 外切:两圆的半径之和等于两圆圆心距离 (3) 相交:两圆的半径之和大于两圆圆心距离,两圆圆心距离大于两圆半径之差 ...

  4. 笔记本配置两个网络同时上外网和内网

    一般的工作环境中,最常用的办公模式还是内网办公.嗯,为了安全嘛,但是关键特么整个网络都是内网的.作为一个拷贝忍者,这让我十分痛苦,大家应该都懂磨磨蹭蹭用手机百度的痛了.有的公司好一点点,会给你一个代理 ...

  5. js求两圆交点_利用二项式通项公式求系数及综合运用(2)

    更多资料获取,添加qq群:639636957 更多精彩,请点击上方蓝字关注我们! 二项式通项公式的基本应用 1 题目 2 视频讲解 3 答案 4 知识点 往期视频汇总 每日一题第1题之数列对数型不等式 ...

  6. js求两圆交点_如何求两个圆的交点坐标,请举例

    展开全部 将两个圆62616964757a686964616fe4b893e5b19e31333431363563的方程相减,就消掉了x²,y²项,剩下一个关于x, y的一次方程,可解得y=kx+b. ...

  7. 两个圆公切线求法_求两圆的公切线计算

    关于两圆的公切线计算我们首先需要搞清楚的是两个圆之间有哪些位置关系,两个圆的位置包括内含.内切.外切.外离几种方式,可以看出位置关系可以根据"两圆心之间的距离"与"两圆半 ...

  8. 两圆重叠问题你会求解吗?这个问题的准确答案,德国数学家最近才找到

    萧箫 发自 凹非寺 量子位 报道 | 公众号 QbitAI 先来看一道简单的几何问题: 下图中,黑圆恰好将红圆的面积等分,且黑圆的圆心恰好在红圆上.假设红圆半径为R,黑圆半径为r,求r. 是不是感觉已 ...

  9. Java设计一个类代表二维空间的一个点,设计一个类代表二维空间的一个圆,计算面积,,并写程序验证计算一个点(Point对象)是否在圆(Cricle对象)内

    题目要求: (1) 设计一个类代表二维空间的一个点 (2) 设计一个类代表二维空间的一个圆.要求两个成员变量.一个是圆心,一 个是半径,提供计算面积的方法. (3) 为上述Cricle类添加一个方法, ...

最新文章

  1. 有关java的一些话
  2. 11gR2游标共享新特性带来的一些问题以及_cursor_features_enabled、_cursor_obsolete_threshold和106001 event...
  3. element el-input 自动获取焦点和IE下光标位置解决方法
  4. Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射
  5. ORA-28001: the password has expired (DBD ERROR: OCISessionBegin)解决办法
  6. 操作系统ppt_华为车BU王军:华为三大汽车操作系统,及跨域集成软件框架(内含PPT)...
  7. TensorFlow教程之API DOC 6.3.10. NN
  8. bsxfun 的理解
  9. Winform 窗体关闭事件
  10. C语言学习之用函数求立方体的体积
  11. 同花顺 行情服务器系统,[分享]完美运行同花顺,Linux下的股友有福了
  12. PTP(IEEE1588),TSN时间同步方法
  13. 短视频的海绵宝宝配音怎么制作?这可能是最容易上手的配音教程
  14. IT:后端进阶技术路线图(初级→中级→高级)、后端开发工程师(技术方向分类之后台业务开发/中间件/内核/分布式架构)基础知识简介、技术路线/技术趋势指南(如何选择自己的技术方向)之详细攻略
  15. html5 canvas画椭圆形
  16. 传奇GOM引擎-GEE引擎版本如何添加GM账号刷装备
  17. C#操作Excel总结(最全面的操作EXCEL技巧汇总)
  18. 人工智能机器学习 路线
  19. HDU 5730 Shell Necklace
  20. 用python控制钉钉软件_python 调用钉钉机器人的方法

热门文章

  1. java程序作弄别人_我的世界:作弄基友,戏耍熊孩子?家中常备红石陷阱,谁来谁遭殃!...
  2. C语言比较两个数的大小,输出较大的数
  3. 微信赌场——H5棋牌游戏渗透之旅
  4. 棋牌游戏支付接口H5支付宝微信
  5. 掌握销售谈判三大策略,开单成功率提升60%!
  6. 启动Solr 8.10 后访问UI报错:CoreContainer is either not initialized or shutting down.
  7. Proteus内部编程仿真STM32(附程序)
  8. 走出996困境:产权、通证与生产力 |链捕手
  9. 开始尝试淘宝直通车推广
  10. 企业数字化转型saas电商系统(已开源)