Skip to content

Commit

Permalink
Add initial files
Browse files Browse the repository at this point in the history
  • Loading branch information
jimmyasyraf committed Mar 24, 2022
1 parent 6d99c1e commit e1873df
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require 'rake/testtask'

Rake::TestTask.new do |t|
t.libs << 'test'
end

desc "Run tests"
task :default => :test
12 changes: 12 additions & 0 deletions brokjson.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Gem::Specification.new do |s|
s.name = 'brokjson'
s.version = '1.0.0'
s.summary = 'BrokJSON is a space-saving alternative to GeoJSON'
s.description = 'BrokJSON is a space-saving alternative to GeoJSON. Convert GeoJSON to BrokJSON and vice versa'
s.authors = ['Hazimi Asyraf']
s.email = '[email protected]'
s.files = ['lib/brokjson.rb']
s.test_files = ['test/test_brokjson.rb']
s.homepage = 'https://rubygems.org/gems/brokjson'
s.license = 'MIT'
end
173 changes: 173 additions & 0 deletions lib/brokjson.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
class BrokJson
def self.geo2brok(geojson)
global_geometries = []
global_properties = []
global_foreign_members = []

geojson['features'].each do |feature|
next if feature['type'].downcase != 'feature'

return unless feature.key?('geometry')

# Add properties
props = []
if feature.key?('properties')
feature['properties'].each do |property_key, property_value|
# Add to list if item in list
global_properties << property_key unless global_properties.include? property_key

index = global_properties.find_index(property_key)

# Check if props are long enough
props = props + [nil] * (index + 1 - props.length) if props.length - 1 < index

# Add to props
props[index] = property_value
end
end

# Add foreign members
foreign_members = []
feature.each do |item_key, item_val|
next if ['type', 'properties', 'geometry'].include? item_key.downcase

global_foreign_members << item_key unless global_foreign_members.include? item_key

index = global_foreign_members.find_index(item_key)

foreign_members = foreign_members + [nil] * (index + 1 - foreign_members.length) if foreign_members.length - 1 < index

foreign_members[index] = item_val
end

coords = nil
if feature['geometry']['type'].downcase == 'geometrycollection'
# GeometryCollection detected!
coords = []

feature["geometry"]["geometries"].each do |geom|
# Now check if last item of geometries is same type. If not, add the type
if (coords.length == 0 || coords[-1]['type'].downcase != geom['type'].downcase)
# Add new geometry list
coords << { 'type' => geom['type'], 'features' => [] }
end

# Add feature to geometry list
coords[coords.length - 1]['features'] << [geom['coordinates']]
end
else
# Add Coords
coords = feature['geometry']['coordinates']
end

# Create feature-array
brok_feature = [coords]

# Add props
brok_feature << props if props.length > 0

# Add foreign members
if foreign_members.length > 0
brok_feature << nil if brok_feature.length < 2
brok_feature << foreign_members
end

# Now check if last item of geometries is same type. If not, add the type
if (global_geometries.length == 0 || global_geometries[-1]['type'].downcase != feature['geometry']['type'].downcase)
# Add new geometry list
global_geometries << { 'type' => feature['geometry']['type'], 'features' => [] }
end

# Add feature to geometry list
global_geometries[global_geometries.length - 1]['features'] << brok_feature
end

# Build BrokJSON
brok = {}

# Add global properties
brok['properties'] = global_properties if global_properties.length > 0

# Add foreign members
brok['foreignMembers'] = global_foreign_members if global_foreign_members.length > 0

# Add all unknown members
geojson.each do |member_key, member_val|
# Exclude List
next if ['type', 'features'].include? member_key

brok[member_key] = member_val
end

# Add geometry
brok['geometries'] = global_geometries if global_geometries.length > 0

return brok
end

def self.brok2geo(brok)
geo = {
'type' => 'FeatureCollection'
}

# Look for custom properties on root
brok.each do |member_key, member_val|
geo[member_key] = member_val unless ['properties', 'geometries', 'foreignMembers'].include? member_key
end

geo['features'] = [] if brok['geometries'].length > 0

# Add geometries
brok['geometries'].each do |geometry_collection|
geometry_collection['features'].each do |feature|
# Create Feature
json_feature = { 'type' => 'Feature' }

# Check and add properties
properties = {}
if feature.length >= 2
(0..feature[1].length).each do |p|
prop = feature[1][p]

next if prop.nil?

properties[brok['properties'][p]] = prop
end
end

# Check and add foreign members
if feature.length >= 3
(0..feature[2].length).each do |m|
json_feature[brok['foreignMembers'][m]] = feature[2][m]
end
end

# Add props
json_feature['properties'] = properties if properties.length > 0

# Check if geometry collection
if geometry_collection['type'].downcase == 'geometryCollection'
new_coords = []
geometry_collection['features'].each do |coordinates|
coordinates[0].each do |geocol|
geocol['features'].each do |types|
coord = { 'type' => geocol['type'], 'coordinates' => types[0] }
new_coords << coord
end
end
end

# Add Geometry
json_feature['geometry'] = { 'type' => geometry_collection['type'], 'geometries' => new_coords }
else
# Normal Geometry
json_feature['geometry'] = { 'type' => geometry_collection['type'], 'coordinates' => feature[0] }
end

geo['features'] << json_feature
end
end

return geo
end
end
79 changes: 79 additions & 0 deletions test/test_brokjson.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
require 'test/unit'
require 'brokjson'

class BrokJsonTest < Test::Unit::TestCase
def test_can_convert_from_geojson_to_brokjson
assert_equal sample_brokjson, BrokJson.geo2brok(sample_geojson)
end

def test_can_convert_from_brokjson_to_geojson
assert_equal sample_geojson, BrokJson.brok2geo(sample_brokjson)
end

private

def sample_geojson
{
'type' => 'FeatureCollection',
'title' => 'Hello World',
'features' => [
{
'type' => 'Feature',
'properties' => {
'id' => 1,
'title' => 'Datapoint 1',
'value' => 343
},
'geometry' => {
'type' => 'Point',
'coordinates' => [
8.5402,
47.3782
]
}
},
{
'type' => 'Feature',
'properties' => {
'id' => 1,
'title' => 'Datapoint 2',
'value' => 14
},
'geometry' => {
'type' => 'Point',
'coordinates' => [
8.5637,
47.4504
]
}
}
]
}
end

def sample_brokjson
{
'properties' => [
'id',
'title',
'value'
],
'title' => 'Hello World',
'geometries' => [
{
'type' => 'Point',
'features'=> [
[
[8.5402, 47.3782],
[1, 'Datapoint 1', 343]
],
[
[8.5637, 47.4504],
[1, 'Datapoint 2', 14]
]
]
}
]
}
end
end

0 comments on commit e1873df

Please sign in to comment.