Jinuss's blog Jinuss's blog
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

前端可视化
首页
  • 前端文章

    • JavaScript
  • 学习笔记

    • 《JavaScript高级程序设计》
    • 《Vue》
    • 《React》
    • 《Git》
    • JS设计模式总结
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 核心基类

  • Control控件篇

  • Geom几何图形篇

    • Geom几何图形篇介绍
    • Geometry基类
    • GeometryCollection类
    • SimpleGeometry类
    • Point类
    • MultiPoint类
    • LinearRing类
    • Polygon类
    • MultiPolygon类
      • 概述
      • 源码分析
        • MultiPolygon类的源码实现
        • MultiPolygon类的构造函数
        • MultiPolygon类的主要方法
      • 总结
    • LineString类
    • MultiLineString类
    • Circle类
  • Layer图层篇

  • Renderer篇

  • Feature篇

  • style样式篇

  • 《Openlayers源码》笔记
  • Geom几何图形篇
东流
2024-12-28
目录

MultiPolygon类

# 概述

在Openlayers中,MultiPolygon类顾名思义就是表示由多个多边形组成的几何对象,关于Polygon类可以参考这篇文章;同Polygon类一样,MultiPolygon类继承于SimpleGeometry类。

本文主要介绍MultiPolygon类的源码实现和原理。

# 源码分析

# MultiPolygon类的源码实现

MultiPolygon类的源码实现如下:

class MultiPolygon extends SimpleGeometry {
  constructor(coordinates, layout, endss) {
    super();
    this.endss_ = [];
    this.flatInteriorPointRevision_ = -1;
    this.flatInteriorPoints = null;
    this.maxDelta_ = -1;
    this.maxDeltaRevision_ = -1;
    this.orientedRevision_ = -1;
    this.orientedFlatCoordinates_ = null;

    if (!endss && !Array.isArray(coordinates[0])) {
      const polygons = coordinates;
      const flatCoordinates = [];
      const thisEndss = [];
      for (let i = 0, ii = polygons.length; i < ii; ++i) {
        const polygon = polygons[i];
        const offset = flatCoordinates.length;
        const ends = polygon.getEnds();
        for (let j = 0, jj = ends.length; j < jj; ++j) {
          ends[j] += offset;
        }
        extend(flatCoordinates, polygon.getFlatCoordinates());
        thisEndss.push(ends);
      }
      layout =
        polygons.length === 0 ? this.getLayout() : polygons[0].getLayout();
      coordinates = flatCoordinates;
      endss = thisEndss;
    }

    if (layout !== undefined && endss) {
      this.setFlatCoordinates(layout, coordinates);
      this.endss_ = endss;
    } else {
      this.setCoordinates(coordinates, layout);
    }
  }
  appendPolygon(polygon) {
    let ends;
    if (!this.flatCoordinates) {
      this.flatCoordinates = polygon.getFlatCoordinates().slice();
      ends = polygon.getEnds().slice();
      this.endss_.push();
    } else {
      const offset = this.flatCoordinates.length;
      extend(this.flatCoordinates, polygon.getFlatCoordinates());
      ends = polygon.getEnds().slice();
      for (let i = 0, ii = ends.length; i < ii; ++i) {
        ends[i] += offset;
      }
    }
    this.endss_.push(ends);
    this.changed();
  }
  clone() {
    const len = this.endss_.length;
    const newEndss = new Array(len);
    for (let i = 0; i < len; ++i) {
      newEndss[i] = this.endss_[i].slice();
    }

    const multiPolygon = new MultiPolygon(
      this.flatCoordinates.slice(),
      this.layout,
      newEndss
    );
    multiPolygon.applyProperties(this);

    return multiPolygon;
  }

  closestPointXY(x, y, closestPoint, minSquaredDistance) {
    if (minSquaredDistance < closestSquaredDistanceXY(this.getExtent(), x, y)) {
      return minSquaredDistance;
    }
    if (this.maxDeltaRevision_ != this.getRevision()) {
      this.maxDelta_ = Math.sqrt(
        multiArrayMaxSquaredDelta(
          this.flatCoordinates,
          0,
          this.endss_,
          this.stride,
          0
        )
      );
      this.maxDeltaRevision_ = this.getRevision();
    }

    return assignClosestMultiArrayPoint(
      this.getOrientedFlatCoordinates(),
      0,
      this.endss_,
      this.stride,
      this.maxDelta_,
      true,
      x,
      y,
      closestPoint,
      minSquaredDistance
    );
  }
  containsXY(x, y) {
    return linearRingssContainsXY(
      this.getOrientedFlatCoordinates(),
      0,
      this.endss_,
      this.stride,
      x,
      y
    );
  }
  getArea() {
    return linearRingssArea(
      this.getOrientedFlatCoordinates(),
      0,
      this.endss_,
      this.stride
    );
  }
  getCoordinates(right) {
    let flatCoordinates;
    if (right !== undefined) {
      flatCoordinates = this.getOrientedFlatCoordinates().slice();
      orientLinearRingsArray(
        flatCoordinates,
        0,
        this.endss_,
        this.stride,
        right
      );
    } else {
      flatCoordinates = this.flatCoordinates;
    }

    return inflateMultiCoordinatesArray(
      flatCoordinates,
      0,
      this.endss_,
      this.stride
    );
  }
  getEnds() {
    return this.endss_;
  }
  getFlatInteriorPoint() {
    if (this.flatInteriorPointsRevision_ != this.getRevision()) {
      const flatCenters = linearRingssCenter(
        this.flatCoordinates,
        0,
        this.endss_,
        this.stride
      );
      this.flatInteriorPoints_ = getInteriorPointsOfMultiArray(
        this.getOrientedFlatCoordinates(),
        0,
        this.endss_,
        this.stride,
        flatCenters
      );
      this.flatInteriorPointsRevision_ = this.getRevision();
    }
    return this.flatInteriorPoints_;
  }
  getInteriorPoints() {
    return new MultiPoint(this.getFlatInteriorPoints().slice(), "XYM");
  }
  getOrientedFlatCoordiantes() {
    if (this.orientedRevision_ != this.getRevision()) {
      const flatCoordinates = this.flatCoordinates;
      if (
        linearRingssAreOriented(flatCoordinates, 0, this.endss_, this.stride)
      ) {
        this.orientedFlatCoordinates_ = flatCoordinates;
      } else {
        this.orientedFlatCoordinates_ = flatCoordinates.slice();
        this.orientedFlatCoordinates_.length = orientLinearRingsArray(
          this.orientedFlatCoordinates_,
          0,
          this.endss_,
          this.stride
        );
      }
      this.orientedRevision_ = this.getRevision();
    }
    return this.orientedFlatCoordinates_;
  }
  getSimplifiedGeometryInternal(squaredTolerance) {
    const simplifiedFlatCoordinates = [];
    const simplifiedEndss = [];
    simplifiedFlatCoordinates.length = quantizeMultiArray(
      this.flatCoordinates,
      0,
      this.endss_,
      this.stride,
      Math.sqrt(squaredTolerance),
      simplifiedFlatCoordinates,
      0,
      simplifiedEndss
    );
    return new MultiPolygon(simplifiedFlatCoordinates, "XY", simplifiedEndss);
  }
  getPolygon(index) {
    if (index < 0 || this.endss_.length <= index) {
      return null;
    }
    let offset;
    if (index === 0) {
      offset = 0;
    } else {
      const prevEnds = this.endss_[index - 1];
      offset = prevEnds[prevEnds.length - 1];
    }
    const ends = this.endss_[index].slice();
    const end = ends[ends.length - 1];
    if (offset !== 0) {
      for (let i = 0, ii = ends.length; i < ii; ++i) {
        ends[i] -= offset;
      }
    }
    return new Polygon(
      this.flatCoordinates.slice(offset, end),
      this.layout,
      ends
    );
  }
  getPolygons() {
    const layout = this.layout;
    const flatCoordinates = this.flatCoordinates;
    const endss = this.endss_;
    const polygons = [];
    let offset = 0;
    for (let i = 0, ii = endss.length; i < ii; ++i) {
      const ends = endss[i].slice();
      const end = ends[ends.length - 1];
      if (offset !== 0) {
        for (let j = 0, jj = ends.length; j < jj; ++j) {
          ends[j] -= offset;
        }
      }
      const polygon = new Polygon(
        flatCoordinates.slice(offset, end),
        layout,
        ends
      );
      polygons.push(polygon);
      offset = end;
    }
    return polygons;
  }
  getType() {
    return "MultiPolygon";
  }
  intersectsExtent(extent) {
    return intersectsLinearRingMultiArray(
      this.getOrientedFlatCoordinates(),
      0,
      this.endss_,
      this.stride,
      extent
    );
  }
  setCoordinates(coordinates, layout) {
    this.setLayout(layout, coordinates, 3);
    if (!this.flatCoordinates) {
      this.flatCoordinates = [];
    }
    const endss = deflateMultiCoordinatesArray(
      this.flatCoordinates,
      0,
      coordinates,
      this.stride,
      this.endss_
    );
    if (endss.length === 0) {
      this.flatCoordinates.length = 0;
    } else {
      const lastEnds = endss[endss.length - 1];
      this.flatCoordinates.length =
        lastEnds.length === 0 ? 0 : lastEnds[lastEnds.length - 1];
    }
    this.changed();
  }
}
1
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284

# MultiPolygon类的构造函数

MultiPolygon类构造函数接受三个参数:坐标数据coordinates、坐标布局layout和endss每个多边形结束点数组;在Polygon类的构造函数中用this.ends_存储每个线性环的结束坐标的索引,而在MultiPolygon类中用this.endss_存储每个多边形的结束点新鲜,每个多边形的结束点是一个坐标数组;其余变量如this.flatInteriorPointRevision_等等同Polygon类中一样,都是用于优化几何对象的处理和渲染、比如计算多边形的内部点、顶点排序变化等;MultiPolygon类的构造函数还会判断,若参数endss不存在并且coordinates的第一个值不是数组,即coordinates是一个包含多个多边形对象的数组,则遍历这些多边形,获取其结束点ends并将它们根据当前的偏移调整,然后将多个多边形的坐标扁平化最后赋值给coordinates,将每个多边形的结束点数组存储到this.Endss最后赋值给endss;然后根据坐标布局风格layout和endss来决定是调用this.setFlatCoordiantes还是this.setCoordiantes设置this.endss_、this.layout、this.stride和this.flatCoordinates。

# MultiPolygon类的主要方法

MultiPolygon类的主要方法如下

  • appendPolygon方法:该方法是向当前几何对象添加一个多边形,接受一个参数polygon多边形;首先会判断,若this.flatCoordinates不存在,则调用polygon.getFlatCoordiantes方法获取参数多边形的坐标赋值给this.flatCoordiantes;并且获取多边形的结束点;若存在,则获取多边形的坐标添加到this.faltCoordiantes中,并且获取多边形坐标的长度,以此来设置该多边形的结束点的偏移值,然后将ends添加到this.endss_的末端,最后调用this.changed方法

  • clone方法:复制当前几何对象,通过this.endss_获取每个多边形的结束点信息,然后实例化MultiPolygon类,调用实例对象的applyProperties方法应用属性,最后返回实例对象。

  • closestPointXY方法:计算给定点(x,y)到当前几何对象的最近距离的平方,以及可能会修改最近点坐标closestPoint和最近距离的平方minSquaredDistance;方法内部同Polygon类中同名函数类似,会基于几何对象发生变化时重新计算this.maxDelta_

  • containsXY方法:判断给定点(x,y)是否在当前几何对象内部或者边界上,内部会逐一判断每个多边形是否包含该点,若包含则返回true;否则判断下一个多边形,若都不包含,则返回false.

  • getArea方法:获取当前几何对象的面积,内部调用的方法是linearRingsArea方法

  • getCoordinates方法:获取几何对象的坐标,内部就是调用inflateMultiCoordinatesArray方法

  • getEnds方法:获取this.endss_的值

  • getFlatInteriorPoints方法:实现原理和Polygon类中的同名函数类似,不过是需要通过this.endss_变量获取每个多边形的坐标,再计算对应多边形的内部点,也就说this.flatInteriorPoints_中保存的是每个多边形的内部点

  • getInteriorPoints方法:获取当前几何对象每个多边形的内部点

  • getOrientedFlatCoordiantes方法:实现原理和Polygon类中的同名函数一样

  • getSimplifiedGeometryInternal方法:获取简化后的几何对象,接受一个参数squaredTolerance容差平方,该值越大,表示要去除的点更多;内部是调用quantizeMultiArray方法进行简化当前几何对象,简化后对象的坐标保存在simplifiedFlatCoordiantes中,最后调用MultiPolygon实例化并返回实例对象

  • getPolygon方法:返回几何对象中索引值对应的多边形,首先会计算参数index是否合法,然后通过index和this.endss_计算该索引值对应的坐标,然后调用Polygon类实例化一个多边形,最后返回该多边形的实例。

  • getPolygons方法:获取几何对象的多边形,以数组形式返回;通过this.endss_变量计算其中某个多边形的坐标(起止位置),然后调用Polygon进行实例化,将其实例对象保存到数组polygons中最后返回。

  • getType方法:返回当前几何对象的类型,MultiPolygon

  • intersectExtent方法:判断extent是否与当前几何对象相交,内部是调用intersectsLinearRingMultiArray方法

  • setCoordinates方法:内部是调用delatMultiCoordinatesArray方法,设置this.flatCoordinates、this.layout和this.stride,最后调用this.changed方法

# 总结

本文主要介绍了MultiPolygon类的实现原理,MultiPolygon类和Polygon类的实现原理几乎大同小异。

编辑 (opens new window)
上次更新: 2024/12/28, 15:32:49
Polygon类
LineString类

← Polygon类 LineString类→

最近更新
01
GeoJSON
05-08
02
Circle
04-15
03
CircleMarker
04-15
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式