最近處理一些問題,涉及到對(duì)直線進(jìn)行處理怜校。對(duì)于十幾年不接觸數(shù)學(xué)的人而言,有些意思注竿。
我想要實(shí)現(xiàn)的有以下:
- 已知兩個(gè)點(diǎn)(x1, y1), (x2, y2)茄茁,求直線方程;
- 已知四個(gè)點(diǎn)(x1, y1), (x2, y2), (p1, q1), (p2, q2)巩割,求(x1, y1), (x2, y2)組成的直線與(p1, q1), (p2, q2)組成直線裙顽,這兩條直線的交點(diǎn);
- 過該交點(diǎn)喂分,平分交點(diǎn)的角锦庸,形成的直線机蔗,求該直線的方程蒲祈;
- 最好能畫出來上述的圖。
需要準(zhǔn)備的數(shù)學(xué)知識(shí)萝嘁,可以參考維基或數(shù)學(xué)課本梆掸,也可以自己算出來。簡(jiǎn)單截圖如下:
-
直線定義牙言,兩點(diǎn)式酸钦、斜截式和一般式
-
兩個(gè)直線的交點(diǎn)
-
平面2點(diǎn)距離
-
角平分線定理
備注:實(shí)際上也可以求的交點(diǎn)的夾角后,通過一條直線旋轉(zhuǎn)后生成方程咱枉。但是推導(dǎo)起來有點(diǎn)困難卑硫,所以沒有采用。過后我如果解決了蚕断,會(huì)再寫上欢伏。
步驟如下:
- 求交點(diǎn);
- 在交點(diǎn)的左右取x值亿乳,計(jì)算出對(duì)應(yīng)的y值硝拧,形成2個(gè)點(diǎn)后,直線的方程就有了葛假。
下面是代碼(簡(jiǎn)化處理障陶,沒有考慮平行的情況)
# 導(dǎo)入必要的包
import numpy as np
from matplotlib import pyplot as plt
import math
# 過直線A的兩點(diǎn)
x1, y1 = 2, 3
x2, y2 = 7, 10
# 過直線B的兩點(diǎn)
p1, q1 = 4, 8
p2, q2 = 6, 3
# 繪制直線A上的點(diǎn)
plt.plot(x1, y1, "ob")
plt.plot(x2, y2, "ob")
# 繪制直線A上的點(diǎn)
plt.plot(p1, q1, "or")
plt.plot(p2, q2, "or")
# 定義求斜率的方法
def get_k(x1,y1,x2,y2):
k = (y1-y2)/(x1-x2)
return k
# 定義求截距的方法
def get_b(x1,y1,x2,y2):
b = (x1*y2-x2*y1)/(x1-x2)
return b
# 繪制直線A
k1 = get_k(x1,y1,x2,y2)
b1 = get_b(x1,y1,x2,y2)
x_1 = np.arange(1, 10, 0.2)
y_1 = k1 *x_1 +b1
plt.plot(x_1 , y_1 , linewidth=0.5)
# 繪制直線B
k2 = get_k(p1,q1,p2,q2)
b2 = get_b(p1,q1,p2,q2)
x_2 = np.arange(1, 10, 0.2)
y_2 = k2 *x_2 +b2
plt.plot(x_2, y_2, linewidth=0.5)
# 定義矩陣運(yùn)算,方便調(diào)用
def mat(a, b, c, d):
return a*d-b*c
# 定義獲取一般式ABC的方法
def get_ABC(x1, y1, x2, y2):
A = y2 - y1
B = x1 - x2
C = x2*y1 - x1*y2
return A, B, C
# 分別求兩條直線的ABC
A1, B1, C1 = get_ABC(x1, y1, x2, y2)
A2, B2, C2 = get_ABC(p1, q1, p2, q2)
# 求出交點(diǎn)并繪制
cross_x = - (mat(C1, B1, C2, B2))/(mat(A1, B1, A2, B2))
cross_y = - (mat(A1, C1, A2, C2))/(mat(A1, B1, A2, B2))
plt.plot(cross_x, cross_y, "og")
# 求三角形底邊長(zhǎng)度聊训,隨便定義個(gè)中文名函數(shù)抱究。x是在x軸取的值,只需要在交點(diǎn)左右取兩點(diǎn)即可
def get_底邊長(zhǎng)度(x, k1, b1, k2, b2):
y1 = k1*x+b1
y2 = k2*x+b2
return math.fabs(y1-y2)
# 定義求距離的方法
def get_distance(x0, y0, x1, y1):
dd = (x0-x1)**2 + (y0-y1)**2
d = math.sqrt(dd)
return d
# 在交點(diǎn)的左带斑、右各取一個(gè)x軸位置鼓寺,分別求出該x時(shí)酿雪,兩條直線的y的值
x_left = cross_x - 3
y_left_1 = k1*x_left+b1
y_left_2 = k2*x_left+b2
x_right = cross_x + 3
y_right_1 = k1*x_right+b1
y_right_2 = k2*x_right+b2
# 于是一共有4個(gè)點(diǎn):(x_left, y_left_1), (x_left, y_left_2), (x_right, y_right_1), (x_right, y_right_2)
# 利用角平分線定理求得在夾角平分線上的點(diǎn)的y值
上邊長(zhǎng)_left = get_distance(x_left, max(y_left_1, y_left_2), cross_x, cross_y)
下邊長(zhǎng)_left = get_distance(x_left, min(y_left_1, y_left_2), cross_x, cross_y)
上邊長(zhǎng)_right = get_distance(x_right, max(y_right_1, y_right_2), cross_x, cross_y)
下邊長(zhǎng)_right = get_distance(x_right, min(y_right_1, y_right_2), cross_x, cross_y)
底邊長(zhǎng)度_left = get_底邊長(zhǎng)度(x_left, k1, b1, k2, b2)
底邊長(zhǎng)度_right = get_底邊長(zhǎng)度(x_right, k1, b1, k2, b2)
上底邊_left = (上邊長(zhǎng)_left * 底邊長(zhǎng)度_left)/(上邊長(zhǎng)_left+下邊長(zhǎng)_left)
y_left = max(y_left_1, y_left_2) - 上底邊_left # 左邊的點(diǎn)為(x_left, y_left)
上底邊_right = (上邊長(zhǎng)_right * 底邊長(zhǎng)度_right)/(上邊長(zhǎng)_right+下邊長(zhǎng)_right)
y_right = max(y_right_1, y_right_2) - 上底邊_right # 右邊的點(diǎn)為(x_right, y_right)
# 現(xiàn)在夾角平分線上的2個(gè)點(diǎn)就有了。該直線很容易求得侄刽。順便把這2個(gè)點(diǎn)也畫出來
plt.plot(x_left, y_left, "og")
plt.plot(x_right, y_right, "og")
k = get_k(x_left, y_left, x_right, y_right)
b = get_b(x_left, y_left, x_right, y_right)
# 最后把直線畫出來
x = np.arange(1, 10, 0.2)
y = k*x+b
plt.plot(x, y, linewidth=0.8)
結(jié)果如下圖:
畫出來的圖看起來好像兩個(gè)角不一樣大指黎。本著求真務(wù)實(shí)的精神,在用點(diǎn)到距離的公式驗(yàn)算一下州丹。
正確的情況下醋安,點(diǎn)到兩條直線的距離應(yīng)該相等。
# 定義計(jì)算點(diǎn)到直線的距離的方法
def get_點(diǎn)到直線距離(A, B, C, x, y):
up = math.fabs(A*x+B*y+C)
down = math.sqrt(A**2+B**2)
d = up/down
return d
d1 = line.get_點(diǎn)到直線距離(A1, B1, C1, x_left, y_left)
d2 = line.get_點(diǎn)到直線距離(A2, B2, C2, x_right, y_right)
# d1 = 2.6512291367965264
# d2 = 2.6512291367965277
d1與d2幾乎相等了墓毒,看起來角不一樣大吓揪,可能是由于運(yùn)算的誤差造成的。
以上所计,如果有錯(cuò)誤柠辞,還請(qǐng)留言批評(píng)指正。