Java 通过向量,计算移动方向,计算线段角度等

1. 简介

向量是指在数学中用于表示大小和方向的量。在计算机科学中,向量通常用于表示物体的位置、速度和加速度等。在Java中,可以使用坐标系中两点之间的差异来计算向量之间的距离。

在二维空间中,向量通常表示为一个有序的数对(x, y),其中x和y分别表示向量在x轴和y轴上的分量。例如,向量(3, 4)表示一个向右3个单位和向上4个单位的向量。在三维空间中,向量通常表示为一个有序的三元组(x, y, z),其中x、y和z分别表示向量在x、y和z轴上的分量。

我们可以通过计算线段的向量,来判断手指(鼠标)在屏幕中的移动方向。速度等信息。可以通过向量计算两条线段的夹角度数等。

2. 获取线段的向量

向量可以进行加法和减法运算。向量的加法运算是将两个向量的分量相加,得到一个新的向量。向量的减法运算是将一个向量的分量减去另一个向量的分量,得到一个新的向量。

而我们如何通过坐标获取线段的向量呢?很简单x1-x2 就是向量x,y1-y2就是向量y。合起来就是向量在二维平面(直角坐标系)中的向量值:

代码语言:javascript
复制
   public static void getVectors(Point p1,Point p2,Point p3,Point p4){
        double ABx = p1.x - p2.x;
        double ABy = p1.y - p2.y;
        double CDx = p3.x - p4.x;
        double CDy = p3.y - p4.y;
    System.out.println("线段1的向量是: (" + ABx + ", " + ABy + ").");
    System.out.println("线段2的向量是: (" + CDx + ", " + CDy + ").");
   
    //向量的加法:
     double[] sum = new double[2];
     sum[0] = ABx + CDx;
     sum[1] = ABy + CDy;
    //得到的和sum就是一个新的向量了。是线段1和线段2的向量和。而减法也就是将+号跟换为-号而已。
}</code></pre></div></div><p>我们得到的向量有什么用处呢?下面就是向量的一些简单使用场景了。</p><h3 id="cpk10" name="3.-%E8%AE%A1%E7%AE%97%E7%BA%BF%E6%AE%B5%E5%92%8CX%E8%BD%B4%E7%9A%84%E8%A7%92%E5%BA%A6"><strong>3. 计算线段和X轴的角度</strong></h3><p>假如,我们有两个任意的坐标点,需要计算这两个坐标点连接的线段与X轴的夹角。</p><p>我们可以使用向量的知识,很简单的得到这个角度:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">public double getDegrees(Point p1, Point p2) {

//得到两个坐标点的差值, 其实得到的dx 和dy 就是我们线条的向量了
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
double angleRadians = Math.atan2(dy, dx); // 根据该方法,可以直接获取坐标点和x轴的夹角,返回的是一个-π到π之间的弧度值
double degrees = Math.toDegrees(angleRadians); //调用Math的API 将弧度转为角度,角度值范围为±180°。
return degrees;
}

在这个方法中,我们传入的坐标点的Y值的大小,决定了角度的正负数。

如果p1的Y值大于p2,返回的就是:-179°0 中间的值。

如果p1的Y值小于p2,返回的就是:0180°中间的值。

我们如果结合手机或者电脑屏幕的坐标来计算。

简单理解就是,点p1在p2的上方,那么计算的就是从x轴出发顺时针的角度,也就是0180°

而点p1在点p2的下方,那么计算的就是从x轴出发,逆时针的角度。也就是-179°0。(因为180°的时候,p1和p2平行,无所谓顺时针逆时针)。

4. 根据用户移动轨迹,判断用户的移动方向

在上面计算了线段和X轴的夹角。我们其实可以根据这个角度,判断计算用户的移动轨迹。也就能得到用户手指或者鼠标的移动轨迹了。

示例如下:

代码语言:javascript
复制
   public static String getDegrees(Point p1, Point p2) {
//得到线段的向量
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
//得到线段和x轴的夹角弧度
double angleRadians = Math.atan2(dy, dx);
//zinyan.com 将弧度值转为角度值
double degrees = Math.toDegrees(angleRadians);
//根据角度确定方向
if (degrees >= -45 && degrees < 45) {
return "right";//从右往左,也就是所谓的右边进入
} else if (degrees >= 45 && degrees < 135) {
return "up"; //从下往上 ,也就是所谓的上部进入
} else if (degrees >= -135 && degrees < -45) {
return "down";//从上往下 ,也就是所谓的底部进入
} else {
return "left"; //其他的就是左边进入的了, 从左往右移动的轨迹
}
}

上面的角度比较值,其实45度比较好理解。我们平面画一条直线当做X轴。线条上面的就是0-180°,线条下面的就是0180°

然后画一个米字格,每个线段的夹角就是45°。那么右边就是±45°。上面就是45°~135°了(PS:135=45+45+45)。

5. 通过向量和角度,计算两个线条的夹角

在前面,我们计算了如何获取线条和X轴的夹角。我们如果有两条线段,那么如何获取这两条线段的夹角呢?

处理逻辑很简单,例如线段1和x轴的夹角是90°,线段2和x轴的夹角是130°。那么线段1和线段2的夹角应该是:130°-90°=40°

使用x轴当做基准点,进行处理,你会发现运算逻辑很简单,具体示例代码如下:

代码语言:javascript
复制
//p1和p2 组合成线段1,p3和p4组合成线段2
public static double getDegress(Point p1,Point p2,Point p3,Point p4){
//这里是p2-p1也可以是p1-p2 位置是无所谓的,只是要统一。如果x轴是p2-p1,那么y轴也得是p2-p1
double d1x = p2.x - p1.x;
double d1y = p2.y - p1.y;
//这个的逻辑和上面一样,p3-p4或者p4-p3都可以
double d2x = p4.x - p3.x;
double d2y = p4.y - p3.y;
//然后通过atan2 得到弧度,要注意了这个方法中必须是y轴值在前面,x轴值在后面
//两个弧度相减,就是两个线段的夹角弧度
double angle = Math.atan2(d1y, d1x) - Math.atan2(d2y, d2x);
//将弧度,转为角度。并通过绝对值去除正负符号
angle = Math.abs(Math.toDegrees(angle));
if (angle > 180) {
//因为线段夹角内角+外角=360°,
// 如果超过180°了说明我们得到的是最大的外角了,而夹角应该是最小的角度,所以进行了360-angile
angle = 360 - angle;
}
return angle;
}

当我们使用向量和Math的API。你会发现计算角度等会很方便

Math.atan2() 方法返回从 X 轴到指定坐标点 (x,y) 之间的角度(以弧度为单位)。它是 Math.atan(y/x)的安全版,可以避免除数为 0 的情况。

6. 小结

关于向量也就是这些了。还有更多复杂的使用场景。这里就不扩展了,太复杂了。