Permalink
Browse files

Merge branch 'release/v0.2'

Conflicts:
	jquery-jvectormap.js
  • Loading branch information...
bjornd committed May 6, 2012
2 parents dfe0c35 + 3438b23 commit 119df09c21cbcc57bdfbb3fff63c7277d5416606
View
@@ -1,3 +1,10 @@
+#
+# jVectorMap version 0.2
+#
+# Copyright 2011-2012, Kirill Lebedev
+# Licensed under the MIT license.
+#
+
import argparse
import sys
from osgeo import ogr
@@ -10,17 +17,18 @@
class Map:
width = 0
height = 0
-
+ bbox = []
+
def __init__(self, name, language):
self.paths = {}
self.name = name
self.language = language
-
+
def addPath(self, path, code, name):
self.paths[code] = {"path": path, "name": name}
-
+
def getJSCode(self):
- map = {"paths": self.paths, "width": self.width, "height": self.height}
+ map = {"paths": self.paths, "width": self.width, "height": self.height, "insets": self.insets, "projection": self.projection}
return "$.fn.vectorMap('addMap', '"+self.name+"_"+self.language+"',"+anyjson.serialize(map)+');'
@@ -36,27 +44,28 @@ def __init__(self, inputFile, **kwargs):
self.country_name_index = kwargs['country_name_index']
self.country_code_index = kwargs['country_code_index']
self.longtitude0 = kwargs['longtitude0']
+ self.inputFileEncoding = kwargs['input_file_encoding']
if kwargs['viewport']:
self.viewport = map(lambda s: float(s), kwargs['viewport'].split(' '))
else:
self.viewport = False
-
+
# spatial reference to convert to
self.spatialRef = osr.SpatialReference()
self.spatialRef.ImportFromProj4('+proj=mill +lat_0=0 +lon_0='+self.longtitude0+' +x_0=0 +y_0=0 +R_A +ellps=WGS84 +datum=WGS84 +units=m +no_defs')
-
+
# handle map insets
if kwargs['insets']:
self.insets = anyjson.deserialize(kwargs['insets'])
else:
self.insets = []
-
-
+
+
def loadData(self):
source = ogr.Open( self.inputFile )
layer = source.GetLayer(0)
layer.SetAttributeFilter( self.where )
-
+
if self.viewport:
layer.SetSpatialFilterRect( *self.viewport )
transformation = osr.CoordinateTransformation( layer.GetSpatialRef(), self.spatialRef )
@@ -65,9 +74,9 @@ def loadData(self):
self.viewportRect = shapely.geometry.box(point1[0], point1[1], point2[0], point2[1])
else:
self.viewportRect = False
-
+
layer.ResetReading()
-
+
# load codes from external tsv file if present or geodata file otherwise
self.codes = {}
if self.codes_file:
@@ -81,15 +90,15 @@ def loadData(self):
if code == '-99':
code = '_'+str(nextCode)
nextCode += 1
- name = feature.GetFieldAsString(self.country_name_index)
+ name = feature.GetFieldAsString(self.country_name_index).decode(self.inputFileEncoding)
self.codes[name] = code
layer.ResetReading()
-
+
# load features
for feature in layer:
geometry = feature.GetGeometryRef()
geometryType = geometry.GetGeometryType()
-
+
if geometryType == ogr.wkbPolygon or geometryType == ogr.wkbMultiPolygon:
geometry.TransformTo( self.spatialRef )
shapelyGeometry = shapely.wkb.loads( geometry.ExportToWkb() )
@@ -98,55 +107,80 @@ def loadData(self):
shapelyGeometry = shapelyGeometry.buffer(0)
shapelyGeometry = self.applyFilters(shapelyGeometry)
if shapelyGeometry:
- name = feature.GetFieldAsString(self.country_name_index)
+ name = feature.GetFieldAsString(self.country_name_index).decode(self.inputFileEncoding)
code = self.codes[name]
self.features[code] = {"geometry": shapelyGeometry, "name": name, "code": code}
else:
raise Exception, "Wrong geomtry type: "+geometryType
-
-
+
+
def convert(self, outputFile):
self.loadData()
-
+
codes = self.features.keys()
+ self.map.insets = []
envelope = []
for inset in self.insets:
- size = self.renderMapInset(inset['codes'], inset['left'], inset['top'], inset['width'])
- envelope.append( shapely.geometry.box(inset['left'], inset['top'], inset['left']+size[0], inset['top']+size[1]) )
+ insetBbox = self.renderMapInset(inset['codes'], inset['left'], inset['top'], inset['width'])
+ insetHeight = (insetBbox[3] - insetBbox[1]) * (inset['width'] / (insetBbox[2] - insetBbox[0]))
+ self.map.insets.append({
+ "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}],
+ "left": inset['left'],
+ "top": inset['top'],
+ "width": inset['width'],
+ "height": insetHeight
+ })
+ envelope.append(
+ shapely.geometry.box(
+ inset['left'], inset['top'], inset['left'] + inset['width'], inset['top'] + insetHeight
+ )
+ )
for code in inset['codes']:
codes.remove(code)
- size = self.renderMapInset(codes, 0, 0, self.width)
- envelope.append( shapely.geometry.box(0, 0, size[0], size[1]) )
- bbox = shapely.geometry.MultiPolygon( envelope ).bounds
-
- self.map.width = round(bbox[2]-bbox[0], 2)
- self.map.height = round(bbox[3]-bbox[1], 2)
-
+
+ insetBbox = self.renderMapInset(codes, 0, 0, self.width)
+ insetHeight = (insetBbox[3] - insetBbox[1]) * (self.width / (insetBbox[2] - insetBbox[0]))
+
+ envelope.append( shapely.geometry.box( 0, 0, self.width, insetHeight ) )
+ mapBbox = shapely.geometry.MultiPolygon( envelope ).bounds
+
+ self.map.width = mapBbox[2] - mapBbox[0]
+ self.map.height = mapBbox[3] - mapBbox[1]
+ self.map.insets.append({
+ "bbox": [{"x": insetBbox[0], "y": -insetBbox[3]}, {"x": insetBbox[2], "y": -insetBbox[1]}],
+ "left": 0,
+ "top": 0,
+ "width": self.width,
+ "height": insetHeight
+ })
+ self.map.projection = {"type": 'miller', "centralMeridian": self.longtitude0}
+
open(outputFile, 'w').write( self.map.getJSCode() )
-
-
+
+
def renderMapInset(self, codes, left, top, width):
envelope = []
for code in codes:
envelope.append( self.features[code]['geometry'].envelope )
-
+
bbox = shapely.geometry.MultiPolygon( envelope ).bounds
- bbox = ((bbox[0], bbox[1]), (bbox[2], bbox[3]))
-
- scale = (bbox[1][0]-bbox[0][0]) / width
-
+
+ scale = (bbox[2]-bbox[0]) / width
+
# generate SVG paths
for code in codes:
feature = self.features[code]
geometry = feature['geometry']
if args.buffer_distance:
geometry = geometry.buffer(args.buffer_distance)
+ if geometry.is_empty:
+ continue
if args.simplify_tolerance:
- geometry = geometry.simplify(args.simplify_tolerance, preserve_topology=True)
+ geometry = geometry.simplify(args.simplify_tolerance, preserve_topology=True)
if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon):
polygons = geometry.geoms
- else:
- polygons = [geometry]
+ else:
+ polygons = [geometry]
path = ''
for polygon in polygons:
rings = []
@@ -156,17 +190,16 @@ def renderMapInset(self, codes, left, top, width):
for pointIndex in range( len(ring.coords) ):
point = ring.coords[pointIndex]
if pointIndex == 0:
- path += 'M'+str( round( (point[0]-bbox[0][0]) / scale + left, 2) )
- path += ','+str( round( (bbox[1][1] - point[1]) / scale + top, 2) )
+ path += 'M'+str( round( (point[0]-bbox[0]) / scale + left, 2) )
+ path += ','+str( round( (bbox[3] - point[1]) / scale + top, 2) )
else:
path += 'l' + str( round(point[0]/scale - ring.coords[pointIndex-1][0]/scale, 2) )
path += ',' + str( round(ring.coords[pointIndex-1][1]/scale - point[1]/scale, 2) )
path += 'Z'
self.map.addPath(path, feature['code'], feature['name'])
-
- return ((bbox[1][0]-bbox[0][0])/scale, (bbox[1][1]-bbox[0][1])/scale)
-
-
+ return bbox
+
+
def applyFilters(self, geometry):
if self.viewportRect:
geometry = self.filterByViewport(geometry)
@@ -177,19 +210,19 @@ def applyFilters(self, geometry):
if not geometry:
return False
return geometry
-
-
+
+
def filterByViewport(self, geometry):
try:
return geometry.intersection(self.viewportRect)
except shapely.geos.TopologicalError:
return False
-
-
+
+
def filterByMinimalArea(self, geometry):
if isinstance(geometry, shapely.geometry.multipolygon.MultiPolygon):
polygons = geometry.geoms
- else:
+ else:
polygons = [geometry]
polygons = filter(lambda p: p.area > self.minimal_area, polygons)
return shapely.geometry.multipolygon.MultiPolygon(polygons)
@@ -212,18 +245,21 @@ def filterByMinimalArea(self, geometry):
parser.add_argument('--longtitude0', type=str, default='0')
parser.add_argument('--name', type=str, default='world')
parser.add_argument('--language', type=str, default='en')
+parser.add_argument('--input_file_encoding', type=str, default='iso-8859-1')
args = parser.parse_args()
-converter = Converter(args.input_file,
- where=args.where,
- codes_file=args.codes_file,
- insets=args.insets, width=args.width,
- viewport=args.viewport,
- minimal_area=args.minimal_area,
- country_name_index=args.country_name_index,
- country_code_index=args.country_code_index,
- longtitude0=args.longtitude0,
- name=args.name,
- language=args.language
+converter = Converter(args.input_file,
+ where = args.where,
+ codes_file = args.codes_file,
+ insets = args.insets,
+ width = args.width,
+ viewport = args.viewport,
+ minimal_area = args.minimal_area,
+ country_name_index = args.country_name_index,
+ country_code_index = args.country_code_index,
+ longtitude0 = args.longtitude0,
+ name = args.name,
+ language = args.language,
+ input_file_encoding = args.input_file_encoding
)
converter.convert(args.output_file)
Oops, something went wrong.

0 comments on commit 119df09

Please sign in to comment.