# 內外積在程式中的應用
先複習
* $\vec{AB}=(x2−x1 ,y2 −y1)$
* 內積: $\vec{a}\cdot\vec{b} = a_xb_x+a_yb_y$
* 外積: $\vec{a}\times\vec{b} = a_xb_y-a_yb_x$
:::warning
需要至少三個點才能形成兩個向量
:::
## 內積(Dot Product)
可以用來求角度或判斷夾角是銳角、直角或鈍角
| 判斷 | 結果 |
| --------------------------- | -- |
| ( $\vec{a}\cdot\vec{b}$ > 0 ) | 銳角 |
| ( $\vec{a}\cdot\vec{b}$ = 0 ) | 直角 |
| ( $\vec{a}\cdot\vec{b}$ < 0 ) | 鈍角 |
由角度的關係可以知道兩向量的方向關係:
* **夾角為銳角**( $0^{\circ }\le\theta <90^{\circ }$):內積為正值,表示兩個向量方向大致`相同`。
* **夾角為鈍角**( $90^{\circ }\le\theta <180^{\circ }$):內積為正值,表示兩個向量方向大致`相反`。
* **夾角為直角** ($\theta =90^{\circ }$):內積為零,表示兩個向量互相`垂直`。
## 外積
在幾何中(3D),向量的定義為`公垂向量`,他會垂直 $\vec{a}$ 與 $\vec{b}$ ,但在平面中,沒有地方儲存Z軸,所以會運算結果會是一個正負數,用來代表左右轉還是迴轉。
> a = (1, 0) // 指向 x 軸正方向
b = (0, 1) // 指向 y 軸正方向
外積:
$a×b=(1)(1)−(0)(0)=+1$
代表「z 軸正方向」,也就是「逆時針」旋轉 -> 左轉。
所以正負號可判斷旋轉方向:
* $> 0$ → 左轉
* $< 0$ → 右轉
* $= 0$ → 共線(迴轉或原地不動)
:::warning
要注意外積=0的時候可能是原地不動,迴轉的條件是兩方向相反(透過內積求得方向)
:::
| 類型 | 用法 | 判斷依據 |
| ----- | --------- | ----------- |
| 判斷轉向 | 外積 | 正負號 |
| 判斷夾角 | 內積 | 正負號 |
| 計算面積 | 外積絕對值 / 2 | 幾何面積 |
| 多邊形方向 | 外積和的符號 | 正→逆時針、負→順時針 |
| 判斷正交 | 內積 = 0 | 垂直 |
# 實作
競賽中會透過Struct這個資料結構來快速存取x,y值。
```cpp=
struct Point {
double x, y;
};
int main() {
Point a = {3, 4};
Point b = {1, 2};
cout << a.x+b.x;//4
}
```
當然也可以透過以下寫法:
更快速的存取其他運算。
```cpp=
struct Point {
double x, y;
// 向量加法
Point operator+(const Point &other) const {
return {x + other.x, y + other.y};
}
// 向量減法
Point operator-(const Point &other) const {
return {x - other.x, y - other.y};
}
// 內積
double dot(const Point &other) const {
return x * other.x + y * other.y;
}
// 外積
double cross(const Point &other) const {
return x * other.y - y * other.x;
}
};
```
```cpp=
Point a = {3, 4}, b = {1, 2};
cout << a.dot(b) << endl; // 內積
cout << a.cross(b) << endl; // 外積
```
## 實際演練
[2023/06 APCS 實作題](/Y5GdYfwnQ4Kbw3H8bJTkaw) - 第一題: 路徑偵測