iPhone Χάρτης εντοπίζει συμπλέγματος Kit

ψήφοι
23

Όσον αφορά το iPhone Χάρτης Kit εντοπίζει συμπλέγματος:

Έχω 1000 των σημάτων που θέλω να δείξω στον χάρτη, αλλά είναι ακριβώς πάρα πολλά για να χειριστεί έτσι θέλω να τους σύμπλεγμα.

Υπάρχουν πλαίσια διαθέσιμα ή την απόδειξη των εννοιών; Ότι αυτό είναι δυνατό ή έχει ήδη γίνει;

Δημοσιεύθηκε 12/01/2010 στις 09:52
πηγή χρήστη
Σε άλλες γλώσσες...                            


8 απαντήσεις

ψήφοι
13

Μπορείτε να χρησιμοποιήσετε REVClusterMap να συγκεντρώνονται

Απαντήθηκε 18/07/2011 στις 06:54
πηγή χρήστη

ψήφοι
8

Σημείωση: Αυτό είναι ένα εμπορικό προϊόν Είμαι συνδεδεμένες με, αλλά αυτό λύνει αυτό ακριβώς το πρόβλημα.

Θα λυθεί αυτό το πρόβλημα σε μερικές από τις εφαρμογές μου και αποφάσισα να το εξαγάγετε σε ένα επαναχρησιμοποιήσιμο πλαίσιο. Αυτό λέγεται SuperPIN και είναι ένα (εμπορικό, άδεια κοστίζει $ 149) Πλαίσιο iOS που χρησιμοποιεί εσωτερικά τετραδικά δένδρα για την αποθήκευση σχολιασμό και εκτελεί δικτύου με βάση την ομαδοποίηση. Ο αλγόριθμος είναι αρκετά γρήγορη, η συμπεριληφθούν εφαρμογή του δείγματος δείχνει τα αεροδρόμια του κόσμου (πάνω από 30k + σχολιασμούς) και τρέχει αρκετά ομαλό για ένα 3G iPhone.

Απαντήθηκε 02/05/2011 στις 15:18
πηγή χρήστη

ψήφοι
6

Προσπάθησα οι άλλοι που προτείνεται εδώ, και βρήκα επίσης OCMapView που λειτούργησε το καλύτερο.

δωρεάν και επιτρέπει την εύκολη ομαδοποίηση των σχολιασμών, το οποίο είναι ό, τι χρειαζόμουν. ένα κομμάτι της νεότερα και πιο ενημερωμένες από Revolver και για μένα είναι πιο εύκολο να εφαρμοστεί.

Απαντήθηκε 05/02/2013 στις 22:05
πηγή χρήστη

ψήφοι
6

Αυτό θα μπορούσε να είναι λίγο σαν να χρησιμοποιείτε ένα αλυσοπρίονο για να κόψει το γκαζόν, αλλά εδώ είναι ένα απόσπασμα από Αλγόριθμοι με λίγα λόγια

Η δημιουργία ενός KD-Tree ...

public class KDFactory {
  // Known comparators for partitioning points along dimensional axes.
  private static Comparator<IMultiPoint> comparators[ ] ;
  // Recursively construct KDTree using median method on input points.
  public static KDTree generate (IMultiPoint [ ] points) {
    if (points. length == 0) { return null; }
    // median will be the root.
    int maxD = points[ 0] . dimensionality( );
    KDTree tree = new KDTree(maxD) ;
    // Make dimensional comparators that compare points by ith dimension
    comparators = new Comparator[ maxD+1] ;
    for (int i = 1; i <= maxD; i++) {
      comparators[ i] = new DimensionalComparator(i) ;
    }
    tree. setRoot(generate (1, maxD, points, 0, points. length-1) ) ;
    return tree;
  }

  // generate the node for the d-th dimension (1 <= d <= maxD)
  // for points[ left, right]
  private static DimensionalNode generate (int d, int maxD,
                                           IMultiPoint points[ ] ,
                                           int left, int right) {
    // Handle the easy cases first
    if (right < left) { return null; }
    if (right == left) { return new DimensionalNode (d, points[ left] ) ; }
    // Order the array[ left, right] so the mth element will be the median
    // and the elements prior to it will all be <=, though they won' t
    // necessarily be sorted; similarly, the elements after will all be >=
    int m = 1+(right-left) /2;
    Selection. select(points, m, left, right, comparators[ d] ) ;
    // Median point on this dimension becomes the parent
    DimensionalNode dm = new DimensionalNode (d, points[ left+m-1] ) ;
    // update to the next dimension, or reset back to 1
    if (++d > maxD) { d = 1; }
    // recursively compute left and right sub-trees, which translate
    // into ' below' and ' above' for n-dimensions.
    dm. setBelow(maxD, generate (d, maxD, points, left, left+m-2) ) ;
    dm. setAbove(maxD, generate (d, maxD, points, left+m, right) ) ;
    return dm;
  }
}

Βρίσκοντας το πλησιέστερο γείτονες καλύτερα: O (log n) χειρότερη O (n)

// method in KDTree
public IMultiPoint nearest (IMultiPoint target) {
  if (root == null) return null;
  // find parent node to which target would have been inserted. This is our
  // best shot at locating closest point; compute best distance guess so far
  DimensionalNode parent = parent(target) ;
  IMultiPoint result = parent. point;
  double smallest = target. distance(result) ;
  // now start back at the root, and check all rectangles that potentially
  // overlap this smallest distance. If better one is found, return it.
  double best[ ] = new double[ ] { smallest };
  double raw[ ] = target. raw( );
  IMultiPoint betterOne = root. nearest (raw, best) ;
  if (betterOne ! = null) { return betterOne; }
  return result;
}

// method in DimensionalNode. min[ 0] contains best computed shortest distance.
IMultiPoint nearest (double[ ] rawTarget, double min[ ] ) {
    // Update minimum if we are closer.
    IMultiPoint result = null;
    // If shorter, update minimum
    double d = shorter(rawTarget, min[ 0] ) ;
    if (d >= 0 && d < min[ 0] ) {
      min[ 0] = d;
      result = point;
    }
    // determine if we must dive into the subtrees by computing direct
    // perpendicular distance to the axis along which node separates
    // the plane. If d is smaller than the current smallest distance,
    // we could "bleed" over the plane so we must check both.
    double dp = Math. abs(coord - rawTarget[ dimension-1] ) ;
    IMultiPoint newResult = null;
    if (dp < min[ 0] ) {
      // must dive into both. Return closest one.
      if (above ! = null) {
        newResult = above. nearest (rawTarget, min) ;
        if (newResult ! = null) { result = newResult; }
      }
      if (below ! = null) {
        newResult = below. nearest(rawTarget, min) ;
        if (newResult ! = null) {  result = newResult; }
      }
    } else {
      // only need to go in one! Determine which one now.
      if (rawTarget[ dimension-1] < coord) {
        if (below ! = null) {
          newResult = below. nearest (rawTarget, min) ;
        }
      } else {
        if (above ! = null) {
          newResult = above. nearest (rawTarget, min) ;
        }
      }
      // Use smaller result, if found.
      if (newResult ! = null) { return newResult; }
    }
    return result;
  }

Περισσότερα για KD-Δέντρα στο Wikipedia

Απαντήθηκε 13/01/2010 στις 17:39
πηγή χρήστη

ψήφοι
1

Είχα πρόσφατα την εφαρμογή σχολιασμό ομαδοποίηση με MapKit. Οι λύσεις που αναφέρονται παραπάνω είναι καλές, ανάλογα με την περίπτωση χρήσης σας. Κατέληξα να πηγαίνει με FBAnnotationClustering (Objective-C) επειδή ήταν δωρεάν, και είχε πολλά αστέρια και μερικά θέματα για GitHub:

https://github.com/infinum/FBAnnotationClustering

Η εφαρμογή δούλευα σε αυτό πολύ χάρτης-centric, οπότε ήταν λογικό να μεταφράσει FBAnnotationClustering σε Swift. Εδώ είναι μια θέση blog για την προσέγγιση, η οποία περιλαμβάνει μια σύνδεση με το δείγμα έργου για GitHub.

http://ribl.co/blog/2015/05/28/map-clustering-with-swift-how-we-implemented-it-into-the-ribl-ios-app/

Απαντήθηκε 29/06/2015 στις 17:50
πηγή χρήστη

ψήφοι
1

Μια απόδειξη της έννοιας είναι εκτός σύνδεσης εφαρμογή Χάρτες «OffMaps»?)

http://itunes.apple.com/us/app/offmaps/id313854422?mt=8

Απαντήθηκε 14/01/2010 στις 21:23
πηγή χρήστη

ψήφοι
0

Εμπνευσμένο από WWDC 2011 βίντεο, αυτός ο κώδικας λειτουργεί πολύ καλά για μένα. Ίσως όχι ο γρηγορότερος όλων προτείνεται εδώ, αλλά είναι δωρεάν και είναι σίγουρα το πιο απλό.

Είναι ουσιαστικά χρησιμοποιούν 2 χάρτες. Το ένα είναι κρυφό και κρατήστε πατημένο το κάθε σχολιασμού (allAnnotationMapView τον κωδικό μου). Η μία είναι ορατή και εμφανίζει μόνο τις συστάδες ή τα σχόλια, αν και μόνο (MapView τον κωδικό μου).

- (void)didZoom:(UIGestureRecognizer*)gestureRecognizer {
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded){
        [self updateVisibleAnnotations];
    }
}
- (void)updateVisibleAnnotations {
    static float marginFactor = 2.0f;
    static float bucketSize = 50.0f;
    MKMapRect visibleMapRect = [self.mapView visibleMapRect];
    MKMapRect adjustedVisibleMapRect = MKMapRectInset(visibleMapRect, -marginFactor * visibleMapRect.size.width, -marginFactor * visibleMapRect.size.height);

    CLLocationCoordinate2D leftCoordinate = [self.mapView convertPoint:CGPointZero toCoordinateFromView:self.view];
    CLLocationCoordinate2D rightCoordinate = [self.mapView convertPoint:CGPointMake(bucketSize, 0) toCoordinateFromView:self.view];
    double gridSize = MKMapPointForCoordinate(rightCoordinate).x - MKMapPointForCoordinate(leftCoordinate).x;
    MKMapRect gridMapRect = MKMapRectMake(0, 0, gridSize, gridSize);

    double startX = floor(MKMapRectGetMinX(adjustedVisibleMapRect) / gridSize) * gridSize;
    double startY = floor(MKMapRectGetMinY(adjustedVisibleMapRect) / gridSize) * gridSize;
    double endX = floor(MKMapRectGetMaxX(adjustedVisibleMapRect) / gridSize) * gridSize;
    double endY = floor(MKMapRectGetMaxY(adjustedVisibleMapRect) / gridSize) * gridSize;

    gridMapRect.origin.y = startY;
    while(MKMapRectGetMinY(gridMapRect) <= endY) {
        gridMapRect.origin.x = startX;
        while (MKMapRectGetMinX(gridMapRect) <= endX) {
            NSSet *allAnnotationsInBucket = [self.allAnnotationMapView annotationsInMapRect:gridMapRect];
            NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];

            NSMutableSet *filteredAnnotationsInBucket = [[allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
                BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
                BOOL shouldBeMerged = NO;
                if (isPointMapItem) {
                    PointMapItem *pointItem = (PointMapItem *)obj;
                    shouldBeMerged = pointItem.shouldBeMerged;
                }
                return shouldBeMerged;
            }] mutableCopy];
            NSSet *notMergedAnnotationsInBucket = [allAnnotationsInBucket objectsPassingTest:^BOOL(id obj, BOOL *stop) {
                BOOL isPointMapItem = [obj isKindOfClass:[PointMapItem class]];
                BOOL shouldBeMerged = NO;
                if (isPointMapItem) {
                    PointMapItem *pointItem = (PointMapItem *)obj;
                    shouldBeMerged = pointItem.shouldBeMerged;
                }
                return isPointMapItem && !shouldBeMerged;
            }];
            for (PointMapItem *item in notMergedAnnotationsInBucket) {
                [self.mapView addAnnotation:item];
            }

            if(filteredAnnotationsInBucket.count > 0) {
                PointMapItem *annotationForGrid = (PointMapItem *)[self annotationInGrid:gridMapRect usingAnnotations:filteredAnnotationsInBucket];
                [filteredAnnotationsInBucket removeObject:annotationForGrid];
                annotationForGrid.containedAnnotations = [filteredAnnotationsInBucket allObjects];
                [self.mapView addAnnotation:annotationForGrid];
                //force reload of the image because it's not done if annotationForGrid is already present in the bucket!!
                MKAnnotationView* annotationView = [self.mapView viewForAnnotation:annotationForGrid];
                NSString *imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
                UILabel *countLabel = [[UILabel alloc] initWithFrame:CGRectMake(15, 2, 8, 8)];
                [countLabel setFont:[UIFont fontWithName:POINT_FONT_NAME size:10]];
                [countLabel setTextColor:[UIColor whiteColor]];
                [annotationView addSubview:countLabel];
                imageName = [AnnotationsViewUtils imageNameForItem:annotationForGrid selected:NO];
                annotationView.image = [UIImage imageNamed:imageName];

                if (filteredAnnotationsInBucket.count > 0){
                    [self.mapView deselectAnnotation:annotationForGrid animated:NO];
                }
                for (PointMapItem *annotation in filteredAnnotationsInBucket) {
                    [self.mapView deselectAnnotation:annotation animated:NO];
                    annotation.clusterAnnotation = annotationForGrid;
                    annotation.containedAnnotations = nil;
                    if ([visibleAnnotationsInBucket containsObject:annotation]) {
                        CLLocationCoordinate2D actualCoordinate = annotation.coordinate;
                        [UIView animateWithDuration:0.3 animations:^{
                            annotation.coordinate = annotation.clusterAnnotation.coordinate;
                        } completion:^(BOOL finished) {
                            annotation.coordinate = actualCoordinate;
                            [self.mapView removeAnnotation:annotation];
                        }];
                    }
                }
            }
            gridMapRect.origin.x += gridSize;
        }
        gridMapRect.origin.y += gridSize;
    }
}

- (id<MKAnnotation>)annotationInGrid:(MKMapRect)gridMapRect usingAnnotations:(NSSet *)annotations {
    NSSet *visibleAnnotationsInBucket = [self.mapView annotationsInMapRect:gridMapRect];
    NSSet *annotationsForGridSet = [annotations objectsPassingTest:^BOOL(id obj, BOOL *stop) {
        BOOL returnValue = ([visibleAnnotationsInBucket containsObject:obj]);
        if (returnValue) {
            *stop = YES;
        }
        return returnValue;
    }];

    if (annotationsForGridSet.count != 0) {
        return [annotationsForGridSet anyObject];
    }
    MKMapPoint centerMapPoint = MKMapPointMake(MKMapRectGetMinX(gridMapRect), MKMapRectGetMidY(gridMapRect));
    NSArray *sortedAnnotations = [[annotations allObjects] sortedArrayUsingComparator:^(id obj1, id obj2) {
        MKMapPoint mapPoint1 = MKMapPointForCoordinate(((id<MKAnnotation>)obj1).coordinate);
        MKMapPoint mapPoint2 = MKMapPointForCoordinate(((id<MKAnnotation>)obj2).coordinate);

        CLLocationDistance distance1 = MKMetersBetweenMapPoints(mapPoint1, centerMapPoint);
        CLLocationDistance distance2 = MKMetersBetweenMapPoints(mapPoint2, centerMapPoint);

        if (distance1 < distance2) {
            return NSOrderedAscending;
        }
        else if (distance1 > distance2) {
            return NSOrderedDescending;
        }
        return NSOrderedSame;
    }];
    return [sortedAnnotations objectAtIndex:0];
}
Απαντήθηκε 29/11/2013 στις 14:55
πηγή χρήστη

ψήφοι
-1

Νομίζω ότι Foto Brisko (iTunes link) κάνει αυτό.
Δεν νομίζω ότι υπάρχει ένα πλαίσιο το κακάο Touch για αυτό.

Απαντήθηκε 12/01/2010 στις 10:06
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more