~shikharkohli/sahana-eden/gsoc1

« back to all changes in this revision

Viewing changes to controllers/gis.py

  • Committer: Shikhar Kohli
  • Date: 2010-08-11 18:40:09 UTC
  • mfrom: (802.1.156 eden)
  • Revision ID: shikharkohli@gmail.com-20100811184009-yy8zag5dowlam0ip
Merge trunk and update (a bit) of JS

Show diffs side-by-side

added added

removed removed

Lines of Context:
364
364
    table = db[tablename]
365
365
 
366
366
    # Model options
367
 
    table.level.comment = DIV( _class="tooltip", _title=T("Level|Is the location is a geographic area, then state at what level here."))
368
 
    table.code.comment = DIV( _class="tooltip", _title=T("Code|For a country this would be the ISO2 code, for a Town, it would be the Airport Locode."))
 
367
    table.level.comment = DIV( _class="tooltip", _title=Tstr("Level") + "|" + Tstr("Is the location is a geographic area, then state at what level here."))
 
368
    table.code.comment = DIV( _class="tooltip", _title=Tstr("Code") + "|" + Tstr("For a country this would be the ISO2 code, for a Town, it would be the Airport Locode."))
369
369
    table.parent.comment = DIV(A(ADD_LOCATION,
370
370
                                       _class="colorbox",
371
371
                                       _href=URL(r=request, c="gis", f="location", args="create", vars=dict(format="popup", child="parent")),
1407
1407
 
1408
1408
    return dict(map=map)
1409
1409
 
1410
 
# Experimental!
1411
 
def feature_create_map():
1412
 
    "Show a map to draw the feature"
1413
 
    title = T("Add GIS Feature")
1414
 
    form = crud.create("gis_location", onvalidation=lambda form: gis.wkt_centroid(form))
1415
 
 
1416
 
    _config = db.gis_config
1417
 
    _projection = db.gis_projection
1418
 
    query = (_config.id == 1) & (_projection.id == _config.projection_id)
1419
 
    projection = db(query).select(_projection.epsg, limitby=(0, 1)).first().epsg
1420
 
 
1421
 
    # Layers
1422
 
    baselayers = layers()
1423
 
 
1424
 
    return dict(title=title, form=form, projection=projection, openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing)
1425
 
 
1426
1410
def geolocate():
1427
1411
    " Call a Geocoder service "
1428
1412
    if "location" in request.vars:
1594
1578
    return dict(map=map)
1595
1579
 
1596
1580
def proxy():
1597
 
    """Based on http://trac.openlayers.org/browser/trunk/openlayers/examples/proxy.cgi
1598
 
This is a blind proxy that we use to get around browser
1599
 
restrictions that prevent the Javascript from loading pages not on the
1600
 
same server as the Javascript. This has several problems: it's less
1601
 
efficient, it might break some sites, and it's a security risk because
1602
 
people can use this proxy to browse the web and possibly do bad stuff
1603
 
with it. It only loads pages via http and https, but it can load any
1604
 
content type. It supports GET and POST requests."""
 
1581
    """
 
1582
    Based on http://trac.openlayers.org/browser/trunk/openlayers/examples/proxy.cgi
 
1583
    This is a blind proxy that we use to get around browser
 
1584
    restrictions that prevent the Javascript from loading pages not on the
 
1585
    same server as the Javascript. This has several problems: it's less
 
1586
    efficient, it might break some sites, and it's a security risk because
 
1587
    people can use this proxy to browse the web and possibly do bad stuff
 
1588
    with it. It only loads pages via http and https, but it can load any
 
1589
    content type. It supports GET and POST requests.
 
1590
    """
1605
1591
 
1606
1592
    import urllib2
1607
1593
    import cgi
1682
1668
        msg += "Content-Type: text/plain\n\n"
1683
1669
        msg += "Some unexpected error occurred. Error text was: %s" % str(E)
1684
1670
        return msg
1685
 
 
1686
 
 
1687
 
 
1688
 
######################
1689
 
# Deprecated Functions
1690
 
######################
1691
 
 
1692
 
def layers():
1693
 
    """
1694
 
    Deprecated!
1695
 
    Provide the Enabled Layers
1696
 
    """
1697
 
 
1698
 
    from gluon.tools import fetch
1699
 
 
1700
 
    response.warning = ""
1701
 
 
1702
 
    layers = Storage()
1703
 
 
1704
 
    # OpenStreetMap
1705
 
    layers.openstreetmap = Storage()
1706
 
    layers_openstreetmap = db(db.gis_layer_openstreetmap.enabled == True).select()
1707
 
    for layer in layers_openstreetmap:
1708
 
        for subtype in gis_layer_openstreetmap_subtypes:
1709
 
            if layer.subtype == subtype:
1710
 
                layers.openstreetmap["%s" % subtype] = layer.name
1711
 
 
1712
 
    # Google
1713
 
    layers.google = Storage()
1714
 
    # Check for Google Key
1715
 
    try:
1716
 
        layers.google.key = db(db.gis_apikey.name == "google").select(db.gis_apikey.apikey).first().apikey
1717
 
        layers_google = db(db.gis_layer_google.enabled == True).select()
1718
 
        for layer in layers_google:
1719
 
            for subtype in gis_layer_google_subtypes:
1720
 
                if layer.subtype == subtype:
1721
 
                    layers.google["%s" % subtype] = layer.name
1722
 
                    layers.google.enabled = 1
1723
 
    except:
1724
 
        # Redirect to Key entry screen
1725
 
        session.warning = T("Please enter a Google Key if you wish to use Google Layers")
1726
 
        redirect(URL(r=request, f=apikey))
1727
 
 
1728
 
    # Yahoo
1729
 
    layers.yahoo = Storage()
1730
 
    # Check for Yahoo Key
1731
 
    try:
1732
 
        layers.yahoo.key = db(db.gis_apikey.name == "yahoo").select(db.gis_apikey.apikey).first().apikey
1733
 
        layers_yahoo = db(db.gis_layer_yahoo.enabled == True).select()
1734
 
        for layer in layers_yahoo:
1735
 
            for subtype in gis_layer_yahoo_subtypes:
1736
 
                if layer.subtype == subtype:
1737
 
                    layers.yahoo["%s" % subtype] = layer.name
1738
 
                    layers.yahoo.enabled = 1
1739
 
    except:
1740
 
        # Redirect to Key entry screen
1741
 
        session.warning = T("Please enter a Yahoo Key if you wish to use Yahoo Layers")
1742
 
        redirect(URL(r=request, f=apikey))
1743
 
 
1744
 
    # Bing (Virtual Earth)
1745
 
    # Broken in GeoExt: http://www.geoext.org/pipermail/users/2009-December/000393.html
1746
 
    #layers.bing = Storage()
1747
 
    #layers_bing = db(db.gis_layer_bing.enabled == True).select()
1748
 
    #for layer in layers_bing:
1749
 
    #    for subtype in gis_layer_bing_subtypes:
1750
 
    #        if layer.subtype == subtype:
1751
 
    #            layers.bing["%s" % subtype] = layer.name
1752
 
 
1753
 
    # GPX
1754
 
    layers.gpx = Storage()
1755
 
    layers_gpx = db(db.gis_layer_gpx.enabled == True).select()
1756
 
    for layer in layers_gpx:
1757
 
        name = layer.name
1758
 
        layers.gpx[name] = Storage()
1759
 
        track = db(db.gis_track.id == layer.track_id).select(limitby=(0, 1)).first()
1760
 
        layers.gpx[name].url = track.track
1761
 
        if layer.marker_id:
1762
 
            layers.gpx[name].marker = db(db.gis_marker.id == layer.marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1763
 
        else:
1764
 
            marker_id = db(db.gis_config.id == 1).select(db.gis_config.marker_id, limitby=(0, 1)).first().marker_id
1765
 
            layers.gpx[name].marker = db(db.gis_marker.id == marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1766
 
 
1767
 
    cachepath = os.path.join(request.folder, "uploads", "gis_cache")
1768
 
    if os.access(cachepath, os.W_OK):
1769
 
        cache = True
1770
 
    else:
1771
 
        cache = False
1772
 
 
1773
 
    # GeoRSS
1774
 
    layers.georss = Storage()
1775
 
    layers_georss = db(db.gis_layer_georss.enabled == True).select()
1776
 
    if layers_georss and not cache:
1777
 
        response.warning += cachepath + " " + str(T("not writable - unable to cache GeoRSS layers!")) + "\n"
1778
 
    for layer in layers_georss:
1779
 
        name = layer.name
1780
 
        url = layer.url
1781
 
        if cache:
1782
 
            filename = "gis_cache.file." + name.replace(" ", "_") + ".rss"
1783
 
            filepath = os.path.join(cachepath, filename)
1784
 
            try:
1785
 
                # Download file to cache
1786
 
                file = fetch(url)
1787
 
                f = open(filepath, "w")
1788
 
                f.write(file)
1789
 
                f.close()
1790
 
                records = db(db.gis_cache.name == name).select()
1791
 
                if records:
1792
 
                    records[0].update(modified_on=response.utcnow)
1793
 
                else:
1794
 
                    db.gis_cache.insert(name=name, file=filename)
1795
 
                url = URL(r=request, c="default", f="download", args=[filename])
1796
 
            except:
1797
 
                # URL inaccessible
1798
 
                if os.access(filepath, os.R_OK):
1799
 
                    # Use cached version
1800
 
                    date = db(db.gis_cache.name == name).select(db.gis_cache.modified_on, limitby=(0, 1)).first().modified_on
1801
 
                    response.warning += url + " " + str(T("not accessible - using cached version from")) + " " + str(date) + "\n"
1802
 
                    url = URL(r=request, c="default", f="download", args=[filename])
1803
 
                else:
1804
 
                    # No cached version available
1805
 
                    response.warning += url + " " + str(T("not accessible - no cached version available!")) + "\n"
1806
 
                    # skip layer
1807
 
                    continue
1808
 
        else:
1809
 
            # No caching possible (e.g. GAE), display file direct from remote (using Proxy)
1810
 
            pass
1811
 
 
1812
 
        # Add to return
1813
 
        layers.georss[name] = Storage()
1814
 
        layers.georss[name].url = url
1815
 
        layers.georss[name].projection = db(db.gis_projection.id == layer.projection_id).select(db.gis_projection.epsg, limitby=(0, 1)).first().epsg
1816
 
        if layer.marker_id:
1817
 
            layers.georss[name].marker = db(db.gis_marker.id == layer.marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1818
 
        else:
1819
 
            marker_id = db(db.gis_config.id == 1).select(db.gis_config.marker_id, limitby=(0, 1)).first().marker_id
1820
 
            layers.georss[name].marker = db(db.gis_marker.id == marker_id).select(db.gis_marker.image, limitby=(0, 1)).first().image
1821
 
 
1822
 
    # KML
1823
 
    layers.kml = Storage()
1824
 
    layers_kml = db(db.gis_layer_kml.enabled == True).select()
1825
 
    if layers_kml and not cache:
1826
 
        response.warning += cachepath + " " + str(T("not writable - unable to cache KML layers!")) + "\n"
1827
 
 
1828
 
    # Append dynamic feed:
1829
 
    # /gis/map_viewing_client?kml_feed=<url>&kml_name=<feed_name>
1830
 
    layers_kml = [Storage(name=l.name, url=l.url) for l in layers_kml]
1831
 
    if "kml_feed" in request.vars and "kml_name" in request.vars:
1832
 
        layers_kml.append(Storage(name=request.vars["kml_name"], url=request.vars["kml_feed"]))
1833
 
 
1834
 
    for layer in layers_kml:
1835
 
        name = layer.name
1836
 
        url = layer.url
1837
 
        if cache:
1838
 
            filename = "gis_cache.file." + name.replace(" ", "_") + ".kml"
1839
 
            filepath = os.path.join(cachepath, filename)
1840
 
            # Download file
1841
 
            file, warning = gis.download_kml(url, deployment_settings.get_base_public_url())
1842
 
            # Handle errors
1843
 
            if "URLError" in warning or "HTTPError" in warning:
1844
 
                # URL inaccessible
1845
 
                if os.access(filepath, os.R_OK):
1846
 
                    # Use cached version
1847
 
                    date = db(db.gis_cache.name == name).select(db.gis_cache.modified_on, limitby=(0, 1)).first().modified_on
1848
 
                    response.warning += url + " " + str(T("not accessible - using cached version from")) + " " + str(date) + "\n"
1849
 
                    url = URL(r=request, c="default", f="download", args=[filename])
1850
 
                else:
1851
 
                    # No cached version available
1852
 
                    response.warning += url + " " + str(T("not accessible - no cached version available!")) + "\n"
1853
 
                    # skip layer
1854
 
                    continue
1855
 
            else:
1856
 
                # Download was succesful
1857
 
                if "ParseError" in warning:
1858
 
                    # @ToDo Parse detail
1859
 
                    response.warning += str(T("Layer")) + ": " + name + " " + str(T("couldn't be parsed so NetworkLinks not followed.")) + "\n"
1860
 
                if "GroundOverlay" in warning or "ScreenOverlay" in warning:
1861
 
                    response.warning += str(T("Layer")) + ": " + name + " " + str(T("includes a GroundOverlay or ScreenOverlay which aren't supported in OpenLayers yet, so it may not work properly.")) + "\n"
1862
 
                # Write file to cache
1863
 
                f = open(filepath, "w")
1864
 
                f.write(file)
1865
 
                f.close()
1866
 
                records = db(db.gis_cache.name == name).select()
1867
 
                if records:
1868
 
                    records[0].update(modified_on=response.utcnow)
1869
 
                else:
1870
 
                    db.gis_cache.insert(name=name, file=filename)
1871
 
                url = URL(r=request, c="default", f="download", args=[filename])
1872
 
        else:
1873
 
            # No caching possible (e.g. GAE), display file direct from remote (using Proxy)
1874
 
            pass
1875
 
 
1876
 
        # Add to return
1877
 
        layers.kml[name] = Storage()
1878
 
        layers.kml[name].url = url
1879
 
 
1880
 
    # WMS
1881
 
    layers.wms = Storage()
1882
 
    layers_wms = db(db.gis_layer_wms.enabled == True).select()
1883
 
    for layer in layers_wms:
1884
 
        name = layer.name
1885
 
        layers.wms[name] = Storage()
1886
 
        layers.wms[name].url = layer.url
1887
 
        layers.wms[name].base = layer.base
1888
 
        if layer.map:
1889
 
            layers.wms[name].map = layer.map
1890
 
        layers.wms[name].layers = layer.layers
1891
 
        layers.wms[name].projection = db(db.gis_projection.id == layer.projection_id).select(db.gis_projection.epsg, limitby=(0, 1)).first().epsg
1892
 
        layers.wms[name].transparent = layer.transparent
1893
 
        if layer.format:
1894
 
            layers.wms[name].format = layer.format
1895
 
 
1896
 
    # TMS
1897
 
    layers.tms = Storage()
1898
 
    layers_tms = db(db.gis_layer_tms.enabled == True).select()
1899
 
    for layer in layers_tms:
1900
 
        name = layer.name
1901
 
        layers.tms[name] = Storage()
1902
 
        layers.tms[name].url = layer.url
1903
 
        layers.tms[name].layers = layer.layers
1904
 
        if layer.format:
1905
 
            layers.tms[name].format = layer.format
1906
 
 
1907
 
    # MGRS - only a single one of these should be defined & it actually appears as a Control not a Layer
1908
 
    mgrs = db(db.gis_layer_mgrs.enabled == True).select(limitby=(0, 1)).first()
1909
 
    if mgrs:
1910
 
        layers.mgrs = Storage()
1911
 
        layers.mgrs.name = mgrs.name
1912
 
        layers.mgrs.url = mgrs.url
1913
 
 
1914
 
    # XYZ
1915
 
    layers.xyz = Storage()
1916
 
    layers_xyz = db(db.gis_layer_xyz.enabled == True).select()
1917
 
    for layer in layers_xyz:
1918
 
        name = layer.name
1919
 
        layers.xyz[name] = Storage()
1920
 
        layers.xyz[name].url = layer.url
1921
 
        layers.xyz[name].base = layer.base
1922
 
        layers.xyz[name].sphericalMercator = layer.sphericalMercator
1923
 
        layers.xyz[name].transitionEffect = layer.transitionEffect
1924
 
        layers.xyz[name].numZoomLevels = layer.numZoomLevels
1925
 
        layers.xyz[name].transparent = layer.transparent
1926
 
        layers.xyz[name].visible = layer.visible
1927
 
        layers.xyz[name].opacity = layer.opacity
1928
 
 
1929
 
    # JS
1930
 
    layers.js = Storage()
1931
 
    layers_js = db(db.gis_layer_js.enabled == True).select()
1932
 
    for layer in layers_js:
1933
 
        name = layer.name
1934
 
        layers.js[name] = Storage()
1935
 
        layers.js[name].code = layer.code
1936
 
 
1937
 
    return layers
1938
 
 
1939
 
def display_feature_old():
1940
 
    """
1941
 
    Deprecated!
1942
 
    Cut-down version of the Map Viewing Client.
1943
 
    Used as a .represent for location_id to show just this feature on the map.
1944
 
    """
1945
 
 
1946
 
    # The Feature
1947
 
    feature_id = request.args(0)
1948
 
    feature = db(db.gis_location.id == feature_id).select(limitby=(0, 1)).first()
1949
 
 
1950
 
    # Check user is authorised to access record
1951
 
    if not shn_has_permission("read", db.gis_location, feature.id):
1952
 
        session.error = str(T("No access to this record!"))
1953
 
        raise HTTP(401, body=s3xrc.xml.json_message(False, 401, session.error))
1954
 
 
1955
 
    # Config
1956
 
    config = gis.get_config()
1957
 
    width = config.map_width
1958
 
    height = config.map_height
1959
 
    numZoomLevels = config.zoom_levels
1960
 
    projection = config.epsg
1961
 
    # Support bookmarks (such as from the control)
1962
 
    if "lat" in request.vars:
1963
 
        lat = request.vars.lat
1964
 
    else:
1965
 
        lat = feature.lat
1966
 
    if "lon" in request.vars:
1967
 
        lon = request.vars.lon
1968
 
    else:
1969
 
        lon = feature.lon
1970
 
    if "zoom" in request.vars:
1971
 
        zoom = request.vars.zoom
1972
 
    else:
1973
 
        zoom = config.zoom
1974
 
    units = config.units
1975
 
    maxResolution = config.maxResolution
1976
 
    maxExtent = config.maxExtent
1977
 
    marker_default = config.marker_id
1978
 
    cluster_distance = config.cluster_distance
1979
 
    cluster_threshold = config.cluster_threshold
1980
 
    layout = config.opt_gis_layout
1981
 
 
1982
 
    # Add the config to the Return
1983
 
    output = dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout)
1984
 
 
1985
 
    # Feature details
1986
 
    try:
1987
 
        feature_class = db(db.gis_feature_class.id == feature.feature_class_id).select(limitby=(0, 1)).first()
1988
 
        feature.module = feature_class.module
1989
 
        feature.resource = feature_class.resource
1990
 
    except:
1991
 
        feature_class = None
1992
 
        feature.module = None
1993
 
        feature.resource = None
1994
 
    if feature.module and feature.resource:
1995
 
        _resource = db["%s_%s" % (feature.module, feature.resource)]
1996
 
        feature.resource_id = db(_resource.location_id == feature.id).select(_resource.id, limitby=(0, 1)).first().id
1997
 
    else:
1998
 
        feature.resource_id = None
1999
 
    # provide an extra access so no need to duplicate popups code
2000
 
    feature.gis_location = Storage()
2001
 
    feature.gis_location = feature
2002
 
    feature.gis_feature_class = feature_class
2003
 
 
2004
 
    # Look up the marker to display
2005
 
    feature.marker = gis.get_marker(feature_id)
2006
 
 
2007
 
    try:
2008
 
        # Metadata is M->1 to Features
2009
 
        # We use the most recent one
2010
 
        query = (db.doc_metadata.location_id == feature.id) & (db.doc_metadata.deleted == False)
2011
 
        metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2012
 
 
2013
 
        # Person .represent is too complex to put into JOIN
2014
 
        contact = shn_pr_person_represent(metadata.person_id)
2015
 
 
2016
 
    except:
2017
 
        metadata = None
2018
 
        contact = None
2019
 
    feature.metadata = metadata
2020
 
    feature.contact = contact
2021
 
 
2022
 
    try:
2023
 
        # Images are M->1 to Features
2024
 
        # We use the most recently uploaded one
2025
 
        query = (db.doc_image.location_id == feature.id) & (db.doc_image.deleted == False)
2026
 
        image = db(query).select(db.doc_image.image, orderby=~db.doc_image.created_on).first().image
2027
 
    except:
2028
 
        image = None
2029
 
    feature.image = image
2030
 
 
2031
 
    # Add the feature to the Return
2032
 
    output.update(dict(feature=feature))
2033
 
 
2034
 
    # Layers
2035
 
    baselayers = layers()
2036
 
    # Add the Base Layers to the Return
2037
 
    output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2038
 
    # Don't want confusing overlays
2039
 
    output.update(dict(georss_layers=[], gpx_layers=[], kml_layers=[], js_layers=[], mgrs=[]))
2040
 
 
2041
 
    return output
2042
 
 
2043
 
def display_features_old():
2044
 
    """
2045
 
    Deprecated!
2046
 
    Cut-down version of the Map Viewing Client.
2047
 
    Used as a link from the RHeader.
2048
 
        URL generated server-side
2049
 
    Shows all locations matching a query.
2050
 
    Most recent location is marked using a bigger Marker.
2051
 
    """
2052
 
 
2053
 
    # Parse the URL, check for implicit resources, extract the primary record
2054
 
    # http://127.0.0.1:8000/sahana/gis/display_features&module=pr&resource=person&instance=1&jresource=presence
2055
 
    ok = 0
2056
 
    if "module" in request.vars:
2057
 
        res_module = request.vars.module
2058
 
        ok +=1
2059
 
    if "resource" in request.vars:
2060
 
        resource = request.vars.resource
2061
 
        ok +=1
2062
 
    if "instance" in request.vars:
2063
 
        instance = int(request.vars.instance)
2064
 
        ok +=1
2065
 
    if "jresource" in request.vars:
2066
 
        jresource = request.vars.jresource
2067
 
        ok +=1
2068
 
    if ok != 4:
2069
 
        session.error = str(T("Insufficient vars: Need module, resource, jresource, instance"))
2070
 
        raise HTTP(400, body=s3xrc.xml.json_message(False, 400, session.error))
2071
 
 
2072
 
    component, pkey, fkey = s3xrc.model.get_component(res_module, resource, jresource)
2073
 
    table = db["%s_%s" % (res_module, resource)]
2074
 
    jtable = db[str(component.table)]
2075
 
    query = (jtable[fkey] == table[pkey]) & (table.id == instance)
2076
 
    # Filter out deleted
2077
 
    deleted = (table.deleted == False)
2078
 
    query = query & deleted
2079
 
    # Filter out inaccessible
2080
 
    query2 = db.gis_location.id == jtable.location_id
2081
 
    accessible = shn_accessible_query("read", db.gis_location)
2082
 
    query2 = query2 & accessible
2083
 
 
2084
 
    features = db(query).select(db.gis_location.ALL, left = [db.gis_location.on(query2)])
2085
 
 
2086
 
    # Implicit case for instance requires:
2087
 
    #request = the_web2py_way_to_build_a_request_from_url(button-data)
2088
 
    #jr = s3xrc.request(request)
2089
 
    #xml_tree = jr.export_xml()
2090
 
    #retrieve the location_id's from xml_tree using XPath
2091
 
 
2092
 
    # Calculate an appropriate BBox
2093
 
    bounds = gis.get_bounds(features=features)
2094
 
    lon_max = bounds["max_lon"]
2095
 
    lon_min = bounds["min_lon"]
2096
 
    lat_max = bounds["max_lat"]
2097
 
    lat_min = bounds["min_lat"]
2098
 
 
2099
 
    #bbox = str(lon_min) + "," + str(lat_min) + "," + str(lon_max) + "," + str(lat_max)
2100
 
    #We now project these client-side, so pass raw info (client-side projection means less server-side dependencies)
2101
 
    output = dict(lon_max=lon_max, lon_min=lon_min, lat_max=lat_max, lat_min=lat_min)
2102
 
 
2103
 
    # Config
2104
 
    config = gis.get_config()
2105
 
    width = config.map_width
2106
 
    height = config.map_height
2107
 
    numZoomLevels = config.zoom_levels
2108
 
    projection = config.epsg
2109
 
    # Support bookmarks (such as from the control)
2110
 
    if "lat" in request.vars:
2111
 
        lat = request.vars.lat
2112
 
    else:
2113
 
        lat = None
2114
 
    if "lon" in request.vars:
2115
 
        lon = request.vars.lon
2116
 
    else:
2117
 
        lon = None
2118
 
    if "zoom" in request.vars:
2119
 
        zoom = request.vars.zoom
2120
 
    else:
2121
 
        zoom = None
2122
 
    units = config.units
2123
 
    maxResolution = config.maxResolution
2124
 
    maxExtent = config.maxExtent
2125
 
    marker_default = config.marker_id
2126
 
    cluster_distance = config.cluster_distance
2127
 
    cluster_threshold = config.cluster_threshold
2128
 
    layout = config.opt_gis_layout
2129
 
 
2130
 
    # Add the config to the Return
2131
 
    output.update(dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout))
2132
 
 
2133
 
    # Feature details
2134
 
    for feature in features:
2135
 
        try:
2136
 
            feature_class = db(db.gis_feature_class.id == feature.feature_class_id).select(limitby=(0, 1)).first()
2137
 
        except:
2138
 
            feature_class = None
2139
 
        feature.module = feature_class.module
2140
 
        feature.resource = feature_class.resource
2141
 
        if feature.module and feature.resource:
2142
 
            try:
2143
 
                _resource = db["%s_%s" % (feature.module, feature.resource)]
2144
 
                feature.resource_id = db(_resource.location_id == feature.id).select(_resource.id, limitby=(0, 1)).first().id
2145
 
            except:
2146
 
                feature.resource_id = None
2147
 
        else:
2148
 
            feature.resource_id = None
2149
 
        # provide an extra access so no need to duplicate popups code
2150
 
        feature.gis_location = Storage()
2151
 
        feature.gis_location = feature
2152
 
        feature.gis_feature_class = feature_class
2153
 
 
2154
 
        # Look up the marker to display
2155
 
        feature.marker = gis.get_marker(feature.id)
2156
 
 
2157
 
        try:
2158
 
            # Metadata is M->1 to Features
2159
 
            # We use the most recent one
2160
 
            query = (db.doc_metadata.location_id == feature.id) & (db.doc_metadata.deleted == False)
2161
 
            metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2162
 
 
2163
 
            # Person .represent is too complex to put into JOIN
2164
 
            contact = shn_pr_person_represent(metadata.person_id)
2165
 
 
2166
 
        except:
2167
 
            metadata = None
2168
 
            contact = None
2169
 
        feature.metadata = metadata
2170
 
        feature.contact = contact
2171
 
 
2172
 
        try:
2173
 
            # Images are M->1 to Features
2174
 
            # We use the most recently uploaded one
2175
 
            query = (db.doc_image.location_id == feature.id) & (db.doc_image.deleted == False)
2176
 
            image = db(query).select(orderby=~db.doc_image.created_on, limitby=(0, 1)).first().image
2177
 
        except:
2178
 
            image = None
2179
 
        feature.image = image
2180
 
 
2181
 
    # Add the features to the Return
2182
 
    output.update(dict(features=features))
2183
 
 
2184
 
    # Layers
2185
 
    baselayers = layers()
2186
 
    # Add the Base Layers to the Return
2187
 
    output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2188
 
    # Don't want confusing overlays
2189
 
    output.update(dict(georss_layers=[], gpx_layers=[], kml_layers=[], js_layers=[], mgrs=[]))
2190
 
 
2191
 
    return output
2192
 
 
2193
 
def map_viewing_client_old():
2194
 
    """
2195
 
    Map Viewing Client.
2196
 
    Main user UI for viewing the Maps with associated Features
2197
 
    """
2198
 
 
2199
 
    title = T("Map Viewing Client")
2200
 
    response.title = title
2201
 
 
2202
 
    # Start building the Return with the Framework
2203
 
    output = dict(title=title, )
2204
 
 
2205
 
    # Config
2206
 
    # ToDo return all of these to the view via a single 'config' var
2207
 
    config = gis.get_config()
2208
 
    width = config.map_width
2209
 
    height = config.map_height
2210
 
    numZoomLevels = config.zoom_levels
2211
 
    projection = config.epsg
2212
 
    # Support bookmarks (such as from the control)
2213
 
    if "lat" in request.vars:
2214
 
        lat = request.vars.lat
2215
 
    else:
2216
 
        lat = config.lat
2217
 
    if "lon" in request.vars:
2218
 
        lon = request.vars.lon
2219
 
    else:
2220
 
        lon = config.lon
2221
 
    if "zoom" in request.vars:
2222
 
        zoom = request.vars.zoom
2223
 
    else:
2224
 
        zoom = config.zoom
2225
 
    units = config.units
2226
 
    maxResolution = config.maxResolution
2227
 
    maxExtent = config.maxExtent
2228
 
    marker_default = config.marker_id
2229
 
    cluster_distance = config.cluster_distance
2230
 
    cluster_threshold = config.cluster_threshold
2231
 
    layout = config.opt_gis_layout
2232
 
 
2233
 
    # Add the Config to the Return
2234
 
    output.update(dict(width=width, height=height, numZoomLevels=numZoomLevels, projection=projection, lat=lat, lon=lon, zoom=zoom, units=units, maxResolution=maxResolution, maxExtent=maxExtent, cluster_distance=cluster_distance, cluster_threshold=cluster_threshold, layout=layout))
2235
 
 
2236
 
    # Layers
2237
 
    baselayers = layers()
2238
 
    # Add the Layers to the Return
2239
 
    output.update(dict(openstreetmap=baselayers.openstreetmap, google=baselayers.google, yahoo=baselayers.yahoo, bing=baselayers.bing, tms_layers=baselayers.tms, wms_layers=baselayers.wms, xyz_layers=baselayers.xyz))
2240
 
    output.update(dict(georss_layers=baselayers.georss, gpx_layers=baselayers.gpx, js_layers=baselayers.js, kml_layers=baselayers.kml))
2241
 
    # MGRS isn't a Layer, it's a Control, but added here anyway
2242
 
    output.update(dict(mgrs=baselayers.mgrs))
2243
 
 
2244
 
    # Internal Features
2245
 
    features = Storage()
2246
 
    # Features are displayed in a layer per FeatureGroup
2247
 
    feature_groups = db(db.gis_feature_group.enabled == True).select()
2248
 
    for feature_group in feature_groups:
2249
 
        groups = db.gis_feature_group
2250
 
        locations = db.gis_location
2251
 
        classes = db.gis_feature_class
2252
 
        metadata = db.doc_metadata
2253
 
        # Which Features are added to the Group directly?
2254
 
        # ^^ No longer supported, for simplicity
2255
 
        #link = db.gis_location_to_feature_group
2256
 
        # JOINs are efficient for RDBMS but not compatible with GAE
2257
 
        #features1 = db(link.feature_group_id == feature_group.id).select(groups.ALL, locations.ALL, classes.ALL, left=[groups.on(groups.id == link.feature_group_id), locations.on(locations.id == link.location_id), classes.on(classes.id == locations.feature_class_id)])
2258
 
        # FIXME?: Extend JOIN for Metadata (sortby, want 1 only), Markers (complex logic), Resource_id (need to find from the results of prev query)
2259
 
        # Which Features are added to the Group via their FeatureClass?
2260
 
        link = db.gis_feature_class_to_feature_group
2261
 
        features2 = db(link.feature_group_id == feature_group.id).select(groups.ALL, locations.ALL, classes.ALL, left=[groups.on(groups.id == link.feature_group_id), classes.on(classes.id == link.feature_class_id), locations.on(locations.feature_class_id == link.feature_class_id)])
2262
 
        # FIXME?: Extend JOIN for Metadata (sortby, want 1 only), Markers (complex logic), Resource_id (need to find from the results of prev query)
2263
 
        #features[feature_group.id] = features1 | features2
2264
 
        features[feature_group.id] = features2
2265
 
        for feature in features[feature_group.id]:
2266
 
            try:
2267
 
                # Deprecated since we'll be using KML to populate Popups with Edit URLs, etc
2268
 
                feature.module = feature.gis_feature_class.module
2269
 
                feature.resource = feature.gis_feature_class.resource
2270
 
                if feature.module and feature.resource:
2271
 
                    try:
2272
 
                        _resource = db["%s_%s" % (feature.module, feature.resource)]
2273
 
                        feature.resource_id = db(_resource.location_id == feature.gis_location.id).select(_resource.id, limitby=(0, 1)).first().id
2274
 
                    except:
2275
 
                        feature.resource_id = None
2276
 
                else:
2277
 
                    feature.resource_id = None
2278
 
 
2279
 
                # Look up the marker to display
2280
 
                feature.marker = gis.get_marker(feature.gis_location.id)
2281
 
 
2282
 
                try:
2283
 
                    # Metadata is M->1 to Features
2284
 
                    # We use the most recent one
2285
 
                    query = (db.doc_metadata.location_id == feature.gis_location.id) & (db.doc_metadata.deleted == False)
2286
 
                    metadata = db(query).select(orderby=~db.doc_metadata.event_time).first()
2287
 
 
2288
 
                    # Person .represent is too complex to put into JOIN
2289
 
                    contact = shn_pr_person_represent(metadata.person_id)
2290
 
 
2291
 
                except:
2292
 
                    metadata = None
2293
 
                    contact = None
2294
 
                feature.metadata = metadata
2295
 
                feature.contact = contact
2296
 
 
2297
 
                try:
2298
 
                    # Images are M->1 to Features
2299
 
                    # We use the most recently uploaded one
2300
 
                    query = (db.doc_image.location_id == feature.gis_location.id) & (db.doc_image.deleted == False)
2301
 
                    image = db(query).select(db.doc_image.image, orderby=~db.doc_image.created_on).first().image
2302
 
                except:
2303
 
                    image = None
2304
 
                feature.image = image
2305
 
            except:
2306
 
                pass
2307
 
 
2308
 
    # Add the Features to the Return
2309
 
    #output.update(dict(features=features, features_classes=feature_classes, features_markers=feature_markers, features_metadata=feature_metadata))
2310
 
    output.update(dict(feature_groups=feature_groups, features=features))
2311
 
 
2312
 
    return output
2313