圓是任意一點擁有唯一的圓心角。所以在定義圓的時候,可以加乙個圓心角求座標的函式。
首先是輔助巨集:
const double eps = 1e-10;
const double pi = acos(-1); // π
const double two_pi = 2*pi;
const int maxn = 100 + 5;
const int inf = 10000;
圓的儲存結構定義:
struct circle
point point(double a)
};
直線與圓的交點。假定直線為ab,圓的圓心為c,半徑為r。
我們可以通過解方程組的方式解決。
設交點為p=a+t(b-a),代入圓方程整理後先得到(at+b)^2 + (ct+d)^2 = r^2 進一步整理後得到一元二次方程et^2 + ft + g=0 根據判別式的值可以區分三種情況,即午無交點,乙個交點和兩個交點。
函式返回的是交點的個數,引數sol存放的是交點本身。注意上述**並沒有清空sol,這樣可以反覆呼叫這個函式,把所有交點放在乙個sol裡。
int getlinecircleintersection(line l, circle c, double& t1, double& t2, vector& sol)
//相交
t1 = (-f - sqrt(delta)) / (2*e);
sol.push_back(l.point(t1));
t2 = (-f + sqrt(delta)) / (2*e);
sol.push_back(l.point(t2));
return 2;
}
int getsegmentcircleintersection(point a, point b, circle c, double &t1, double &t2, vector&sol)
return cnt;
}else
if(dcmp(t2) >= 0 && dcmp(t2-1) <= 0)
return cnt;
}}
圓和線段是否相交,相切不算,線段不考慮端點.
bool circleintersectsegment(point a, point b, circle c)
兩圓相交。
假定圓心分別為c1和c2,半徑為r1和r2,圓心距為d,根據餘弦定理可以算出c1c2到c1p1的角da,根據向量c1c2的極角a,加減da就可以得到c1p1和c1p2的極角。有了極角,就可以很方便地計算出p1和p2的座標了。
int getcirclecircleintersection(circle c1, circle c2, vector& sol)
if(dcmp(c1.r + c2.r - d) < 0) //兩圓相離
return 0;
if(dcmp(fabs(c1.r - c2.r) - d) > 0) //兩圓內含
return 0;
a = angle(c2.c - c1.c); //向量c1c2的極角
da = acos((c1.r*c1.r + d*d - c2.r*c2.r) / (2*c1.r*d));
//c1c2到c1p1的角、
p1 = c1.point(a-da);
p2 = c1.point(a+da);
sol.push_back(p1);
if(p1 == p2)
return 1;
sol.push_back(p2);
return 2;
}
過定點做圓的切線。先求出pq的距離和pc的夾角ang,則向量pc的極角ang就是兩條切線的極角。注意切線不存在和只有一條的情況。
過點p到圓c的切線,v[i]是第i條切線的向量。返回切線條數。
int gettangents(point p, circle c, vector *v)
ang = asin(c.r / dist);
v[0] = rotate(u, ang);
v[1] = rotate(u, -ang);
return 2;
}
兩圓的公切線。根據兩圓的圓心距從小到大排列。
情況一:兩圓完全重合,有無數條公切線。
情況二:兩圓內含,沒有公共點。沒有公切線。
情況三:兩圓內切。有一條公切線。
情況四:兩圓相交。有兩條外公切線。
情況五:兩圓外切。有三條公切線,其中一條內公切線,兩條外公切線。
情況六:兩圓相離。有四條公切線,其中內公切線兩條,外公切線兩條。
情況三和情況五中的內公切線都對應於「過圓上一點求圓的切線」,只需連線圓心和切點。旋轉90度即可直到切線的方向向量。
返回切線的條數,-1表示無數條切線。
int gettangents(circle a, circle b, point *a, point *b)
cnt = 0;
u = b.c - a.c;
d = length(u); //圓心距
base = angle(u); //兩圓心向量極角
if(dcmp(d) == 0)
if(dcmp(a.r - b.r - d) > 0) //內含
return 0;
if(dcmp(a.r - b.r - d) == 0) //內切
ang = acos((a.r-b.r) / d); //向量u與圓心與交點連線之間的角
a[cnt] = a.point(base + ang);
b[cnt] = b.point(base + ang);
cnt++;
a[cnt] = a.point(base - ang);
b[cnt] = b.point(base - ang);
cnt++;
if(dcmp(d - a.r - b.r) == 0) //外切
else if(dcmp(d - a.r - b.r) > 0) //相離
return cnt;
}
點在圓內,圓周上不算。
bool isincircle(point p, circle c)
判斷點是否在圓內,包括邊界
bool incircle(point p, circle c)
求圓心為o(0,0),半徑為r,點ao與bo之間組成的夾角組成的圓弧的長度
double arcarea(point a, point b, double r)
球面相關問題。
經緯度轉換為空間座標。經線圈(-180度-180度)和緯線圈(0度-360度)的概念相信大家並不陌生,但如何把經緯度轉化為對於球心的空間左邊呢?可以先算出z座標:用半徑乘以sin(緯度)就可以了,然後乘以cos(緯度),投影到x,y平面,在按照平面上的方法乘以經度的正余弦。
lat為緯度角度, lng為經度角度
x=rcos(lat)cos(lng)
y=rcos(lat)sin(lng)
z=rsin(lat)
角度轉換成弧度。 此為逆時針的角度,若為順時針,加上負號。
double torad(double deg)
經緯度轉換為空間座標
void get_coord(double r, double lat, double lng, double &x, double &y, double &z)
球面距離:已知球面兩點,如何求出它們的最短路?注意,只能沿著球面走,不能穿過球的內部。從表面走的話,最近的路徑是走圓弧,具體來說是走大圓圓弧。用乙個穿過球心的平面截這個球,截面就是乙個大圓。怎麼求大圓弧長呢?你無需想象那個大圓的空間位置,而可以把它們想象成乙個平面問題:求半徑r,弦長為d的圓弧長度。
圓心角為2arcsin(d/2r),因此弧長為2arcsin(d/2r)r. (弧長=圓心角(弧度)* 半徑)
二維幾何模板 二維幾何基礎
二維幾何模板 include include include include include include include include include using namespace std 二維幾何基礎 struct point typedef point vector const doub...
二維幾何基礎
模板 from 紫書 includeusing namespace std typedef long double ld const ld eps 1e 10 const ld pi acos ld 1.0 struct point typedef point vector vector opera...
二維幾何基礎
在幾何中,向量是乙個炒雞重要的東西,像空氣對於人,水對於魚 qaq 在這裡就不詳細介紹向量了,大家在高中數學中會學到,數學毒瘤,貌似資訊也是哈哈哈 下面是他們的常用定義 struct point 建構函式,方便 編寫 typedef point vector 從程式實現上,vector只是point...