Project

lulu

0.0
No commit activity in last 3 years
No release in over 3 years
Lulu merges the closest overlapping pair of map markers into a one whose area is the sum of the original two, located at their centroid. It repeats this until no overlaps remain. Some interesting data structures make this quite fast for all but pathologically bad data. Markers can be circles or squares. The user may provide a scale factor allowing the marker radius to have a different scale than distance between markers.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.5
~> 10.1
~> 2.14
 Project Readme

Lulu

Lulu - A ruby gem for merging map markers by agglomerative clustering.

Installation

Add this line to your application's Gemfile:

gem 'lulu'

And then execute:

$ bundle

Or install it yourself as:

$ gem install lulu

Usage

require 'lulu'

# Make an empty marker list
list = Lulu::MarkerList.new

# Add some markers.  It's list.add(x, y, size). The size is actually area.
10000.times{ |n| list.add(Random.rand(1000), Random.rand(1000), Random.rand(100)) }

# Get the list length.
p list.length  # Produces 10000

# Optionally set merge parameters. Marker calculations can assume circular or
# square markers, and a scale factor may be set. The scale factor is applied
# to marker radii so that the marker size exists in a different coordinate
# space from the inter-marker distances.  This makes sense, for example, if
# the marker coordinates are pixels on a map. A pixel on the map represents
# distance, a pixel in a marker something else.  Returns self.
list.set_info(:circle, 1)

# Merge the markers.  Pairs that are merged are deleted and replaced by a
# fresh marker added to the list. If the original list has N, this can
# result in 2N-1 markers in the result.  Subsequent merges will remove
# all deleted markers from previous merges. This is called compression.
# See below.  Returns list.length.
list.merge

# Get the list length again.  If markers were merged, the list grew.
p list.length  # Produces 10415

# Squeeze out deleted markers, i.e. ones that have been merged to form
# new ones. All remaining nodes are marked :single (see method parts below)
# Returns list.length
list.compress

# Merge after compress is idempotent.
list.merge  # doesn't change list

# Get the marker at index 1000.  This is a list [x, y, size].
# If the index is out of range, nil is returned.
p list.marker(1000)  # Produces [748.0, 187.0, 80.0]

# Get whether the marker at index 100 was deleted during a merge.
p list.deleted(100) # returns true

# Print the list of all undeleted markers
p list.markers # Produces [[601.0, 715.0, 38.0]...[647.3314285714285, 179.19619047619048, 1050.0]]

# Clear the list, returning it to the empty state.  Returns self.
list.clear

# For a given marker index, get the two indices of the markers (its _parts_)
# that were merged to create it, if any.
list.parts(5324)
# For the marker with index 5324, returns
# [:root, i, j] if it is the undeleted result of a merge of markers i and j
# [:merge, i, j] if it is the subsequently deleted result of a merge of markers i and j
# [:single] if it is an undeleted original node
# [:leaf] if ti is a deleted original node
# nil if 5324 is out of range

The method parts is sufficient to walk the tree of all nodes formed by merging. In this manner, a parallel array of attribute information can be merged to match so that merged attributes are available for each :root.

Contributing

  1. Fork it ( http://github.com//lulu/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request