BMKClusterAlgorithm.m 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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 zoomLevel 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.title = candidate.clusterItem.title;
  62. cluster.subTitle = candidate.clusterItem.subTitle;
  63. CGRect searchRect = [self getRectWithPt:candidate.pt Span:zoomSpecificSpan];
  64. NSMutableArray *items = (NSMutableArray*)[_quadtree searchInRect:searchRect];
  65. if (items.count == 1) {
  66. [cluster.clusterItems addObject:candidate.clusterItem];
  67. [results addObject:cluster];
  68. [visitedCandidates addObject:candidate];
  69. [distanceToCluster setObject:[NSNumber numberWithDouble:0] forKey:[NSNumber numberWithLongLong:candidate.hash]];
  70. continue;
  71. }
  72. for (BMKQuadItem *quadItem in items) {
  73. NSNumber *existDistache = [distanceToCluster objectForKey:[NSNumber numberWithLongLong:quadItem.hash]];
  74. CGFloat distance = [self getDistanceSquared:candidate.pt point:quadItem.pt];
  75. if (existDistache != nil) {
  76. if (existDistache.doubleValue < distance) {
  77. continue;
  78. }
  79. BMKCluster *existCluster = [itemToCluster objectForKey:[NSNumber numberWithLongLong:quadItem.hash]];
  80. [existCluster.clusterItems removeObject:quadItem.clusterItem];
  81. }
  82. [distanceToCluster setObject:[NSNumber numberWithDouble:distance] forKey:[NSNumber numberWithLongLong:quadItem.hash]];
  83. [cluster.clusterItems addObject:quadItem.clusterItem];
  84. [itemToCluster setObject:cluster forKey:[NSNumber numberWithLongLong:quadItem.hash]];
  85. }
  86. [visitedCandidates addObjectsFromArray:items];
  87. [results addObject:cluster];
  88. }
  89. }
  90. return results;
  91. }
  92. - (CGRect)getRectWithPt:(CGPoint) pt Span:(CGFloat) span {
  93. CGFloat half = span / 2.f;
  94. return CGRectMake(pt.x - half, pt.y - half, span, span);
  95. }
  96. - (CGFloat)getDistanceSquared:(CGPoint) pt1 point:(CGPoint) pt2 {
  97. return (pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y);
  98. }
  99. @end