主要是注意所使用的数据类型。

之前用的是float,出现了一些意外,而且花费了我不少时间来反复验证、推导,

做了很多的无用功,而且,反复推导得出来的计算步骤并没有什么不牢靠的地方。

然后计算得到的结果却是让人如此之不省心,梗的我闷得慌。

今天上午发来了一贴,多位朋友各抒己见,

总算是让我发现了一些不足的地方,首当其冲的是一个变量弄错了,

导致大批的计算失准。

后来修正了这个bug以后,还是会出现计算不精确的地方。

再后来便将涉及的所有成员变量由float 纠正为 double 类型,

计算精度果然得到了提高,失准的地方再次被干掉。

这次给自己的教训就是:

涉及到精度比较高的数值运算的时候,还是得统统用 double。

之前还以为 float 已经比较不错,能够满足基本的需求了,

经过这次我总算是懂了,double的存在离我并不遥远。

这个问题堵了我比较久了,大概也有快10个月了,当时没解决就规避之没去用了,

今天能够解决这个遗留已久的问题,真是让人心情愉快!

下面贴出 Objective-C 和 Java 的相关代码:

Objective-C 部分(核心代码摘录)

/** 已知两点,求过该两点的直线表达式~ */
- (BYLine) getLine:(b2Vec2)p1 anotherPoint:(b2Vec2)p2 {BYLine line;if((p1.x - p2.x) != 0) {line.kExists = true;line.k = (p1.y - p2.y) / (p1.x - p2.x);line.b = p1.y - line.k * p1.x;} else {line.kExists = false;line.extraX = p1.x;}return line;
}
/** 已知一点和直线斜率,求该直线的表达式~ */
- (BYLine) getLine:(b2Vec2)point kParam:(double)kParam {BYLine line;line.kExists = true;line.k = kParam;line.b = point.y - kParam * point.x;return line;
}
- (double) getDistanceBetween2Points:(b2Vec2)p0 anotherPoint:(b2Vec2)p1 {return sqrt(pow(p0.y - p1.y, 2) + pow(p0.x - p1.x, 2));
}
/** 获取一条直线上距离某点一定距离的两个点~ */
- (b2Vec2*) get2Points:(BYLine)ln p:(b2Vec2)point pw:(double)pathWidth {b2Vec2* target = new b2Vec2[2];double circleRadius = pathWidth / 2;if(ln.k != 0) {// 斜率存在且不为 0~double kOfNewLine = -1 / ln.k;BYLine newLine = [self getLine:point kParam:kOfNewLine];// 经过数学运算,得出二元一次方程组的表达式double A = pow(newLine.k, 2) + 1;double B = 2 * (newLine.k * newLine.b - newLine.k * point.y - point.x);double C = pow(point.x, 2) + pow((newLine.b - point.y), 2) - pow(circleRadius, 2);double delta = pow(B, 2) - 4 * A * C;if(delta < 0) {    // 经实践检验有一定几率走入该分支,必须做特殊化处理~NSLog(@"竟然会无解,他妈的怎么回事儿啊!");target[0] = b2Vec2(point.x, point.y - circleRadius);target[1] = b2Vec2(point.x, point.y + circleRadius);} else {double x1 = (-B + sqrt(delta)) / (2 * A);double y1 = newLine.k * x1 + newLine.b;target[0] = b2Vec2(x1, y1);double x2 = (-B - sqrt(delta)) / (2 * A);double y2 = newLine.k * x2 + newLine.b;target[1] = b2Vec2(x2, y2);}} else {// 斜率存在且为 0~target[0] = b2Vec2(point.x, point.y - circleRadius);target[1] = b2Vec2(point.x, point.y + circleRadius);}NSLog(@"离中心点的距离为:%f", [self getDistanceBetween2Points:target[0] anotherPoint:point]);return target;
}
// 绘制触摸点到移动点的轨迹,1个像素~
- (void) drawTouchPath {if(_mouseDown) {// 已知(2等分,用分数表示~)b2Vec2 pStart = _touchSegment.p1;b2Vec2 pEnd = _touchSegment.p2;// 推出b2Vec2 pMiddle = b2Vec2((pStart.x + pEnd.x) / 2, (pStart.y + pEnd.y) / 2);float pathLength = [self getDistanceBetween2Points:pStart anotherPoint:pEnd];// 设置触摸轨迹的宽度~float pathWidth = pathLength / 3.0f;if(pathWidth > TOUCH_PATH_MAX_WIDTH) {pathWidth = TOUCH_PATH_MAX_WIDTH;}b2Vec2* result;BYLine expFunc = [self getLine:pStart anotherPoint:pEnd];if(expFunc.kExists) {   // 斜率存在~result = [self get2Points:expFunc p:pMiddle pw:pathWidth];} else {                // 斜率不存在~result = new b2Vec2[2];result[0] = b2Vec2(pMiddle.x - pathWidth / 2, pMiddle.y);result[1] = b2Vec2(pMiddle.x + pathWidth / 2, pMiddle.y);}b2Vec2 finalResult[5];finalResult[0] = pStart;finalResult[1] = result[0];finalResult[2] = pEnd;finalResult[3] = result[1];finalResult[4] = pStart;// 绘制白色内容物~glColor4f(1.0f, 1.0f, 1.0f, 1.0f);glVertexPointer(2, GL_FLOAT, 0, finalResult);glDrawArrays(GL_TRIANGLE_STRIP, 0, 5);}
}

Java 部分(部件齐全,能直接拿来跑的)

package org.bruce.vertices.controller.geometry;/*** @author BruceYang* 对点的抽象~*/
public class CGPoint {public double x;public double y;public CGPoint() {}public CGPoint(double x, double y) {this.x = x;this.y = y;}@Overridepublic String toString() {return "x=" + this.x + ", y=" + this.y;}
}

*****************************************************

package org.bruce.vertices.controller.geometry;/*** @author BruceYang* 这个是对通用一次直线方程 A*x + B*y + C = 0 的封装~* 本来封装的是斜截式,不过发现当斜率k不存在的时候会比较麻烦,因此该用一般式* 再个就是接着用一般式的演变方式 x + B/A*y + C/A = 0,但是考虑到可能存在x == 0 的情况,因此又舍弃~* * 娘的,一般式还是他妈的无济于事啊,改回斜截式,多提供两个成员变量:* 一个boolean表示k是否存在,一个额外的float表示k不存在的时候直线方程 x=***, *** 等于多少~*/
public class CGLine {// 特别声明为public类型,免得到时候访问的时候麻烦,到时候直接点就行了private boolean kExists;  // 大部分情况下 k 都应该是存在的,因此提供一个 true 的默认值~public double k = 77885.201314f;public double b = 13145.207788f;public double extraX = 52077.881314f;/*** 这是当 k 存在时的构造方法~* @param k* @param b*/public CGLine(double k, double b) {this.kExists = true;this.k = k;this.b = b;}/*** 已知两点,求直线的方程~* @param p1* @param p2*/public CGLine(CGPoint p1, CGPoint p2) {if((p1.x - p2.x) != 0) {CGDbg.println("y = k*x + b, k exits!!");this.kExists = true;this.k = (p1.y - p2.y)/(p1.x - p2.x);this.b = (p1.y - p1.x * k);} else {CGDbg.println("y = k*x + b, k doesn't exists!!");// 如果走进这个分支,表示直线垂直于x轴,斜率不存在,保留k的默认值~this.kExists = false;this.extraX = p1.x;}CGDbg.print("过p1("+p1.x+", " +p1.y + "), p2("+p2.x+", "+p2.y+")两点的直线方程表达式为: ");if(kExists) {CGDbg.println("y = " + k + "*x + " + b);} else {CGDbg.println("x = " + extraX + "(垂直于x轴!)");}}/*** 点斜式~* @param p    某点* @param k   过该点的直线的斜率*/public CGLine(double k, CGPoint p) {/*** (y-y') = k*(x-x')* 变形成斜截式为:* y = k*x + y' - k*x'* k = k, b = y'-k*x'*/this.kExists = true;this.k = k;this.b = p.y - k * p.x;}/*** 这是当 k 不存在时的构造方法~* @param extraX*/public CGLine(double extraX) {this.kExists = false;this.extraX = extraX;}@Overridepublic String toString() {return "Line.toString()方法被调用,y = k*x + b斜截式, k=" + this.k + ", b=" + this.b + ", kExists=" + this.kExists + ", extraX=" + this.extraX;}public boolean iskExists() {return kExists;}public void setkExists(boolean kExists) {this.kExists = kExists;}
}

*****************************************************

package org.bruce.vertices.controller.geometry;/*** @author Bruce Yang* 用于打印调试~*/
public class CGDbg {public static final boolean DEBUG_MODE = true;// 方便进行调试信息的输出,开关~public static void println(Object info) {if(DEBUG_MODE) {           System.out.println(info);}}public static void print(Object info) {if(DEBUG_MODE) {          System.out.print(info);}}
}

*****************************************************

package org.bruce.vertices.controller.geometry;/*** @author BruceYang*/
public class CGGeometryLib {/*** @param p0 第一个点的坐标* @param p1 第二个点的坐标* @return       两个点之间的距离* 计算出两点之间的距离*/public static double getDistanceBetween2Points(CGPoint p0, CGPoint p1) {double distance = Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));return distance;}/*** @param p* @param l* @return       该方法用于获取某点在某条直线上的投影点的坐标*/public static CGPoint getProjectivePoint(CGPoint p, CGLine l) {CGPoint target = null;if(l.iskExists()) {if(l.k != 0) {CGLine newLine = new CGLine(-1/l.k, p.y -(-1/l.k)*p.x);target = getCrossPoint(l, newLine);} else {    // 如果直线l的斜率存在且斜率的值为0,明显是一条平行于x轴的直线~// 此时,点 p 到直线 l 的距离为:Math.abs(p.y-l.b)target = new CGPoint(p.x, l.b);}} else { // 如果直线l的斜率不存在,明显是一条垂直于x轴的直线~// 此时,点 p 到直线 l 的距离为:Math.abs(p.x-l.extraX)target = new CGPoint(l.extraX, p.y);}CGDbg.println("点 ("+p.x+", "+p.y+") 在直线:y="+l.k+"x+"+l.b+" 上的投影点为 ("+target.x+", "+target.y+")");return target;}/*** 该方法用于求出两条直线的交点坐标* 这个方法是定制的,只有 l1, l2 均存在斜率 k 时方能使用(限制取消)~* @param l1* @param l2* @return*/public static CGPoint getCrossPoint(CGLine l1, CGLine l2) {
//      dbgPrintln("into the getCrossPoint, l1: " + l1);
//      dbgPrintln("into the getCrossPoint, l2: " + l2);double x, y;if(l1.iskExists() && l2.iskExists()) {x = (l2.b - l1.b) / (l1.k - l2.k);y = l1.k * x + l1.b;} else if(!l1.iskExists() && l2.iskExists()) {x = l1.extraX;y = l2.k * x + l2.b;} else if(l1.iskExists() && !l2.iskExists()) {x = l2.extraX;y = l1.k * x + l1.b;} else {// 两条直线的斜率都不存在?!,不可能发生的情况!!x = 0;y = 0;}CGDbg.println("getCrossPoint, CGPoint(x=" + x + ", y=" + y + ")");return new CGPoint(x, y);}/*** @param args* 怎样判断是否符合要求?将过每组3个点中除开多边形顶点的两个点的直线方程求出来* 比较求出的 4 个 候选圆心点 哪个与此直线离的比较近,哪个就是符合要求的圆心点* 以下方法用于获取离特定直线距离最近的一个点(目前只支持斜率k存在的直线,以后慢慢扩充)!* 要得到距离特定直线距离最远的一个点只要稍作改动即可!*/public static CGPoint getNearestPoint(CGPoint[] points, CGLine line) {double minDistance = 0;int minIndex = 0;if(line.iskExists()) {// 直线斜率存在的分支~for(int i = 0; i < points.length; ++ i) {CGPoint p = points[i];double d = Math.abs(line.k*p.x-p.y+line.b)/Math.sqrt(Math.pow(line.k,2)+1);if(i == 0) {// 赋予初值,不然 minDistance 的值就为 0 了~minDistance = d;}if(d < minDistance) {minDistance = d;minIndex = i;}}} else {// 直线斜率不存在的分支(亦即直线垂直于 x 轴)~for(int i = 0; i < points.length; ++ i) {CGPoint p = points[i];double d = Math.abs(p.x - line.extraX);if(i == 0) {// 赋予初值,不然minDistance的值就为0了~minDistance = d;}if(d < minDistance) {minDistance = d;minIndex = i;}}}CGPoint dest = points[minIndex];CGDbg.println("即将离开chooseOne()方法,圆心点为:("+dest.x+", "+dest.y+")");return dest;}/*** 获取传入两点的中点~* @param p1* @param p2* @return*/public static CGPoint getMiddlePoint(CGPoint p1, CGPoint p2) {return new CGPoint((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f);}/*** 封装一下 Math 的 pow 、sqrt 方法,调用起来方便一些~* @param d1* @param d2* @return*/public static double pow(double d1, double d2) {return Math.pow(d1, d2);}public static double sqrt(double d) {return Math.sqrt(d);}public static double sin(double theta) {return Math.sin(theta);}public static double cos(double theta) {return Math.cos(theta);}/*** 传入线段的两个端点,获取中点,以该中点为圆心做半径为 radius 的圆,* 经过线段中点做线段的垂线,返回垂线与圆的两个交点~* Objective-C 里面的结果有点儿问题,不知道是什么原因,来java 里面碰碰有运气~* @param p1      线段端点1* @param p2       线段端点2* @param radius   圆半径* @return           线段中垂线与圆的两个交点~*/public static CGPoint[] getWhatIWanted(CGPoint p1, CGPoint p2, double radius) {CGPoint[] target = new CGPoint[2];CGPoint pMiddle = getMiddlePoint(p1, p2);
//      double segLength = getDistanceBetween2Points(p1, p2);CGLine l1 = new CGLine(p1, p2);if(l1.iskExists()) {if(l1.k != 0) {double kOfNewLine = -1 / l1.k;CGLine newLine = new CGLine(kOfNewLine, pMiddle);// 经过数学运算,得出二元一次方程组的表达式double A = pow(newLine.k, 2) + 1;double B = 2 * (newLine.k * newLine.b - newLine.k * pMiddle.y - pMiddle.x);double C = pow(pMiddle.x, 2) + pow((newLine.b - pMiddle.y), 2) - pow(radius, 2);double delta = pow(B, 2) - 4 * A * C;if(delta < 0) {    // 经实践检验有一定几率走入该分支,必须做特殊化处理~// 2012。04。28。20。01,精度不够所致,换成double后无该情况出现~CGDbg.println("竟然会无解,他妈的怎么回事儿啊!");target[0] = new CGPoint(pMiddle.x, pMiddle.y - radius);target[1] = new CGPoint(pMiddle.x, pMiddle.y + radius);} else {double x1 = (-B + sqrt(delta)) / (2 * A);double y1 = newLine.k * x1 + newLine.b;target[0] = new CGPoint(x1, y1);double x2 = (-B - sqrt(delta)) / (2 * A);double y2 = newLine.k * x2 + newLine.b;target[1] = new CGPoint(x2, y2);}} else {target[0] = new CGPoint(pMiddle.x, pMiddle.y - radius);target[1] = new CGPoint(pMiddle.x, pMiddle.y + radius);}} else {target[0] = new CGPoint(pMiddle.x - radius, pMiddle.y);target[1] = new CGPoint(pMiddle.x + radius, pMiddle.y);}System.out.println("target[0] 距离中点的距离为:" + getDistanceBetween2Points(target[0], pMiddle));System.out.println("target[1] 距离中点的距离为:" + getDistanceBetween2Points(target[1], pMiddle));return target;}/*** 测试实用性,测试结果如下:* 之前用 float 类型的时候,每隔 1 度测试一次,共测试一个圆周,无解的情况出现一次* 每隔 1 度测试一次, 共测试一个圆周,无解的情况无。* 每隔 0.5 度测试一次,共测试一个圆周,无解的情况只出现一次* @param args*/public static void main(String[] args) {double currentRadian = 0;double deltaRadian = Math.PI / 360;double bigRadius = 50;double smallRadius = 20;CGPoint origin = new CGPoint(0, 0);   // 原点~CGPoint tail = null; // tail 是尾巴、末梢的意思~for(int i = 0; i < 720; ++ i) {System.out.println(" -- 第 "+ i + "度!");tail = new CGPoint(bigRadius*cos(currentRadian), bigRadius*sin(currentRadian));currentRadian += deltaRadian;getWhatIWanted(origin, tail, smallRadius);}}
}

求过圆心直线与圆的两个交点相关推荐

  1. lisp取两直线交点画圆_求过圆心直线与圆的两个交点

    主要是注意所使用的数据类型. 之前用的是float,出现了一些意外,而且花费了我不少时间来反复验证.推导, 做了很多的无用功,而且,反复推导得出来的计算步骤并没有什么不牢靠的地方. 然后计算得到的结果 ...

  2. matlab过圆心的直线,iOS计算过圆心直线与圆的交点

    主要计算公式: 直线的一般方程      y = kx + b; 圆的一般方程        x^2 + y^2 + Dx + Ey + F = 0; 圆的基本系数关系     r = (根号(D^2 ...

  3. 求线段或直线与圆的交点

    2019独角兽企业重金招聘Python工程师标准>>> 设圆心为O,圆半径为r,直线(或线段)L上的两个点为P1.P2. 第一步:如果L是线段且P1,P2都包含在O内,则没有交点. ...

  4. lisp 读取样条曲线座标点_如何在lisp中求一条直线和一条曲线的交点

    ★快捷命令的命名规律 1. 快捷命令通常是该命令英文单词的第一个或前面两个字母,有的是前三个字母. 比如,直线(Line)的快捷命令是"L":复制(COpy)的快捷命令是" ...

  5. 直线与直线、直线与圆、直线与矩形的交点

    求直线与直线.直线与圆.直线与矩形的交点 直线与直线的交点:a1x + b1x + c1x = 0 与 a2x + b2x + c2x = 0的交点坐标可直接根据公式x = (b1c2 - b2c1) ...

  6. 判断圆和线相切java_通过直线与圆交点数,轻松判断直线与圆关系,相离、相交、相切...

    初中数学,以直线与圆交点个数来判断,直线与圆有3种位置关系.相离,直线与圆无交点:相切,直线与圆有一个交点:相交,直线与圆有两个交点.同样,我们也可以通过直线与圆心的距离来判断直线与圆的位置关系,那下 ...

  7. JAVA程序设计:求直线与圆的交点坐标

    其实圆与直线的交点方程并不难解,难得是算法实现,废话不多说,直接上代码: 核心类 /*** @Author: Zhangwenshun* @Description:* @Date: Created i ...

  8. 24.2.2直线和圆的位置关系(1)教学设计

    本课通过学生动手画图并实践操作,直观感受直线和圆的三种位置关系.设圆心到直线的距离为d,半径为r,然后归纳d与r的数量关系对应直线和圆的位置关系,利用数形结合让学生理解相关知识. 课堂检测部分设计A组 ...

  9. 求圆心到点的直线与圆的相交点

    求圆心到点的直线与圆的相交点 点B为圆上一动点,已知圆心O(x2,y2), 圆外点A(x1,y1),圆半径r值,求B(x,y)坐标. 由图可知,产生下面两个公式. m/n = y1-y2/x1-x2 ...

最新文章

  1. 2020-07-16 CVPR2020 VL论文讨论(5) 笔记
  2. JPA EntityManager详解
  3. 程序员“苦逼值”测试,分数越高越苦逼
  4. Oracle历史记录
  5. 编译安装sqlite-3.6.20【原创】
  6. 第一章 密码学和加密交易的介绍
  7. 什么是计算机游戏技术,dlss技术是什么意思有什么用?目前支持dlss的游戏有哪些?...
  8. Spring源码之BeanDefinitionRegistryPostProcessor内部执行流程
  9. php1108脱机使用,惠普p1108能扫描吗 打印机出现脱机解决方法【详解】
  10. MATLAB 图像处理工具箱 一种简单的基于图像处理交通信号灯识别算法
  11. solidworks 2016 crack
  12. PropertyBeanUtils.copyProperties(dest, orig)
  13. 2018技术胖Web前端视频教程全套
  14. Vue 2.x折腾记 - (16) 基于Ant Design Vue 封装一个配置式的表单搜索组件
  15. 服务器操作系统linux,关于服务器的操作系统
  16. 我的世界服务器神秘修改节点,我的世界NBT指令修改神秘时代4MOD方法详解
  17. 学习笔记 - Postgres如何创建有自增主键的表
  18. 10分钟带你了解MSTP协议,附加配置MSTP实验
  19. HMI-42-【节能模式】实现油量表和水温表
  20. 前端使用Element-上传图片,图片转码位base64位传给后端,再获取后端数据展示图片

热门文章

  1. 经典管理学定律3 - 鳄鱼法则
  2. RTXa1000和a2000差距
  3. Unity期末AI足球游戏小项目(免费开源)
  4. 前端学习从入门到高级全程记录之1 (HTML基础知识)
  5. JS中的构造函数的含义和用法
  6. Excel 多条件筛选 与 数据透视表 实现
  7. scrapy实战项目(简单的爬取知乎项目)
  8. 神经网络自动布局技术,神经网络自动布局原理
  9. 游戏和股票的结构有一定的类似性
  10. 移动通信的频段、频率与频点