c#實現的一些幾何演算法(二)
續一
//關於線的一些演算法
public class GeometricClass
{
/* 判斷點與線段的關係,用途很廣泛
本函式是根據下面的公式寫的,P是點C到線段AB所在直線的垂足
AC dot AB
r = ---------
||AB||^2
(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
= -------------------------------
L^2
r has the following meaning:
r=0 P = A
r=1 P = B
r<0 P is on the backward extension of AB
r>1 P is on the forward extension of AB
0<r<1 P is interior to AB
*/
public static double RelationOfPointAndLine(SpatialPoint p, SpatialLine l)
{
SpatialLine tl = new SpatialLine();
tl.startPoint = l.startPoint;
tl.endPoint = p;
return dotmultiply(tl.endPoint, l.endPoint, l.startPoint) / (CalculateFlatDistance(l.startPoint, l.endPoint) * CalculateFlatDistance(l.startPoint, l.endPoint));
}
// 根據已知兩點座標,求過這兩點的直線解析方程: a*x+b*y+c = 0 (a >= 0)
public static SpatialLine Makeline(SpatialPoint p1, SpatialPoint p2)
{
SpatialLine tl = new SpatialLine();
int sign = 1;
tl.a = p2.y - p1.y;
if (tl.a < 0)
{
sign = -1;
tl.a = sign * tl.a;
}
tl.b = sign * (p1.x - p2.x);
tl.c = sign * (p1.y * p2.x - p1.x * p2.y);
return tl;
}
// 根據直線解析方程返回直線的斜率k,水平線返回 0,豎直線返回 1e200
public static double SlopeOfLine(SpatialLine l)
{
if (Math.Abs(l.a) < INF)
return 0;
if (Math.Abs(l.b) < INF)
return double.MaxValue;
return -(l.a / l.b);
}
// 返回直線的傾斜角alpha ( 0 - pi)
public static double alphaOfLine(SpatialLine l)
{
if (Math.Abs(l.a) < INF)
return 0;
if (Math.Abs(l.b) < INF)
return PI / 2;
double k = SlopeOfLine(l);
if (k > 0)
return Math.Atan(k);
else
return PI + Math.Atan(k);
}
// 求點C到線段AB所在直線的垂足 P
public static SpatialPoint PerpendicularOnLine(SpatialPoint p, SpatialLine l)
{
double r = RelationOfPointAndLine(p, l);
SpatialPoint tp = new SpatialPoint();
tp.x = l.startPoint.x + r * (l.endPoint.x - l.startPoint.x);
tp.y = l.startPoint.y + r * (l.endPoint.y - l.startPoint.y);
return tp;
}
// 求點p到線段l所在直線的距離,請注意本函式與上個函式的區別
public static double DistanceInPointToLine(SpatialPoint p, SpatialLine l)
{
return Math.Abs(multiply(p, l.endPoint, l.startPoint)) / CalculateFlatDistance(l.startPoint, l.endPoint);
}
// 返回線段l1與l2之間的夾角 單位:弧度 範圍(-pi,pi)
public static double AngleOfTwoLine(SpatialLine l1, SpatialLine l2)
{
SpatialPoint o, s, e;
o = new SpatialPoint();
s = new SpatialPoint();
e = new SpatialPoint();
o.x = o.y = 0;
s.x = l1.endPoint.x - l1.startPoint.x;
s.y = l1.endPoint.y - l1.startPoint.y;
e.x = l2.endPoint.x - l2.startPoint.x;
e.y = l2.endPoint.y - l2.startPoint.y;
return AngleOfThreePoint(o, s, e);
}
// 如果線段u和v相交(包括相交在端點處)時,返回true
//判斷P1P2跨立Q1Q2的依據是:( P1 - Q1 ) × ( Q2 - Q1 ) * ( Q2 - Q1 ) × ( P2 - Q1 ) >= 0。
//判斷Q1Q2跨立P1P2的依據是:( Q1 - P1 ) × ( P2 - P1 ) * ( P2 - P1 ) × ( Q2 - P1 ) >= 0。
public static bool IsIntersect(SpatialLine u, SpatialLine v)
{
return ((Math.Max(u.startPoint.x, u.endPoint.x) >= Math.Min(v.startPoint.x, v.endPoint.x)) && //排斥實驗
(Math.Max(v.startPoint.x, v.endPoint.x) >= Math.Min(u.startPoint.x, u.endPoint.x)) &&
(Math.Max(u.startPoint.y, u.endPoint.y) >= Math.Min(v.startPoint.y, v.endPoint.y)) &&
(Math.Max(v.startPoint.y, v.endPoint.y) >= Math.Min(u.startPoint.y, u.endPoint.y)) &&
(multiply(v.startPoint, u.endPoint, u.startPoint) * multiply(u.endPoint, v.endPoint, u.startPoint) >= 0) && //跨立實驗
(multiply(u.startPoint, v.endPoint, v.startPoint) * multiply(v.endPoint, u.endPoint, v.startPoint) >= 0));
}
// (線段u和v相交)&&(交點不是雙方的端點) 時返回true
public static bool IsIntersect_A(SpatialLine u, SpatialLine v)
{
return ((IsIntersect(u, v)) &&
(!PointIsOnLine(u, v.startPoint)) &&
(!PointIsOnLine(u, v.endPoint)) &&
(!PointIsOnLine(v, u.endPoint)) &&
(!PointIsOnLine(v, u.startPoint)));
}
// 線段v所在直線與線段u相交時返回true;方法:判斷線段u是否跨立線段v
public static bool intersect_l(SpatialLine u, SpatialLine v)
{
return multiply(u.startPoint, v.endPoint, v.startPoint) * multiply(v.endPoint, u.endPoint, v.startPoint) >= 0;
}
// 如果兩條直線 l1(a1*x+b1*y+c1 = 0), l2(a2*x+b2*y+c2 = 0)相交,返回true,且返回交點p
public static bool LineIntersect(SpatialLine l1, SpatialLine l2, out SpatialPoint intersectPoint) // 是 L1,L2
{
double d = l1.a * l2.b - l2.a * l1.b;
intersectPoint = new SpatialPoint();
if (Math.Abs(d) < EP) // 不相交
return false;
intersectPoint.x = (l2.c * l1.b - l1.c * l2.b) / d;
intersectPoint.y = (l2.a * l1.c - l1.a * l2.c) / d;
intersectPoint.h = 0;
return true;
}
// 如果線段l1和l2相交,返回true且交點由(intersectPoint)返回,否則返回false
public static bool LineSegmentIntersection(SpatialLine l1, SpatialLine l2, out SpatialPoint intersectPoint)
{
SpatialLine ll1, ll2;
intersectPoint = new SpatialPoint();
ll1 = Makeline(l1.startPoint, l1.endPoint);
ll2 = Makeline(l2.startPoint, l2.endPoint);
if (LineIntersect(ll1, ll2, out intersectPoint))
return PointIsOnLine(l1, intersectPoint) && PointIsOnLine(l2, intersectPoint);
else
return false;
}
}