MultiLineString类
# 概述
在 Openlayers 中,MultiLineString
类用于创建多个线段,和LineString
类类似(可参考这篇文字。MultiLineString
类也是继承于SimpleGeometry
类,关于该类,可以参考。
本文主要介绍MultiLineString
类的源码实现和原理。
# 源码分析
# MultiLineString
类的源码实现
class MultiLineString extends SimpleGeometry {
constructor(coordinates, layout, ends) {
super();
this.ends_ = [];
this.maxDelta_ = -1;
this.maxDeltaRevision_ = -1;
if (Array.isArray(coordinates[0])) {
this.setCoordinates(coordinates, layout);
} else if (layout !== undefined && ends) {
this.setFlatCoordinates(layout, coordinates);
this.ends_ = ends;
} else {
const lineStrings = coordinates;
const flatCoordinates = [];
const ends = [];
for (let i = 0, ii = lineStrings.length; i < ii; ++i) {
const lineString = lineStrings[i];
extend(flatCoordinates, lineString.getFlatCoordinates());
ends.push(flatCoordinates.length);
}
const layout =
lineStrings.length === 0
? this.getLayout()
: lineStrings[0].getLayout();
this.setFlatCoordinates(layout, flatCoordinates);
this.ends_ = ends;
}
}
appendLineString(lineString) {
extend(this.flatCoordinates, lineString.getFlatCoordinates().slice());
this.ends_.push(this.flatCoordinates.length);
this.changed();
}
clone() {
const multiLineString = new MultiLineString(
this.flatCoordinates.slice(),
this.layout,
this.ends_.slice()
);
multiLineString.applyProperties(this);
return multiLineString;
}
closestPointXY(x, y, closestPoint, minSquaredDistance) {
if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
return minSquaredDistance;
}
if (this.maxDeltaRevision_ != this.getRevision()) {
this.maxDelta_ = Math.sqrt(
arrayMaxSquaredDelta(
this.flatCoordinates,
0,
this.ends_,
this.stride,
0
)
);
this.maxDeltaRevision_ = this.getRevision();
}
return assignClosestArrayPoint(
this.flatCoordinates,
0,
this.ends_,
this.stride,
this.maxDelta_,
false,
x,
y,
closestPoint,
minSquaredDistance
);
}
getCoordinateAtM(m, extrapolate, interpolate) {
if (
(this.layout != "XYM" && this.layout != "XYZM") ||
this.flatCoordinates.length === 0
) {
return null;
}
extrapolate = extrapolate !== undefined ? extrapolate : false;
interpolate = interpolate !== undefined ? interpolate : false;
return lineStringsCoordinateAtM(
this.flatCoordinates,
0,
this.ends_,
this.stride,
m,
extrapolate,
interpolate
);
}
getCoordinates() {
return inflateCoordinatesArray(
this.flatCoordinates,
0,
this.ends_,
this.stride
);
}
getEnds() {
return this.ends_;
}
getLineString(index) {
if (index < 0 || this.ends_.length <= index) {
return null;
}
return new LineString(
this.flatCoordinates.slice(
index === 0 ? 0 : this.ends_[index - 1],
this.ends_[index]
),
this.layout
);
}
getFlatMidpoints() {
const midpoints = [];
const flatCoordinates = this.flatCoordinates;
let offset = 0;
const ends = this.ends_;
const stride = this.stride;
for (let i = 0, ii = ends.length; i < ii; ++i) {
const end = ends[i];
const midpoint = interpolatePoint(
flatCoordinates,
offset,
end,
stride,
0.5
);
extend(midpoints, midpoint);
offset = end;
}
return midpoints;
}
getSimplifiedGeometryInternal(squaredTolerance) {
const simplifiedFlatCoordinates = [];
const simplifiedEnds = [];
simplifiedFlatCoordinates.length = douglasPeuckerArray(
this.flatCoordinates,
0,
this.ends_,
this.stride,
squaredTolerance,
simplifiedFlatCoordinates,
0,
simplifiedEnds
);
return new MultiLineString(simplifiedFlatCoordinates, "XY", simplifiedEnds);
}
getType() {
return "MultiLineString";
}
intersectsExtent(extent) {
return intersectsLineStringArray(
this.flatCoordinates,
0,
this.ends_,
this.stride,
extent
);
}
setCoordinates(coordinates, layout) {
this.setLayout(layout, coordinates, 2);
if (!this.flatCoordinates) {
this.flatCoordinates = [];
}
const ends = deflateCoordinatesArray(
this.flatCoordinates,
0,
coordinates,
this.stride,
this.ends_
);
this.flatCoordinates.length = ends.length === 0 ? 0 : ends[ends.length - 1];
this.changed();
}
}
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
174
175
176
177
# MultiLineString
类的构造函数
MultiLineString
类的构造函数接受三个参数:坐标数组coordinates
、坐标布局方式layout
和每个线段的结束点ends
;构造函数内部还定义了两个变量this.maxDelta_
和this.maxDeltaRevision_
用于记录几何对象的修订版本号,在几何对象进行重新计算和渲染时用于判断是否使用缓存,可以提高性能,它们初始值都是为-1
;构造函数会判断参数coordinates
是否为一个二维数组,若是,则调用this.setCoordinates
方法设置坐标;否则,判断参数layout
和ends
,若它们都传值了,则调用this.setFlatCoordinates
方法;否则认为coordinates
表示的是多个线段的数组;然后循环遍历它,将每个线段的坐标数据添加到变量flatCoordinates
中,并且将每个线段的坐标长度添加到ends
中,最后调用this.setFlatCoordinates
方法,设置坐标。
# MultiLineString
类的主要方法
MultiLineString
类的主要方法如下:
appendLineString
方法:向当前几何对象中添加一条线段,参数lineString
是LineString
类的实例,内部就是会调用lineString.getFlatCoordinates
获取参数线段的坐标,然后将它添加到this.flatCoordinates
中,更新this.ends_
的值,最后调用this.changed
方法clone
方法:复制几何对象,实例化MultiLineString
类,调用applyProperties
方法应用属性,最后返回实例对象。closestPointXY
方法: 接受四个参数,给定点的x
、y
、最近点closestPoint
和最小距离平方minSquaredDistance
;closestPointXY
方法内部会先调用closestSquaredDistanceXY
计算给定点与包围盒的最小距离的平方,将之与minSquaredDistance
的大小进行对比,若minSquaredDistance
较小,则返回它;否则,判断几何对象是否发生了改变,若未改变,则使用之前的this.maxDelta_
调用assignClosestArrayPoint
方法计算最小距离平方并返回,并且更新最近点坐标closestPoint
;若改变了,则调用arrayMaxSquaredDelta
方法计算几何对象相邻两点坐标的最大距离,将其赋值给this.maxDelta_
,更新this.maxDeltaRevision_
的值,最后调用assignClosestArrayPoint
方法。getCoordinateAtM
方法:使用线性插值返回几何对象在属性为M
处的坐标,如果不存在,则返回null
egetCoordinates
方法:返回坐标数据,内部就是调用inflateCoordinatesArray
方法将扁平化一维数组this.flatCoordinates
转为多维数组并返回。getEnds
方法:返回this.ends
值,即返回所有线段的结束点getLineString
方法:接受一个参数index
,判断参数index
是否合法;然后截取this.flatCoordinates
实例化LineString
类并返回实例对象。getLineStrings
方法:返回几何对象的所有线段,通过遍历this.ends
截取this.flatCoordinates
,然后实例化LineString
类,最后返回包含所有线段的lineStrings
数组。getFlatMidpoints
方法:返回所有线段的中点,核心方法是interpolatePoint
获取每条线段的中点,然后将其放入数组midpoints
中,最后返回。getSimplifiedGeometryInternal
方法:该方法用于获取几何对象的简化版,内部也是调用douglasPeucker
算法进行简化几何对象,获取简化对象的坐标数据,然后传入获取的坐标数据 实例化MultiLineString
类,最后返回实例。getType
方法:返回几何对象的类型,MultiLineString
intersectsExtent
方法:判断矩形extent
是否与几何对象相交,内部调用的是intersectsLineStringArray
方法并返回其结果;setCoordinates
方法:设置坐标this.flatCoordinates
,坐标布局方式this.layout
以及步幅this.stride
# 总结
本文介绍了MultiLineString
类的源码实现,说白了就是多线段几何对象,很多方法都和LineString
类相似。