BMKClusterAlgorithm.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. //
  2. // BMKClusterAlgorithm.m
  3. // IphoneMapSdkDemo
  4. //
  5. // Created by wzy on 15/9/15.
  6. // Copyright © 2015年 Baidu. All rights reserved.
  7. //
  8. #import "BMKClusterAlgorithm.h"
  9. #define MAX_DISTANCE_IN_DP 200 //300dp
  10. @implementation BMKClusterAlgorithm
  11. @synthesize quadItems = _quadItems;
  12. @synthesize quadtree = _quadtree;
  13. - (id)init {
  14. self = [super init];
  15. if (self) {
  16. _quadtree = [[BMKClusterQuadtree alloc] initWithRect:CGRectMake(0, 0, 1, 1)];
  17. _quadItems = [[NSMutableArray alloc] init];
  18. }
  19. return self;
  20. }
  21. ///添加item
  22. - (void)addItem:(BMKClusterItem*)clusterItem {
  23. BMKQuadItem *quadItem = [[BMKQuadItem alloc] init];
  24. quadItem.clusterItem = clusterItem;
  25. @synchronized(_quadtree) {
  26. [_quadItems addObject:quadItem];
  27. [_quadtree addItem:quadItem];
  28. // NSLog(@"%@", _quadtree.quadItems);
  29. }
  30. }
  31. ///清除items
  32. - (void)clearItems {
  33. @synchronized(_quadtree) {
  34. [_quadItems removeAllObjects];
  35. [_quadtree clearItems];
  36. }
  37. }
  38. /**
  39. * cluster算法核心
  40. * @param zoom map的级别
  41. * @return BMKCluster数组
  42. */
  43. - (NSArray*)getClusters:(CGFloat) zoomLevel {
  44. if (zoomLevel < 3 || zoomLevel > 22) {
  45. return nil;
  46. }
  47. NSMutableArray *results = [NSMutableArray array];
  48. NSUInteger zoom = (NSUInteger)zoomLevel;
  49. CGFloat zoomSpecificSpan = MAX_DISTANCE_IN_DP / pow(2, zoom) / 256;
  50. NSMutableSet *visitedCandidates = [NSMutableSet set];
  51. NSMutableDictionary *distanceToCluster = [NSMutableDictionary dictionary];
  52. NSMutableDictionary *itemToCluster = [NSMutableDictionary dictionary];
  53. @synchronized(_quadtree) {
  54. for (BMKQuadItem *candidate in _quadItems) {
  55. //candidate已经添加到另一cluster中
  56. if ([visitedCandidates containsObject:candidate]) {
  57. continue;
  58. }
  59. BMKCluster *cluster = [[BMKCluster alloc] init];
  60. cluster.coordinate = candidate.clusterItem.coor;
  61. cluster.dataDic = candidate.clusterItem.dataDic;
  62. CGRect searchRect = [self getRectWithPt:candidate.pt Span:zoomSpecificSpan];
  63. NSMutableArray *items = (NSMutableArray*)[_quadtree searchInRect:searchRect];
  64. if (items.count == 1) {
  65. [cluster.clusterItems addObject:candidate.clusterItem];
  66. cluster.dataArr = [NSMutableArray arrayWithArray:@[candidate.clusterItem.dataDic]];
  67. [results addObject:cluster];
  68. [visitedCandidates addObject:candidate];
  69. [distanceToCluster setObject:[NSNumber numberWithDouble:0] forKey:[NSNumber numberWithLongLong:candidate.hash]];
  70. continue;
  71. }
  72. NSMutableArray *mArr = [NSMutableArray new];
  73. for (BMKQuadItem *quadItem in items) {
  74. NSNumber *existDistache = [distanceToCluster objectForKey:[NSNumber numberWithLongLong:quadItem.hash]];
  75. CGFloat distance = [self getDistanceSquared:candidate.pt point:quadItem.pt];
  76. if (existDistache != nil) {
  77. if (existDistache.doubleValue < distance) {
  78. continue;
  79. }
  80. BMKCluster *existCluster = [itemToCluster objectForKey:[NSNumber numberWithLongLong:quadItem.hash]];
  81. [existCluster.clusterItems removeObject:quadItem.clusterItem];
  82. [existCluster.dataArr removeObject:quadItem.clusterItem.dataDic];
  83. }
  84. [distanceToCluster setObject:[NSNumber numberWithDouble:distance] forKey:[NSNumber numberWithLongLong:quadItem.hash]];
  85. [cluster.clusterItems addObject:quadItem.clusterItem];
  86. [mArr addObject:quadItem.clusterItem.dataDic];
  87. [itemToCluster setObject:cluster forKey:[NSNumber numberWithLongLong:quadItem.hash]];
  88. }
  89. [visitedCandidates addObjectsFromArray:items];
  90. cluster.dataArr = mArr;
  91. [results addObject:cluster];
  92. }
  93. }
  94. return results;
  95. }
  96. - (CGRect)getRectWithPt:(CGPoint) pt Span:(CGFloat) span {
  97. CGFloat half = span / 2.f;
  98. return CGRectMake(pt.x - half, pt.y - half, span, span);
  99. }
  100. - (CGFloat)getDistanceSquared:(CGPoint) pt1 point:(CGPoint) pt2 {
  101. return (pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y);
  102. }
  103. @end