2021SC@SDUSC
今天继续来看几何部分的另一个重要组件,线几何对象类(geoine),这个也是从 diagramo中的同类改进而来(链接:Flowchart software | Diagram software | Flowchart diagram),这个类中的线是何学意义上的直线,它不可见,没有宽度,用来进行数学运算。实际上在封装中,这个类是在上一期的点类的前面的,但为了便于理解先对点进行了分析。
var GeoLine = /*#__PURE__*/function () {
function GeoLine(startPoint, endPoint) {
_classCallCheck(this, GeoLine);
this.startPoint = startPoint;
this.endPoint = endPoint;
}
首先是从JSON 对象创建直线。每个直线包含两个值,也就是两点确定一条线的两个点:起始点(startpoint)和终点(endpoint)。可以看出来这里的直线不是数学意义上的无线延长直线,而是线段。
function contains(x, y) {
if (mathMin(this.startPoint.x, this.endPoint.x) <= x && x <= mathMax(this.startPoint.x, this.endPoint.x) && mathMin(this.startPoint.y, this.endPoint.y) <= y && y <= mathMax(this.startPoint.y, this.endPoint.y)) {
if (this.startPoint.x == this.endPoint.x) {
return x == this.startPoint.x;
} else {
// 通常(非垂直)线可以表示为y=a*x+b
var a = (this.endPoint.y - this.startPoint.y) / (this.endPoint.x - this.startPoint.x);
var b = this.startPoint.y - a * this.startPoint.x;
return y == a * x + b;
}
} else {
return false;
}
}
然后就是测试某个点是否位于直线上的函数(再次强调,这里不是数学意义上的无线延长直线,而是线段)。利用的计算方法:计算斜率,看(x,y)点是否位于线段上。
if (mathMin(this.startPoint.x, this.endPoint.x) <= x && x <= mathMax(this.startPoint.x, this.endPoint.x) && mathMin(this.startPoint.y, this.endPoint.y) <= y && y <= mathMax(this.startPoint.y, this.endPoint.y))
首先是判断点是否位于线段的矩形边界内,如果超出了以线段为对角线的矩形的话,点必不可能在线段上。
if (this.startPoint.x == this.endPoint.x) {
return x == this.startPoint.x;
}
然后检查垂直线段,如果点在垂直线上则不在线上(不考虑焦点)。
然后就是利用平面解析几何中的公式。直线方程的一般式为:ax+by+c=0 ,在平面直角坐标系中,我们知道任意两个点的坐标就可求出经过这两个点的直线方程,即:
a=y2-y1
b=x1-x2//注意别写反了
c=-ax1+by1
代码如下
var a = (this.endPoint.y - this.startPoint.y) / (this.endPoint.x - this.startPoint.x);
var b = this.startPoint.y - a * this.startPoint.x;
return y == a * x + b;
利用点的坐标和线的起始点和终止点带入即可,当然要先求出线的坐标方程。
同样的,自然还有对点与线距离的判断。
if (this.endPoint.x === this.startPoint.x) {
return (this.startPoint.y - radius <= y && this.endPoint.y + radius >= y || this.endPoint.y - radius <= y && this.startPoint.y + radius >= y) && x > this.startPoint.x - radius && x < this.startPoint.x + radius;
}
首先是两种情况。
第一种情况是点位于垂直线上,因此附近区域为矩形。
if (this.startPoint.y === this.endPoint.y) {
return (this.startPoint.x - radius <= x && this.endPoint.x + radius >= x || this.endPoint.x - radius <= x && this.startPoint.x + radius >= x) && y > this.startPoint.y - radius && y < this.startPoint.y + radius;
}
第二种是位于水平线上。
此外就是标准的利用点到线的距离进行运算。
var startX = mathMin(this.endPoint.x, this.startPoint.x);
var startY = mathMin(this.endPoint.y, this.startPoint.y);
var endX = mathMax(this.endPoint.x, this.startPoint.x);
var endY = mathMax(this.endPoint.y, this.startPoint.y);
为运算中的各个值进行定义。
var a = this.endPoint.y - this.startPoint.y;
var b = this.startPoint.x - this.endPoint.x;
var c = -(this.startPoint.x * this.endPoint.y - this.endPoint.x * this.startPoint.y);
首先我们需要找到直线方程ax+by+c=0的a,b,c
var d = mathAbs((a * x + b * y + c) / mathSqrt(mathPow(a, 2) + mathPow(b, 2)));
然后我们可以得到距离 。来自于"Mathematics for Computer Graphics, 2nd Ed., by John Vice, page 227"
紧接着,我们可以得出到目标点最近的线上的点的坐标
var closestX = (b * (b * x - a * y) - a * c) / (mathPow(a, 2) + mathPow(b, 2));
var closestY = (a * (-b * x + a * y) - b * c) / (mathPow(a, 2) + mathPow(b, 2));
当点的投影点位于线段内部时
var r = d <= radius && endX >= closestX && closestX >= startX && endY >= closestY && closestY >= startY ||
当点的投影点位于线段外部时
this.startPoint.near(x, y, radius) || this.endPoint.near(x, y, radius);
这样我们就可以求出点到线的距离了。
key: "getPoint",
value: function getPoint(t) {
var xp = t * (this.endPoint.x - this.startPoint.x) + this.startPoint.x;
var yp = t * (this.endPoint.y - this.startPoint.y) + this.startPoint.y;
return new GeoPoint(xp, yp);
}
这里是获取指定百分比上的点,参数 t 是百分比。也就是在线上百分之几的位置的点的坐标的获取。
剩下的关于线的克隆输出和两个线的对比和前面的点的操作大同小异,就不一一赘述了。