<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">
	<channel>
		<title>Blazingly Fast Open Source Algorithm for POI Clustering on iOS | Infinum</title>
		<atom:link href="https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/feed/" rel="self" type="application/rss+xml" />
		<link>https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/</link>
		<description>Building digital products</description>
		<lastBuildDate>Mon, 27 Apr 2026 14:58:27 +0000</lastBuildDate>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>

					<item>
				<image>
					<url>8071https://infinum.com/uploads/2014/09/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios-0.webp</url>
				</image>
				<title>A Blazingly Fast Open Source Algorithm for POI Clustering on iOS</title>
				<link>https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/</link>
				<pubDate>Tue, 16 Sep 2014 00:00:00 +0000</pubDate>
				<dc:creator>Filip Beć</dc:creator>
				<guid isPermaLink="false">https://infinum.com/the-capsized-eight/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/</guid>
				<description>
					<![CDATA[<p>With many POIs on the map, the view gets cluttered and the performance suffers. But you can transform the mess into an organized map.</p>
<p>The post <a href="https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/">A Blazingly Fast Open Source Algorithm for POI Clustering on iOS</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</description>
				<content:encoded>
					<![CDATA[<div
	class="wrapper"
	data-id="es-178"
	 data-animation-target='inner-items'>
		
			<div class="wrapper__inner">
			<div class="block-blog-content js-block-blog-content">
	
<div class="block-blog-content-sidebar" data-id="es-92">
	</div>

<div class="block-blog-content-main">
	
<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-95"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-93">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-94'
	>
	Most mobile apps nowadays include some kind of a map that’s dotted with markers – ATMs, gas stations or any other place relevant to the app’s purpose. The problem is, when you put many POIs on the map, the view gets cluttered and the performance suffers.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-98"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-96">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-97'
	>
	This problem can be solved by reducing the number of annotations. The simplest solution is to display a reduced number of objects when the map is zoomed out and add more of them as the user zooms in. The problem with this approach is that the user is not aware of all the available Places Of Interest. A better solution is something called <strong>POI clustering</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-101"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-99">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-100'
	>
	Clustering is a method of grouping multiple POIs which are close to each other into one location called a <strong>cluster</strong>. At lower zoom levels, the map should show clusters of locations represented by a special view. As the user zooms in on the map, clusters can be split into smaller clusters or even single object views, depending on the zoom level.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-104"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-102">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-103'
	>
	FBAnnotationClustering</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-107"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-media">
	<div	class="media block-media__media media__border--none media__align--center-center"
	data-id="es-105"
	 data-media-type='image'>

	<figure class="image block-media__image-figure image--size-stretch" data-id="es-106">
	<picture class="image__picture block-media__image-picture">
												<img
					src="https://infinum.com/uploads/2014/09/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios-2.webp"
					class="image__img block-media__image-img"
					alt=""
										height="373"
															width="700"
										loading="lazy"
					 />
					</picture>

	</figure></div></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-110"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-108">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-109'
	>
	This problem can be solved by using <a href="https://github.com/infinum/FBAnnotationClustering">FBAnnotationClustering</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-113"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-111">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-112'
	>
	You’re probably wondering what’s FBAnnotationClustering and what Facebook has to do with it. Well, FBAC is an open source clustering library/algorithm I wrote for use in our projects. And FB – those are my initials – my name is Filip Beć.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-116"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-114">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-115'
	>
	Now let’s take a look at the library.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-119"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-117">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-118'
	>
	Clustering by using QuadTree</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-122"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-120">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-121'
	>
	<video autoplay="autoplay" loop="loop" poster="https://s3.amazonaws.com/infinum.web.production/repository_items/files/000/000/392/original/bec_blog_still.jpg?1410765715" preload="auto"></video></p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-125"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-123">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-124'
	>
	Clustering can be carried out efficiently with algorithms for <a href="http://en.wikipedia.org/wiki/Space_partitioning">space-partitioning</a>. A <a href="http://en.wikipedia.org/wiki/Tree_data_structure">tree data structure</a> is usually used to store data for space-partitioning.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-128"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-126">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-127'
	>
	For storage, FBAnnotationClustering uses QuadTree. QuadTree is a data structure that can efficiently find all locations contained in a specific region. It’s built by recursively subdividing a two-dimensional space into smaller regions. Imagine that every node in the tree has a bucket of defined capacity. When that bucket is full of data, the node is subdivided into four new child nodes. Child nodes are smaller quadrants of a parent node.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-131"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-129">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-130'
	>
	You can find more details on how the QuadTree works on <a href="http://en.wikipedia.org/wiki/Quadtree">Wikipedia</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-134"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-132">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-133'
	>
	How to use it?</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-137"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-135">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-136'
	>
	The main advantage of FBAnnotation clustering is that it can be installed into an existing project via <a href="http://cocoapods.org/">CocoaPods</a>. The library has four classes:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-140"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="lists" data-id="es-138">
	<ul	class='typography typography--size-16-text-roman js-typography lists__typography'
	data-id='es-139'
	>
	<li>FBAnnotationCluster</li><li>FBClusteringManager</li><li>FBQuadTree</li><li>FBQuadTreeNode</li></ul></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-143"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-141">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-142'
	>
	You will never have to use FBQuadTree and FBQuadTreeNode. They are utilized only as internal structures. Almost all interaction with the library is achieved by using FBClusteringManager. It creates a data structure and it has some handy methods to deal with the map view. To use the library, you should first initialize an instance of FBClusteringManager. For example:</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-145"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-c github-light" data-language="c" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token">self.clusteringManager </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">[</span><span class="token">[</span><span class="token">FBClusteringManager alloc</span><span class="token">]</span><span class="token"> initWithAnnotations:arrayOfAnnotations</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-148"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-146">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-147'
	>
	Update the currently visible region of the map on every move with annotations obtained from <code>clusteringManager</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-150"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-c github-light" data-language="c" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">-</span><span class="token"> </span><span class="token">(</span><span class="token" style="color: #d73a49;">void</span><span class="token">)</span><span class="token">mapView:</span><span class="token">(</span><span class="token">MKMapView </span><span class="token" style="color: #d73a49;">*</span><span class="token">)</span><span class="token">mapView regionDidChangeAnimated:</span><span class="token">(</span><span class="token">BOOL</span><span class="token">)</span><span class="token">animated
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">[</span><span class="token">[</span><span class="token">NSOperationQueue new</span><span class="token">]</span><span class="token"> addOperationWithBlock:</span><span class="token" style="color: #d73a49;">^</span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #d73a49;">double</span><span class="token"> scale </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token" style="color: #24292e;">self</span><span class="token">.</span><span class="token" style="color: #24292e;">mapView</span><span class="token">.</span><span class="token" style="color: #24292e;">bounds</span><span class="token">.</span><span class="token" style="color: #24292e;">size</span><span class="token">.</span><span class="token" style="color: #24292e;">width</span><span class="token"> </span><span class="token" style="color: #d73a49;">/</span><span class="token"> </span><span class="token" style="color: #24292e;">self</span><span class="token">.</span><span class="token" style="color: #24292e;">mapView</span><span class="token">.</span><span class="token" style="color: #24292e;">visibleMapRect</span><span class="token">.</span><span class="token" style="color: #24292e;">size</span><span class="token">.</span><span class="token" style="color: #24292e;">width</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span><span class="line"><span class="token">        NSArray </span><span class="token" style="color: #d73a49;">*</span><span class="token">annotations </span><span class="token" style="color: #d73a49;">=</span><span class="token"> </span><span class="token">[</span><span class="token" style="color: #24292e;">self</span><span class="token">.</span><span class="token" style="color: #24292e;">clusteringManager</span><span class="token"> clusteredAnnotationsWithinMapRect:</span><span class="token" style="color: #24292e;">mapView</span><span class="token">.</span><span class="token" style="color: #24292e;">visibleMapRect</span><span class="token"> withZoomScale:scale</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">            </span><span class="token">[</span><span class="token" style="color: #24292e;">self</span><span class="token">.</span><span class="token" style="color: #24292e;">clusteringManager</span><span class="token"> displayAnnotations:annotations onMapView:mapView</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">]</span><span class="token">;</span><span class="token">
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-153"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-151">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-152'
	>
	Depending on the visible map region and the level of zoom, the method <code>clusteredAnnotationsWithinMapRect:withZoomScale:</code> will return an array of annotations of your own class and objects of FBAnnotationCluster class. Now it’s up to you to handle objects appropriately in the methods of <code>MKMapViewDelegate</code>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-155"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-code">
	<pre class="phiki language-c github-light" data-language="c" style="background-color: #fff;color: #24292e;"><code><span class="line"><span class="token" style="color: #d73a49;">-</span><span class="token"> </span><span class="token">(</span><span class="token">MKAnnotationView </span><span class="token" style="color: #d73a49;">*</span><span class="token">)</span><span class="token">mapView:</span><span class="token">(</span><span class="token">MKMapView </span><span class="token" style="color: #d73a49;">*</span><span class="token">)</span><span class="token">mapView viewForAnnotation:</span><span class="token">(</span><span class="token">id</span><span class="token" style="color: #d73a49;">&lt;</span><span class="token">MKAnnotation</span><span class="token" style="color: #d73a49;">&gt;</span><span class="token">)</span><span class="token">annotation
</span></span><span class="line"><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token" style="color: #d73a49;">if</span><span class="token"> </span><span class="token">(</span><span class="token">[</span><span class="token">annotation isKindOfClass:</span><span class="token">[</span><span class="token">FBAnnotationCluster class</span><span class="token">]</span><span class="token">]</span><span class="token">)</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle cluster</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token"> </span><span class="token" style="color: #d73a49;">else</span><span class="token"> </span><span class="token">{</span><span class="token">
</span></span><span class="line"><span class="token">        </span><span class="token" style="color: #6a737d;">//</span><span class="token" style="color: #6a737d;"> handle single annotation</span><span class="token">
</span></span><span class="line"><span class="token">    </span><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">    ...
</span></span><span class="line"><span class="token">}</span><span class="token">
</span></span><span class="line"><span class="token">
</span></span></code></pre></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-158"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-156">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-157'
	>
	And that’s all you have to do to transform your mess of POIs into a <strong>beautiful, organized and informative map</strong>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-161"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-heading" data-id="es-159">
	<h2	class='typography typography--size-36-text js-typography block-heading__heading'
	data-id='es-160'
	>
	Blazing fast performance</h2></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-164"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-162">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-163'
	>
	I said that QuadTree is blazingly fast and I wasn’t kidding.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-167"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-165">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-166'
	>
	Critical to performance is the moment of creating the QuadTree structure and inserting new locations. Let’s take a look at the hard numbers. This example covers the creation of a QuadTree structure using a random data set.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-170"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-168">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-169'
	>
	At Infinum, we’ve used this library in production grade applications developed for our clients. The apps are free and publicly available on iTunes Store – <a href="https://itunes.apple.com/us/app/truck-parking-europe/id740515031?mt=8">Truck Parking Europe</a>, <a href="https://itunes.apple.com/us/app/listkomat-ceske-sporitelny/id881468803?mt=8">Lístkomat České spořitelny</a>.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-173"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-171">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-172'
	>
	Last but not least, FBAnnotationClustering is an open source library. The source code, including an example project, is available on <a href="https://github.com/infinum/FBAnnotationClustering">Github</a>. It’s a continuation of some work done by <a href="https://github.com/thoughtbot/TBAnnotationClustering">Thoughtbot</a>, with improvements in some areas and architected to be used as a Cocoapods library.</p></div>	</div>

<div
	class="wrapper wrapper__use-simple--true"
	data-id="es-176"
	 data-animation='slideFade' data-animation-target='inner-items'>
		
			<div class="block-paragraph" data-id="es-174">
	<p	class='typography typography--size-16-text-roman js-typography block-paragraph__paragraph'
	data-id='es-175'
	>
	If you come across any problems with it, I’d appreciate it if you would create an <a href="https://github.com/infinum/FBAnnotationClustering/issues">issue</a>. Also, if you are interested in contributing to the project, you can open a pull request to add a bug fix or perhaps even a new functionality.</p></div>	</div>
</div>
</div>		</div>
	</div><p>The post <a href="https://infinum.com/blog/a-blazingly-fast-open-source-algorithm-for-poi-clustering-on-ios/">A Blazingly Fast Open Source Algorithm for POI Clustering on iOS</a> appeared first on <a href="https://infinum.com">Infinum</a>.</p>
]]>
				</content:encoded>
			</item>
		
	</channel>
</rss>