概述
在 Openlayers 中,Circle
类用于圆的实例化,Circle
类继承于SimpleGeometry
类,关于SimpleGeometry
类,可以参考源码分析之Openlayers中SimpleGeometry类
源码分析
Circle
类的源码实现
Circle
类的源码实现如下:
class Circle extends SimpleGeometry {constructor() {}clone() {const circle = new Circle(this.flatCoordinates.slice(),undefined,this.layout);circle.applyProperties(this);return circle;}closestPointXY(x, y, closestPoint, minSquaredDistance) {const flatCoordinates = this.flatCoordinates;const dx = x - flatCoordinates[0];const dy = y - flatCoordinates[1];const squaredDistance = dx * dx + dy * dy;if (squaredDistance < minSquaredDistance) {if (squaredDistance === 0) {for (let i = 0; i < this.stride; ++i) {closestPoint[i] = flatCoordinates[i];}} else {const delta = this.getRadius() / Math.sqrt(squaredDistance);closestPoint[0] = flatCoordinates[0] + delta * dx;closestPoint[1] = flatCoordinates[1] + delta * dy;for (let i = 2; i < this.stride; ++i) {closestPoint[i] = flatCoordinates[i];}}closestPoint.length = this.stride;return squaredDistance;}return minSquaredDistance;}containsXY(x, y) {const flatCoordinates = this.flatCoordinates;const dx = x - flatCoordinates[0];const dy = y - flatCoordinates[1];return dx * dx + dy * dy <= this.getRadiusSquared_();}getCenter() {return this.flatCoordinates.slice(0, this.stride);}computeExtent(extent) {const flatCoordinates = this.flatCoordinates;const radius = flatCoordinates[this.stride] - flatCoordinates[0];return createOrUpdate(flatCoordinates[0] - radius,flatCoordinates[1] - radius,flatCoordinates[0] + radius,flatCoordinates[1] + radius,extent);}getRadius() {return Math.sqrt(this.getRadiusSquared_());}getRadiusSquared_() {const dx = this.flatCoordinates[this.stride] - this.flatCoordinates[0];const dy = this.flatCoordinates[this.stride + 1] - this.flatCoordinates[1];return dx * dx + dy * dy;}getType() {return "Circle";}intersectsExtent(extent) {const circleExtent = this.getExtent();if (intersects(extent, circleExtent)) {const center = this.getCenter();if (extent[0] <= center[0] && extent[2] >= center[0]) {return true;}if (extent[1] <= center[1] && extent[3] >= center[1]) {return true;}return forEachCorner(extent, this.intersectsCoordinate.bind(this));}return false;}setCenter(center) {const stride = this.stride;const radius = this.flatCoordinates[stride] - this.flatCoordinates[0];const flatCoordinates = center.slice();flatCoordinates[stride] = flatCoordinates[0] + radius;for (let i = 1; i < stride; ++i) {flatCoordinates[stride + i] = center[i];}this.setFlatCoordinates(this.layout, flatCoordinates);this.changed();}setCenterAndRadius(center, radius, layout) {this.setLayout(layout, center, 0);if (!this.flatCoordinates) {this.flatCoordinates = [];}const flatCoordinates = this.flatCoordinates;let offset = deflateCoordinate(flatCoordinates, 0, center, this.stride);flatCoordinates[offset++] = flatCoordinates[0] + radius;for (let i = 1, ii = this.stride; i < ii; ++i) {flatCoordinates[offset++] = flatCoordinates[i];}flatCoordinates.length = offset;this.changed();}getCoordinates() {return null;}setCoordinates(coordinates, layout) {}setRadius(radius) {this.flatCoordinates[this.stride] = this.flatCoordinates[0] + radius;this.changed();}rotate(angle, anchor) {const center = this.getCenter();const stride = this.getStride();this.setCenter(rotate(center, 0, center.length, stride, angle, anchor, center));this.changed();}
}
Circle
类的构造函数
Circle
类的构造函数接受三个参数:中心点坐标center
、半径radius
和坐标布局方式layout
。构造函数会先判断,若layout
存在,且半径radius
不存在,则调用this.setFlatCoordinates
方法设置this.layout
、this.stride
和this.flatCoordinates
;否则,判断若radius
不存在或为false
,则修改为0
,最后调用this.setCenterAndRadius
方法,设置中心点和半径。
Circle
类的主要方法
Circle
类的主要方法如下:
-
clone
方法:用于复制一个圆几何对象,内部就是实例化Circle
类,然后调用实例对象的applyProperties
方法,最后返回实例对象。 -
closestPointXY
方法:接受四个参数:给定点x
、y
、最近点坐标closestPoint
和最小距离平方;closestPointXY
方法就是获取给定点距离几何对象(即圆)的最小距离平方,并且修正最近点的坐标值。方法内部会先计算给定点到中心点的距离平方squaredDistance
,然后比较squaredDistance
与minSquaredDistance
的大小;若squaredDistance
大于或等于minSquaredDistance
,则直接返回minSquaredDistance
;否则判断,若squaredDistance
等于0
,这说明给定点就是中心点,然后修改最近点坐标为中心点坐标,并且返回0
;否则,通过几何对象的半径大小和给定点到圆心距离的比例计算出最近点的坐标,然后多维的数据比如M
就保持不变。最后返回给定点到圆心的距离。 -
containsXY
方法:接受两个参数即给定点的坐标x
和y
,然后计算给定点和几何对象中心点的距离平方,比较它和半径平方的大小,若半径平方较大或等于计算的平方,则说明给定点在几何对象内部或者是在圆上。 -
getCenter
方法:用于获取几何对象的中心点坐标。 -
computeExtent
方法:用于获取几何对象的包围盒。 -
getRadius
方法:用于获取几何对象的半径,内部就是调用this.getRadiusSquared_
方法获取半径的平方。 -
getRadiusSquared
方法:获取半径的平方。 -
getType
方法:获取几何对象的类型,Circle
。 -
intersectsExtent
方法:用于判断矩形extent
是否与几何对象相交 -
setCenter
方法:设置几何对象中心点坐标;接受一个参数center
,先从this.flatCoordinates
中计算出半径,然后 重新组装变量flatCoordinates
,再调用this.setFlatCoordinates
方法设置this.flatCoordinates
、this.layout
和this.stride
,最后调用this.changed
方法。 -
setCenterAndRadius
方法:设置几何对象的中心点坐标和半径。 -
getCoordinates
方法:返回null
,因为几何对象圆重要的属性是圆心(即中心点坐标)和半径大小。 -
setCoordinates
方法:未实现。 -
setRadius
方法:用于设置半径,几何对象的半径也是存在this.flatCoordinates
,即this.flatCoordinates
的第三项的大小为x
坐标值加上半径大小,最后会调用this.changed
方法。 -
rotate
方法:接受两个参数:旋转角度angle
和旋转锚点anchor
。方法内部会先分别调用this.getCenter
和this.getStride
方法获取几何对象的中心点坐标和步幅this.stride
,然后调用rotate
方法对中心坐标进行旋转,修改中心点坐标并返回修改后的中心点坐标,然后调用this.setCenter
方法设置中心点坐标,最后调用this.changed
方法。
总结
本文主要介绍了Circle
类的源码实现和原理,精华的地方就是closestPointXY
方法中当给定点(x,y)
在几何对象内部但又不是圆心时,计算最近点距离的逻辑,需要具备一定的数据知识。