曾经坐在飞机上俯瞰整个北京城,在万米高空上可以看到北京的全貌,即使是凌晨一两点,北京依然灯火通明,俨然是一座不眠之城。四通八达的交通线仿佛是这座城市的血脉,里面流淌着的,是生活在这里的人们的梦想。
然而,今天要讲的不是北京,也不是梦想。今天要讲的是我们该如何在地图上点起一盏灯,就像夜幕下的北京城一样。
为了方便理解,我们先看一下最终的实现效果。
最终效果.png
没错,就是要在夜幕下,放几盏灯,告诉别人这块区域目前有人正在里面工作。
在讲解如何实现这种效果前,先分享一下之前的那种存在问题的思路。
之前的做法是:
- 位于底部的阴影区域当做一个大的
PolygonView
,并且充满屏幕。 - 位于上面的高亮区域当做另外的
PolygonView
,依次添加,并设置它们的背景色与透明度,模拟高亮。
然而这样做会产生一个无法避免的问题,那就是无论我们怎么设置高亮区域的背景色与透明度,都不够好看:透明度低的时候,就看不到下面的地图,透明度高的时候,虽然能看到下面的地图,但是却雾蒙蒙的,仿佛那片高亮区域,被雾霾笼罩了。。
那么问题来了,如何让大晚上还在工作的人们,少呼吸点雾霾呢。
思路其实很简单,只需要换个角度来思考就可以了,那就是我们不再分别绘制高亮区域和底部的全屏阴影区域,而是只需要绘制一个阴影区域就可以了,这样剩下的没有绘制的区域自然就是没有雾霾的。
对,再说一遍,只需要绘制一个阴影区域就可以。
先来一张图:
屏幕的四个点分别是S1、S2、S3、S4
,两个高亮区域分别是区域A
和区域B
,区域A的四个点分别是A1、A2、A3、A4,区域B的四个点分别是B1、B2、B3、B4。我们要绘制的就是除去区域A,区域B
后,把剩下的那部分当做一个PolygonView
来绘制。(注意:这里所说的点是指经纬度点,而不是point点)
So
,如何得到阴影区域的Polygon
:
- 首先声明一个经纬度数组
CLLocationCoordinate2D * coors
,用来存放区域坐标点。 - 先从
S1点
开始,将其加入到coors
中,下一个点是A1点
,然后依次添加A2、A3、A4
。 - 添加完
A4
后,** 一定要再将A1点
加一遍**,以构成一个闭环,而不是直接去添加区域B的点,此时A1点
被添加了两遍。 - 接着添加
区域B
的点,先是B1点
,然后依次添加B2、B3、B4
。 - 添加完
B4
后,像区域A
一样,一定要再添加一遍B1点
,以构成闭环。此时B1点
被添加两遍。 - 由于此时只有两个区域,所以添加完
B1点
后,我们需要返回,这里需要注意的一定要原路返回。所以需要再添加一遍A1点
,此时A1点
被添加了3遍(注意:非屏幕边界点最多被添加三遍)。 - 接着我们需要再次添加
S1点
,也就是说从S1点
,出去转了一圈后,最后必须回到S1点
。此时S1点
被添加2遍。(注意:屏幕边界点最多也是被添加3遍)。 - 最后再依次添加
S2、S3、S4
点构成闭环就可以了。
总结一下规律,我们需要从屏幕四个角的任意一个点
开始,假设是S1点
,然后依次添加区域A、区域B、区域C
等区域的点,区域点添加完一圈后,一定要把区域的第一个点再添加一遍,然后再去添加另一个区域的点
,添加完后,依然要再加一遍该区域的第一个点
,如果当前区域是最后一个
区域了,那么添加完后,需要让它原路返回
,也就是说除了最后一个区域的起点是填加两遍
,其他区域的起点都是添加三遍
,添加完后,再添加一遍屏幕的S1点
,最后就是按照顺时针或者逆时针添加屏幕的剩余三个点,添加完三个点后,必须再添加S1点,构成闭合(此时点被添加三遍)。
这样我们就只需要绘制这么一个整合后的阴影区域就可以了。由此就实现了我们的去雾霾目的。
过程有点绕,可能不太好理解,那怎么办,多看几遍然后自己试一试就可以了。demo还是之前的给你的地图模块动手术的demo。代码比较多,但是却很简单,所以文章里就不写代码了,本文介绍的关键在于这种思路,使用的时候,只需要借鉴思路,并且这种思路是通用的,移动端与web端都适用。
为了方便大伙,下面给出对数据的程序处理。
/*从self.locationArray中获取数据进行展示,
里面存储的是一个个模型数组,模型是TestPolygonModel,有lng与lat属性
*/
/*1、获取需要malloc的内存区域,由以下几个部分组成:
• 6个屏幕点
• self.locationArray.count*2 - 1 计算多边形起点被多加的次数,
后面的减一是因为最后一个数组的第一个点只需要多加一遍,其他的都是多加两遍,
注意这里计算的是起点被多加的次数,而不是起点被添加的总次数。
• self.locationArray子数组中元素的个数和,self.locationArray存放的是经纬度模型数组。
*/
NSInteger mallocCount = 0;//需要分配的内存大小,也就是经纬度数组中总共的点数,也就是上面提到的三部分之和
NSInteger itemCount = 0; //也就是self.locationArray子数组中经纬度模型的个数和
NSInteger itemIndex = 0; //coors下表
for (int i = 0; i<self.locationArray.count; i++) {
itemCount = itemCount + [self.locationArray[i] count];
}
mallocCount = 6 + self.locationArray.count * 2 - 1 + itemCount;
/*2、正序计算,无论是不是最后一个数组,先依次将该数组的点加进去,加完后再加一遍该数组中的第一个点。*/
CLLocationCoordinate2D * coors = (CLLocationCoordinate2D *)malloc(mallocCount * sizeof(CLLocationCoordinate2D));
/*添加屏幕左下角的S1点*/
coors[0].longitude = self.mapView.region.center.longitude-self.mapView.region.span.longitudeDelta*1.5;
coors[0].latitude = self.mapView.region.center.latitude-self.mapView.region.span.latitudeDelta*1.5;
/*正序添加每一个数组中的所有元素*/
for (int i = 0; i < self.locationArray.count; i++) {
NSArray *polygonArray = self.locationArray[i];
for (int j = 0; j<polygonArray.count; j++) {
TestPolygonModel *polygonModel = self.locationArray[i][j]; //获取model
itemIndex++;
coors[itemIndex].longitude = [polygonModel.lng floatValue];
coors[itemIndex].latitude = [polygonModel.lat floatValue];
}
//添加完每一组的元素后,需要再添加一遍该组的第一个点,
itemIndex ++;
TestPolygonModel *startPolygon = polygonArray[0];
coors[itemIndex].latitude = [startPolygon.lat floatValue];
coors[itemIndex].longitude = [startPolygon.lng floatValue];
}
/*3、倒叙添加每一组的第一个元素,但是最后一个组不需要添加,因为最后一个组总共只需要加两遍,所以过滤掉最后一组*/
for (NSInteger i = self.locationArray.count - 1; i>0; i--) {
itemIndex ++;
TestPolygonModel *startPolygon = self.locationArray[i-1][0]; //获取model
coors[itemIndex].latitude = [startPolygon.lat floatValue];
coors[itemIndex].longitude = [startPolygon.lng floatValue];
}
/*4、添加屏幕的边界点*/
/*再次添加屏幕的起点*/
itemIndex ++;
coors[itemIndex].longitude = self.mapView.region.center.longitude-self.mapView.region.span.longitudeDelta*1.5;
coors[itemIndex].latitude = self.mapView.region.center.latitude-self.mapView.region.span.latitudeDelta*1.5;
/*添加屏幕右下角的S2点*/
itemIndex ++;
coors[itemIndex].longitude = self.mapView.region.center.longitude+self.mapView.region.span.longitudeDelta*1.5;
coors[itemIndex].latitude = self.mapView.region.center.latitude-self.mapView.region.span.latitudeDelta*1.5;
/*添加屏幕右上角的S3点*/
itemIndex ++;
coors[itemIndex].longitude = self.mapView.region.center.longitude+self.mapView.region.span.longitudeDelta*1.5;
coors[itemIndex].latitude = self.mapView.region.center.latitude+self.mapView.region.span.latitudeDelta*1.5;
/*添加屏幕左上角的S4点*/
itemIndex ++;
coors[itemIndex].longitude = self.mapView.region.center.longitude-self.mapView.region.span.longitudeDelta*1.5;
coors[itemIndex].latitude = self.mapView.region.center.latitude+self.mapView.region.span.latitudeDelta*1.5;
/*再次添加屏幕左下角的S1点*/
itemIndex ++;
coors[itemIndex].longitude = self.mapView.region.center.longitude-self.mapView.region.span.longitudeDelta*1.5;
coors[itemIndex].latitude = self.mapView.region.center.latitude-self.mapView.region.span.latitudeDelta*1.5;
if (mallocCount == itemIndex+1) {
BMKPolygon *polygonModel0 = [BMKPolygon polygonWithCoordinates:coors count:mallocCount];
[self.mapView addOverlay:polygonModel0];
}else{
[SVProgressHUD showErrorWithStatus:@"计算错误"];
}
好吧,作者比较懒,三篇文章,只留下了一个demo。
网友评论
https://lxqjss.github.io/test/wkt.html