已知一个点的坐标,如何判断该点是否在某扇形里面。
先插图
平均分成8份。从0°开始,每份45°。 如何判断改点在哪个扇形区域里面?(已知点的坐标)。 在线等 急急急·!!!
[解决办法]
按照楼主的题意,随手写了一段:
#include<iostream>#include<math.h>#define PI 3.1415926 //宏定义PI,意图是:一个圆周率的近似值。using namespace std;int whichSector(double X, double Y, double R) { double mod; mod = sqrt(X * X + Y * Y); //将点(X,Y)视为复平面上的点,与复数一一对应,现求复数的模。 double arg; arg = atan2(Y, X); //求复数的辐角。 if (mod > R) { //如果复数的模大于预设的半径,则返回0。 return 0; } else { //根据复数的辐角来判别该点落在那个扇区。 if (arg > (double) (0.0 * PI / 4.0) && arg < (double) (1.0 * PI / 4.0)) { return 1; } if (arg > (double) (1.0 * PI / 4.0) && arg < (double) (2.0 * PI / 4.0)) { return 2; } if (arg > (double) (2.0 * PI / 4.0) && arg < (double) (3.0 * PI / 4.0)) { return 3; } if (arg > (double) (3.0 * PI / 4.0) && arg < (double) (4.0 * PI / 4.0)) { return 4; } if (arg > (double) (-4.0 * PI / 4.0) && arg < (double) (-3.0 * PI / 4.0)) { return 5; } if (arg > (double) (-3.0 * PI / 4.0) && arg < (double) (-2.0 * PI / 4.0)) { return 6; } if (arg > (double) (-2.0 * PI / 4.0) && arg < (double) (-1.0 * PI / 4.0)) { return 7; } if (arg > (double) (-1.0 * PI / 4.0) && arg < (double) (-0.0 * PI / 4.0)) { return 8; } return 999; //这是几率极低的事件。 } return 0;}int main(void) { double r, x, y; cout << "Please tell me the Radius of your Circle:" << endl; cin >> r; cout << "Please tell me the value of X of your Point:" << endl; cin >> x; cout << "Please tell me the value of Y of your Point:" << endl; cin >> y; int w; w = whichSector(x, y, r); if (0 == w) { cout << "Your point is OUT of your Circle!" << endl; return 0; } else { if (999 == w) { cout << "Oops... Your Point is ***critically*** ON a border that belongs to no sector!" << endl; } else { cout << "Your Point is ON a certain area of the sector #" << w << "." << endl; } } return 0;}
[解决办法]
为了解决上述的“信息丢失”问题,我们必须找到一种信息不会丢失的等价变换。
在数学里面,实现这种等价变换的工具已经有了,那就是复数vs复平面(上的点)。
任何平面上的点(不论是用直角坐标系刻画,还是用极坐标系刻画),都等价于复平面上的点。
那么,我们可以把楼主的题目中的自由点A(xA,yA)视为复平面上的点。
根据高斯(C.F.Gauss)的原则,复平面上的点与复数是一一对应的。
即,自由点A(xA,yA)与复数Z=xA+yAi完全等价。
也即,自由点A的纵横坐标值与复数Z的虚实二部(不是任督二脉)完全等价。
从复数Z的虚实二部,变换为复数的模和辐角,这个过程中信息不会丢失。
而复数的模(mod)和辐角(arg)正是解答本题的关键:
(一)将复数Z的模与预设的圆半径比较大小,可以判别自由点是否超越圆周范围。
(二)根据复数Z的辐角,可以判别自由点落在哪个扇区。
进入C++ 解题:
(一)计算复数Z的模,很简单,纵横坐标值的平方和再开平方。
(二)计算复数Z的辐角,要注意,C++的<math.h>提供的atan反正切函数,只能计算出值域为从-PI/2到PI/2的所谓“主值”,这样不足以匹配8个扇区。所幸的是,<math.h>提供了atan2函数,该函数接受两个double参数即点的纵横二坐标值,可以计算出值域为从-PI到PI的全圆周角值。
上述解法,就是我贴在8楼的代码。
以上,仅供参考,呵呵……
[解决办法]
我在上面提到的解法,虽然完全符合数学原理,但在计算机上运算,却有着致命的缺陷。
那就是:复数可以与实数对一一对应,而实数在数轴上是连续分布的。但是,计算机里的数字,都是以离散形态存在的。
那么,用计算机计算实数,不可避免地,将会有误差,而有些误差会造成定性判断的错误。
之前的解法,在上述问题上的风险,还是比较显著的。
于是,我们要寻找一个更加接近离散性判断的方法。
我们观察到,圆周内部区域,被分割为8个扇区。这8个扇区乃辐射对称且全等。
8等于2的3次方,这意味着,8个离散量必然可以用3个二元离散量的有序排列来一一对应。
二元离散量有3个,这意味着我们在题目中,要找到合适的关于自由点的三个自由度。
对于自由点A(x,y),最合适的三个自由度:
(1)x>0 的真值;
(2)y>0 的真值;
(3)x^2>y^2 的真值(为什么是x和y的平方比较,而不用x>y?请思考一下……)。
可以列出如下真值表:
+-------+-------+-------+------+-------+--------+| x>0 | y>0 |x^2>y^2| Code | dValue| Sector#|+-------+-------+-------+------+-------+--------+| 1 | 1 | 1 | 111 | 7 | 1 |+-------+-------+-------+------+-------+--------+| 1 | 1 | 0 | 110 | 6 | 2 |+-------+-------+-------+------+-------+--------+| 0 | 1 | 0 | 010 | 2 | 3 |+-------+-------+-------+------+-------+--------+| 0 | 1 | 1 | 011 | 3 | 4 |+-------+-------+-------+------+-------+--------+| 0 | 0 | 1 | 001 | 1 | 5 |+-------+-------+-------+------+-------+--------+| 0 | 0 | 0 | 000 | 0 | 6 |+-------+-------+-------+------+-------+--------+| 1 | 0 | 0 | 100 | 4 | 7 |+-------+-------+-------+------+-------+--------+| 1 | 0 | 1 | 101 | 5 | 8 |+-------+-------+-------+------+-------+--------+