GeometryCollection类
# 概述
本文主要介绍GeometryCollection
类,GeometryCollection
类继承于Geometry
类,关于Geometry
类,参考这篇文章
GeometryCollection
类就是一组几何对象的集合.
# 源码分析
# GeometryCollection
类源码实现
GeometryCollection
类源码实现如下:
class GeometryCollection extends Geometry {
constructor(geometries) {
super();
this.geometries_ = geometries;
this.changeEventKeys_ = [];
this.listenGeometriesChange_();
}
unlistenGeometriesChange_() {
this.changeEventsKeys_.forEach(unlistenByKey);
this.changeEventsKeys_.length = 0;
}
listenGeometriesChange_() {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
this.changeEventsKeys_.push(
listen(geometries[i], EventType.CHANGE, this.changed, this)
);
}
}
clone() {
const geometryCollection = new GeometryCollection(
cloneGeometries(this.geometries_)
);
geometryCollection.applyProperties(this);
return geometryCollection;
}
closestPointXY(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
minSquaredDistance = geometries[i].closestPointXY(
x,
y,
closestPoint,
minSquaredDistance
);
}
return minSquaredDistance;
}
containsXY(x, y) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].containsXY(x, y)) {
return true;
}
}
return false;
}
computeExtent(extent) {
createOrUpdateEmpty(extent);
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
extend(extent, geometries[i].getExtent());
}
return extent;
}
getGeometries() {
return cloneGeometries(this.geometries_);
}
getGeometriesArray() {
return this.geometries_;
}
getGeometriesArrayRecursive() {
/** @type {Array<Geometry>} */
let geometriesArray = [];
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].getType() === this.getType()) {
geometriesArray = geometriesArray.concat(
geometries[i].getGeometriesArrayRecursive()
);
} else {
geometriesArray.push(geometries[i]);
}
}
return geometriesArray;
}
getSimplifiedGeometry(squaredTolerance) {
if (this.simplifiedGeometryRevision !== this.getRevision()) {
this.simplifiedGeometryMaxMinSquaredTolerance = 0;
this.simplifiedGeometryRevision = this.getRevision();
}
if (
squaredTolerance < 0 ||
(this.simplifiedGeometryMaxMinSquaredTolerance !== 0 &&
squaredTolerance < this.simplifiedGeometryMaxMinSquaredTolerance)
) {
return this;
}
const simplifiedGeometries = [];
const geometries = this.geometries_;
let simplified = false;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
const geometry = geometries[i];
const simplifiedGeometry =
geometry.getSimplifiedGeometry(squaredTolerance);
simplifiedGeometries.push(simplifiedGeometry);
if (simplifiedGeometry !== geometry) {
simplified = true;
}
}
if (simplified) {
const simplifiedGeometryCollection = new GeometryCollection(
simplifiedGeometries
);
return simplifiedGeometryCollection;
}
this.simplifiedGeometryMaxMinSquaredTolerance = squaredTolerance;
return this;
}
getType() {
return "GeometryCollection";
}
intersectsExtent(extent) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
if (geometries[i].intersectsExtent(extent)) {
return true;
}
}
return false;
}
isEmpty() {
return this.geometries_.length === 0;
}
rotate(angle, anchor) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].rotate(angle, anchor);
}
this.changed();
}
scale(sx, sy, anchor) {
if (!anchor) {
anchor = getCenter(this.getExtent());
}
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].scale(sx, sy, anchor);
}
this.changed();
}
setGeometries(geometries) {
this.setGeometriesArray(cloneGeometries(geometries));
}
setGeometriesArray(geometries) {
this.unlistenGeometriesChange_();
this.geometries_ = geometries;
this.listenGeometriesChange_();
this.changed();
}
applyTransform(transformFn) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].applyTransform(transformFn);
}
this.changed();
}
translate(deltaX, deltaY) {
const geometries = this.geometries_;
for (let i = 0, ii = geometries.length; i < ii; ++i) {
geometries[i].translate(deltaX, deltaY);
}
this.changed();
}
disposeInternal() {
this.unlistenGeometriesChange_();
super.disposeInternal();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# GeometryCollection
类构造函数
GeometryCollection
类构造函数接受一个参数geometries
,geometries
是一个包含多个几何对象数组,该参数会赋给全局变量this.geometries_
,然后初始化一个变量this.changeEventsKeys_
为空数组,最后调用this.listenGeometriesChange_
方法.
# GeometryCollection
类的方法
GeometryCollection
类的方法主要是对几何对象的一些操作,会去遍历this.geometries_
变量,逐一进行操作.GeometryCollection
类中的主要方法如下:
listenGeometriesChange_
方法:该方法在构造函数中就会被调用,其核心逻辑就是循环遍历this.geometries_
,调用listen
方法注册每个几何对象的change
事件监听,注册事件返回的keys
值保存在全局变量this.changeEventsKeys_
中.listen
方法的实现可以参考这篇文章unlistenGeometriesChange_
方法:用于取消监听,重置this.changeEventKeys_
为空数组,解绑方法unlistenByKey
同样是在event.js
中实现的.clone
方法:clone
方法会返回一个新的几何对象集合,其内部会先调用cloneGeometries
方法去clone
每一个Geometry
,然后实例化GeometryCollection
类,再会调用applyProperties
去应用this
,applyProperties
方法是在Object
类中实现的,主要就是复制属性.closestPointXY
方法:用于获取对几何对象稽核最近的点坐标,以及修改并获取最短距离;方法接受四个参数目标点坐标x``y
,最近点坐标以及最短距离,会先调用closestSquaredDistanceXY
获取目标坐标点到边界范围的平方距离,若最短距离大于该参数最短平方距离,则返回参数minSquaredDistance
;然后遍历this.geometries_
,调用每一个几何对象的closestPointXY
方法,修改最近点坐标和最短距离;最后返回最短距离containsXY
方法:同样地也是遍历this.geometries_
,调用几何对象的containsXY
方法;containsXY
方法就是判断点是否在几何对象集合的边界上,返回一个布尔值。computeExtent
方法:获取几何对象集合的边界范围getGeometries
方法:获取几何对象集合的副本,调用cloneGeometries
方法getGeometriesArray
方法:获取几何对象集合数组getGeometriesArrayRecursive
方法:将嵌套的几何对象(如子集合)展平成一个平坦的数组,即若几何对象数组中的数组项也是一个数组,那么就会递归调用它的getGeometriesArrayRecursive
方法。getSimplifiedGeometry
方法:该方法就是用于简化几何,采用了Douglas-Peucker
算法。这个算法常用于简化折线几何,减少点的数量,同时尽可能保持原始几何形状的准确性。简化通过一个容差值来控制简化的程度,容差值越大,简化的结果就越简单。getSimplifiedGeometry
方法会先检查修订号,若当前几何对象的修订号与上次简化的修订号不一致这说明几何对象已经发生了变化,需要重新计算简化后的几何对象;然后会检查容差值,若容差值小于0
或者小于已经记录的最大容差值,则不需要重新计算,直接返回当前对象;然后初始化一个空数组,simplifiedGeometries
用于存储简化后的几何对象,再遍历this.geometries_
,调用每个几何对象的getSimplifiedGeometry
方法,简化每一个几何对象;若简化后的实例对象不等于原始对象,则将simplified
赋值为true
,然后实例化GeometryCollection
类,生成一个几何对象集合实例并返回;若简化后的实例对象与原始对象相同,一个几何对象也没有被简化,则返回当前对象this
.getType
方法:获取类型,返回GeometryCollection
intersectsExtent
方法:遍历this.geometries_
,然后调用每个几何对象的intersectsExtent
方法,判断几何对象是否与extent
相交;若有一个几何对象和extent
相交则返回true
;若一个都不相交,则返回false
。isEmpty
方法:判断几何对象集合是否为空,返回一个布尔值。rotate
方法:遍历this.geometries_
,然后调用每个几何对象的rotate
方法,最后调用this.changed
方法scale
方法:遍历this.geometries_
,然后调用每个几何对象的scale
方法,最后调用this.changed
方法setGeometries
方法:会先调用cloneGeometries
方法clone
每个几何对象,然后调用this.setGeometriesArray
方法setGeometriesArray
方法:会调用this.unlistenGeometriesChange_
取消监听,然后设置this.geometries_
,再调用this.listenGeometriesChange_
方法注册监听,最后调用this.changed
方法applyTransform
方法:遍历this.geometries_
,然后调用每个几何对象的applyTransform
方法,最后调用this.changed
方法translate
方法:遍历this.geometries_
,然后调用每个几何对象的translate
方法,最后调用this.changed
方法disposeInternal
方法:清理函数,调用this.unlistenGeometriesChange_
取消监听,再调用父类的disposeInternal
方法
# 总结
本文介绍了GeometryCollection
类的源码实现,由此可以清晰理解GeometryCollection
类主要还是一组多个对几何对象进行平移、旋转和缩放转换以及空间关系的判断等等。