# 一.车辆轨迹
# 1.规划路线
查看代码详情
<template>
<div class="content">
<div ref="map" class="map"></div>
<button ref="btn">轨迹回放</button>
</div>
</template>
<script>
export default {
async mounted() {
// 获取轨迹点
let res = await this.$axios({
type: "get",
url: this.$withBase("/data/1.json"),
});
let points = res.data.map((i) =>
ol.proj.transform(i, "EPSG:4326", "EPSG:3857")
);
// 轨迹
var route = new ol.geom.LineString(points);
var routeCoords = route.getCoordinates();
var routeLength = routeCoords.length;
// 轨迹线要素
var routeFeature = new ol.Feature({
type: "route",
geometry: route,
});
// 轨迹点要素
var geoMarker = new ol.Feature({
type: "geoMarker",
geometry: new ol.geom.Point(routeCoords[0]),
});
// 创建样式
var styles = {
route: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 5,
color: "blue",
}),
}),
geoMarker: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
snapToPixel: false,
fill: new ol.style.Fill({
color: "red",
}),
}),
}),
};
var center = points[0];
var animating = false;
var speed, now;
// 创建瓦片图层
var tileLayer = new ol.layer.Tile({
source: new ol.source.OSM(),
});
// 创建要素图层
var vectorLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature, geoMarker],
}),
style: function (feature) {
if (animating && feature.get("type") === "geoMarker") {
return null;
}
return styles[feature.get("type")];
},
});
// 创建地图
var map = new ol.Map({
target: this.$refs.map,
layers: [tileLayer, vectorLayer],
view: new ol.View({
center: center,
zoom: 17,
}),
});
// 监听事件
var moveFeature = function (event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating) {
var elapsedTime = frameState.time - now;
var index = Math.round((speed * elapsedTime) / 1000);
if (index >= routeLength) {
stopAnimation(true);
return;
}
var currentPoint = new ol.geom.Point(routeCoords[index]);
var feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles.geoMarker);
}
map.render();
};
// 开始动画
function startAnimation() {
if (animating) {
stopAnimation(false);
} else {
animating = true;
now = new Date().getTime();
speed = 50;
geoMarker.setStyle(null);
map.getView().setCenter(center);
map.on("postcompose", moveFeature);
map.render();
}
}
// 停止动画
function stopAnimation(ended) {
animating = false;
var coord = ended ? routeCoords[routeLength - 1] : routeCoords[0];
geoMarker.getGeometry().setCoordinates(coord);
map.un("postcompose", moveFeature);
}
// 轨迹回放
this.$refs.btn.addEventListener("click", function () {
startAnimation();
});
},
};
</script>
<style>
.content {
width: 100%;
height: 100%;
}
.map {
width: 100%;
height: 400px;
}
</style>
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
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
# 2.轨迹回放 1
查看代码详情
<template>
<div>
<div ref="map" class="map"></div>
<button ref="btn">轨迹回放</button>
</div>
</template>
<script>
export default {
async mounted() {
// 获取轨迹点
let res = await this.$axios({
type: "get",
url: this.$withBase("/data/1.json"),
});
let points = res.data;
// 轨迹
var route = new ol.geom.LineString(points);
var routeCoords = route.getCoordinates();
var routeLength = routeCoords.length;
// 轨迹线要素
var routeFeature = new ol.Feature({
type: "route",
geometry: route,
});
// 轨迹点要素
var geoMarker = new ol.Feature({
type: "geoMarker",
geometry: new ol.geom.Point(routeCoords[0]),
});
// 创建样式
var styles = {
route: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 5,
color: "blue",
}),
}),
geoMarker: new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
snapToPixel: false,
fill: new ol.style.Fill({
color: "red",
}),
}),
}),
};
var center = [13451034.958002912, 3594986.8806004445];
var animating = false;
var speed, now;
// 创建瓦片图层
var tileLayer = new ol.layer.Tile({
source: new ol.source.OSM(),
});
// 创建轨迹点图层
var markerLayer = new ol.layer.Vector({
source: new ol.source.Vector(),
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 20,
fill: new ol.style.Fill({
color: "red",
}),
}),
}),
});
// 创建轨迹线图层
var lineLayer = new ol.layer.Vector({
source: new ol.source.Vector(),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 5,
color: "blue",
}),
}),
});
// 创建地图
var map = new ol.Map({
target: this.$refs.map,
layers: [tileLayer, markerLayer, lineLayer],
view: new ol.View({
center: center,
zoom: 17,
}),
});
// 定时器
var interval;
var index = 0;
var markerFeature;
// 显示轨迹
this.$refs.btn.addEventListener("click", function () {
// 清除定时器
if (interval != undefined) {
clearInterval(interval);
}
// 清空要素图层
markerLayer.getSource().clear();
lineLayer.getSource().clear();
index = 0;
// 绘制轨迹线
if (points.length > 1) {
var lineFeature = new ol.Feature({
geometry: new ol.geom.LineString(points),
});
lineLayer.getSource().addFeature(lineFeature);
}
// 创建定时器
interval = setInterval(function () {
if (index < points.length) {
// 清除已有轨迹点
markerLayer.getSource().clear();
// 添加轨迹点
var currentPoint = points[index];
markerFeature = new ol.Feature({
geometry: new ol.geom.Point(currentPoint),
});
markerLayer.getSource().addFeature(markerFeature);
// 索引+1
index++;
} else {
clearInterval(interval);
index = 0;
}
}, 10);
});
},
};
</script>
<style>
.map {
width: 100%;
height: 400px;
}
</style>
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
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
# 3.轨迹回放 2
查看代码详情
<template>
<div class="content">
<div ref="map" class="map" />
<div class="handle">
<label for="speed">
速度:
<input
ref="speed"
type="range"
min="10"
max="999"
step="10"
value="60"
/>
</label>
<button ref="startanimation">开始</button>
<button ref="pauseanimation">暂停</button>
<button ref="continueanimation">继续</button>
<button ref="stopanimation">结束</button>
</div>
</div>
</template>
<script>
let {
geom: { Point, LineString },
format: { Polyline },
Feature,
Map,
View,
layer: { Tile: TileLayer, Vector: VectorLayer },
source: { OSM, Vector: VectorSource, XYZ },
style: { Circle: CircleStyle, Fill, Stroke, Style, Icon },
interaction: { Draw, Modify, Snap },
proj: { get },
} = ol;
export default {
data() {
return {
center: [-5639523.95, -3501274.52],
map: null,
polyline: "",
route: null,
routes: null,
routeLength: 0,
routeCoords: [],
routeCoordsX: [],
routeCoordsY: [],
routeFeature: null,
geoMarker: null,
startMarker: null,
endMarker: null,
styles: {},
animating: false,
vectorLayer: null,
startTime: undefined,
startButton: undefined,
stoptime: null,
timer: null,
elapsedTime: 0,
timerFlag: false,
index: 0,
};
},
mounted() {
const that = this;
this.map = new Map({
target: this.$refs.map,
view: new View({
center: this.center,
zoom: 10,
minZoom: 2,
maxZoom: 18,
}),
layers: [
new TileLayer({
source: new XYZ({
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}",
projection: "EPSG:3857",
}),
}),
],
});
this.polyline =
"hldhx@lnau`BCG_EaC??cFjAwDjF??uBlKMd@}@z@??aC^yk@z_@se@b[wFdE??wFfE}NfIoGxB_I\\gG}@eHoCyTmPqGaBaHOoD\\??yVrGotA|N??o[N_STiwAtEmHGeHcAkiA}^aMyBiHOkFNoI`CcVvM??gG^gF_@iJwC??eCcA]OoL}DwFyCaCgCcCwDcGwHsSoX??wI_EkUFmq@hBiOqBgTwS??iYse@gYq\\cp@ce@{vA}s@csJqaE}{@iRaqE{lBeRoIwd@_T{]_Ngn@{PmhEwaA{SeF_u@kQuyAw]wQeEgtAsZ}LiCarAkVwI}D??_}RcjEinPspDwSqCgs@sPua@_OkXaMeT_Nwk@ob@gV}TiYs[uTwXoNmT{Uyb@wNg]{Nqa@oDgNeJu_@_G}YsFw]kDuZyDmm@i_@uyIJe~@jCg|@nGiv@zUi_BfNqaAvIow@dEed@dCcf@r@qz@Egs@{Acu@mCum@yIey@gGig@cK_m@aSku@qRil@we@{mAeTej@}Tkz@cLgr@aHko@qOmcEaJw~C{w@kai@qBchBq@kmBS{kDnBscBnFu_Dbc@_~QHeU`IuyDrC_}@bByp@fCyoA?qMbD}{AIkeAgBk_A_A{UsDke@gFej@qH{o@qGgb@qH{`@mMgm@uQus@kL{_@yOmd@ymBgwE}x@ouBwtA__DuhEgaKuWct@gp@cnBii@mlBa_@}|Asj@qrCg^eaC}L{dAaJ_aAiOyjByH{nAuYu`GsAwXyn@ywMyOyqD{_@cfIcDe}@y@aeBJmwA`CkiAbFkhBlTgdDdPyiB`W}xDnSa}DbJyhCrXitAhT}x@bE}Z_@qW_Kwv@qKaaAiBgXvIm}A~JovAxCqW~WanB`XewBbK{_A`K}fBvAmi@xBycBeCauBoF}}@qJioAww@gjHaPopA_NurAyJku@uGmi@cDs[eRaiBkQstAsQkcByNmaCsK_uBcJgbEw@gkB_@ypEqDoqSm@eZcDwjBoGw`BoMegBaU_`Ce_@_uBqb@ytBwkFqiT_fAqfEwe@mfCka@_eC_UmlB}MmaBeWkkDeHwqAoX}~DcBsZmLcxBqOwqE_DkyAuJmrJ\\o~CfIewG|YibQxBssB?es@qGciA}RorAoVajA_nAodD{[y`AgPqp@mKwr@ms@umEaW{dAmb@umAw|@ojBwzDaaJsmBwbEgdCsrFqhAihDquAi`Fux@}_Dui@_eB_u@guCuyAuiHukA_lKszAu|OmaA{wKm}@clHs_A_rEahCssKo\\sgBsSglAqk@yvDcS_wAyTwpBmPc|BwZknFoFscB_GsaDiZmyMyLgtHgQonHqT{hKaPg}Dqq@m~Hym@c`EuiBudIabB{hF{pWifx@snAw`GkFyVqf@y~BkoAi}Lel@wtc@}`@oaXi_C}pZsi@eqGsSuqJ|Lqeb@e]kgPcaAu}SkDwzGhn@gjYh\\qlNZovJieBqja@ed@siO{[ol\\kCmjMe\\isHorCmec@uLebB}EqiBaCg}@m@qwHrT_vFps@kkI`uAszIrpHuzYxx@e{Crw@kpDhN{wBtQarDy@knFgP_yCu\\wyCwyA{kHo~@omEoYmoDaEcPiuAosDagD}rO{{AsyEihCayFilLaiUqm@_bAumFo}DgqA_uByi@swC~AkzDlhA}xEvcBa}Cxk@ql@`rAo|@~bBq{@``Bye@djDww@z_C_cAtn@ye@nfC_eC|gGahH~s@w}@``Fi~FpnAooC|u@wlEaEedRlYkrPvKerBfYs}Arg@m}AtrCkzElw@gjBbh@woBhR{gCwGkgCc[wtCuOapAcFoh@uBy[yBgr@c@iq@o@wvEv@sp@`FajBfCaq@fIipAdy@ewJlUc`ExGuaBdEmbBpBssArAuqBBg}@s@g{AkB{bBif@_bYmC}r@kDgm@sPq_BuJ_s@{X_{AsK_d@eM{d@wVgx@oWcu@??aDmOkNia@wFoSmDyMyCkPiBePwAob@XcQ|@oNdCoSfFwXhEmOnLi\\lbAulB`X_d@|k@au@bc@oc@bqC}{BhwDgcD`l@ed@??bL{G|a@eTje@oS~]cLr~Bgh@|b@}Jv}EieAlv@sPluD{z@nzA_]`|KchCtd@sPvb@wSb{@ko@f`RooQ~e[upZbuIolI|gFafFzu@iq@nMmJ|OeJn^{Qjh@yQhc@uJ~j@iGdd@kAp~BkBxO{@|QsAfYgEtYiGd]}Jpd@wRhVoNzNeK`j@ce@vgK}cJnSoSzQkVvUm^rSgc@`Uql@xIq\\vIgg@~kDyq[nIir@jNoq@xNwc@fYik@tk@su@neB}uBhqEesFjoGeyHtCoD|D}Ed|@ctAbIuOzqB_}D~NgY`\\um@v[gm@v{Cw`G`w@o{AdjAwzBh{C}`Gpp@ypAxn@}mAfz@{bBbNia@??jIab@`CuOlC}YnAcV`@_^m@aeB}@yk@YuTuBg^uCkZiGk\\yGeY}Lu_@oOsZiTe[uWi[sl@mo@soAauAsrBgzBqgAglAyd@ig@asAcyAklA}qAwHkGi{@s~@goAmsAyDeEirB_{B}IsJuEeFymAssAkdAmhAyTcVkFeEoKiH}l@kp@wg@sj@ku@ey@uh@kj@}EsFmG}Jk^_r@_f@m~@ym@yjA??a@cFd@kBrCgDbAUnAcBhAyAdk@et@??kF}D??OL";
this.route = new Polyline({
factor: 1e6,
}).readGeometry(this.polyline, {
dataProjection: "EPSG:4326",
featureProjection: "EPSG:3857",
});
for (var i = 0; i < this.route.flatCoordinates.length; i++) {
if (i % 2 == 0) {
this.routeCoordsX.push(this.route.flatCoordinates[i]);
} else {
this.routeCoordsY.push(this.route.flatCoordinates[i]);
}
}
// 将[1,2,3,4,5,6...]转为[[1,2],[3,4],[5,6]...]
for (var i = 0; i < this.routeCoordsX.length; i++) {
this.routeCoords.push([this.routeCoordsX[i], this.routeCoordsY[i]]);
}
// 矢量元素要呈现的几何图形的特征属性LineString代表线段
this.routes = new LineString(this.routeCoords);
console.log(this.routes);
this.routeLength = this.routeCoords.length;
this.routeFeature = new Feature({
type: "route",
geometry: this.routes,
});
this.geoMarker = new Feature({
type: "geoMarker",
geometry: new Point(this.routeCoords[0]),
});
this.startMarker = new Feature({
type: "iconStart",
geometry: new Point(this.routeCoords[0]),
});
this.endMarker = new Feature({
type: "iconEnd",
geometry: new Point(this.routeCoords[this.routeLength - 1]),
});
this.styles = {
route: new Style({
stroke: new Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
iconStart: new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: this.$withBase("/data/square.svg"),
}),
}),
iconEnd: new Style({
image: new Icon({
anchor: [0.5, 0.5],
src: this.$withBase("/data/dot.svg"),
}),
}),
geoMarker: new Style({
image: new Icon({
anchor: [0.5, 0.5], // 图标中心
src: this.$withBase("/data/dot.svg"),
scale: 0.6,
rotation: -Math.atan2(
this.routeCoords[0][1] - this.routeCoords[1][1],
this.routeCoords[0][0] - this.routeCoords[1][0]
),
rotateWithView: true,
}),
}),
};
this.vectorLayer = new VectorLayer({
source: new VectorSource({
features: [
this.routeFeature,
this.geoMarker,
this.startMarker,
this.endMarker,
],
}),
style: function (feature) {
if (that.animating && feature.get("type") === "geoMarker") {
return null;
}
return that.styles[feature.get("type")];
},
});
this.map.addLayer(this.vectorLayer);
this.$refs.startanimation.addEventListener(
"click",
function () {
this.animating = true;
this.startTime = new Date().getTime();
// 隐藏geoMarker
this.geoMarker.changed();
this.map.getView().setCenter(this.center);
// 添加事件,地图渲染时触发
if (this.timer) {
clearInterval(this.timer);
}
this.timer = setInterval(() => {
moveFeature.call(this);
}, 60);
this.elapsedTime = 0;
}.bind(this),
false
);
this.$refs.pauseanimation.addEventListener(
"click",
function () {
clearInterval(this.timer);
this.timerFlag = true;
}.bind(this),
false
);
this.$refs.continueanimation.addEventListener(
"click",
function () {
if (this.timerFlag) {
this.map.getView().setCenter(this.center);
// 添加事件,地图渲染时触发
this.timer = setInterval(() => {
moveFeature.call(this);
}, 60);
}
this.timerFlag = false;
}.bind(this),
false
);
this.$refs.stopanimation.addEventListener(
"click",
function (ended) {
clearInterval(this.timer);
this.vectorLayer.getSource().clear();
this.vectorLayer.getSource().addFeature(this.routeFeature);
this.vectorLayer.getSource().addFeature(this.startMarker);
this.vectorLayer.getSource().addFeature(this.endMarker);
}.bind(this),
false
);
function moveFeature(event) {
if (!this.vectorLayer.getVisible()) {
this.vectorLayer.setVisible(true);
}
var carStyle, rotation;
// 开始动画
this.elapsedTime++; // elapsedTime 已过时间
this.index = Math.round(
(Number(this.$refs.speed.value) * this.elapsedTime) / 60
); // 已经走了多少个点
var x, y;
if (this.index >= this.routeCoords.length) {
clearInterval(this.timer);
return;
}
if (this.routeCoords[this.index] && this.routeCoords[this.index + 1]) {
x =
this.routeCoords[this.index][0] - this.routeCoords[this.index + 1][0];
y =
this.routeCoords[this.index][1] - this.routeCoords[this.index + 1][1];
// 返回从原点(0,0)到(x,y)点的线段与x轴正方向之间的弧度值
rotation = Math.atan2(y, x);
} else {
rotation = 0;
}
carStyle = new Style({
image: new Icon({
src: this.$withBase("/data/icon.png"),
rotateWithView: false,
rotation:
-rotation +
Math.atan2(
this.routeCoords[0][1] - this.routeCoords[1][1],
this.routeCoords[0][0] - this.routeCoords[1][0]
) /
2,
scale: 0.6,
anchor: [0.5, 0.5], // 图标中心
}),
});
var line = new Feature({
geometry: new LineString(this.routeCoords),
});
var lineStyle = new Style({
stroke: new Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
});
line.setStyle(lineStyle);
var currentPoint = new Point(this.routeCoords[this.index]);
// 添加矢量元素
var feature = new Feature(currentPoint);
this.vectorLayer.getSource().clear();
feature.setStyle(carStyle);
this.vectorLayer.getSource().addFeature(this.routeFeature);
this.vectorLayer.getSource().addFeature(this.startMarker);
this.vectorLayer.getSource().addFeature(this.endMarker);
this.vectorLayer.getSource().addFeature(feature);
this.map.render();
}
},
};
</script>
<style>
.content {
width: 100%;
height: 100%;
position: relative;
}
.map {
width: 100%;
height: 100%;
}
.handle{
position: absolute;
bottom: 0;
left: 0;
}
</style>
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303