Giter Site home page Giter Site logo

Comments (5)

Pomax avatar Pomax commented on July 30, 2024 1

(To preempt "Why not just use docker?", mostly it's because docker is a monster to install on Windows. Any project that you can run without needing Docker is a sigh of relief)

from open-elevation.

Pomax avatar Pomax commented on July 30, 2024

Example rewrite without gunicorn (obviously not polished, but good enough for my needs):

import configparser
import json
import os
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs, urlparse

from gdal_interfaces import GDALTileInterface


class InternalException(ValueError):
    """
    Utility exception class to handle errors internally and return error codes to the client
    """
    pass


print('Reading config file ...')
parser = configparser.ConfigParser()
parser.read('config.ini')

HOST = '127.0.0.1'
PORT = 9000
DATA_FOLDER = parser.get('server', 'data-folder')
OPEN_INTERFACES_SIZE = parser.getint('server', 'open-interfaces-size')


interface = GDALTileInterface(
    DATA_FOLDER, '%s/summary.json' % DATA_FOLDER, OPEN_INTERFACES_SIZE)
interface.create_summary_json()


def get_elevation(lat, lng):
    """
    Get the elevation at point (lat,lng) using the currently opened interface
    :param lat:
    :param lng:
    :return:
    """
    try:
        elevation = interface.lookup(lat, lng)
    except:
        return {
            'latitude': lat,
            'longitude': lng,
            'error': 'No such coordinate (%s, %s)' % (lat, lng)
        }

    return {
        'latitude': lat,
        'longitude': lng,
        'elevation': elevation
    }


def lat_lng_from_location(location_with_comma):
    """
    Parse the latitude and longitude of a location in the format "xx.xxx,yy.yyy" (which we accept as a query string)
    :param location_with_comma:
    :return:
    """
    try:
        lat, lng = [float(i) for i in location_with_comma.split(',')]
        return lat, lng
    except:
        raise InternalException(json.dumps(
            {'error': 'Bad parameter format "%s".' % location_with_comma}))


def query_to_locations(query):
    """
    Grab a list of locations from the query and turn them into [(lat,lng),(lat,lng),...]
    :return:
    """
    locations = query['locations'][0] if 'locations' in query else None
    if not locations:
        raise InternalException(json.dumps(
            {'error': '"Locations" is required.'}))

    return [lat_lng_from_location(l) for l in locations.split('|')]


def body_to_locations(payload):
    """
    Grab a list of locations from the body and turn them into [(lat,lng),(lat,lng),...]
    :return:
    """
    try:
        locations = payload.get('locations', None)
    except Exception:
        raise InternalException(json.dumps({'error': 'Invalid JSON.'}))

    if not locations:
        raise InternalException(json.dumps(
            {'error': '"Locations" is required in the body.'}))

    latlng = []
    for l in locations:
        try:
            latlng += [(l['latitude'], l['longitude'])]
        except KeyError:
            raise InternalException(json.dumps(
                {'error': '"%s" is not in a valid format.' % l}))

    return latlng


def do_lookup(locations):
    """
    Generic method which gets the locations in [(lat,lng),(lat,lng),...] format by calling get_locations_func
    and returns an answer ready to go to the client.
    :return:
    """
    return {'results': [get_elevation(lat, lng) for (lat, lng) in locations]}


class OpenElevationServer(BaseHTTPRequestHandler):
    def set_headers(self):
        self.send_response(200)
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Cache-Control', 'no-cache')
        self.send_header('Content-type', 'application/json')
        self.end_headers()

    def log_request(self, code='-', size='-'):
        # Don't log regular requests, only error
        return

    def do_GET(self):
        """
        GET method. Uses query_to_locations.
        :return:
        """
        if self.path == '/favicon.ico':
            return self.send_response(404)

        query = parse_qs(urlparse(self.path).query)

        try:
            data = do_lookup(query_to_locations(query))
            response = json.dumps(data).encode('utf-8')
            self.set_headers()
            self.wfile.write(response)
        except :
            self.send_response(400)

    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header('Access-Control-Allow-Credentials', 'true')
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header("Access-Control-Allow-Headers", "X-Requested-With, Content-type")
        self.end_headers()

    def do_POST(self):
        """
        GET method. Uses body_to_locations.
        :return:
        """
        payload = json.loads(self.rfile.read(
            int(self.headers['Content-Length'])))

        try:
            data = do_lookup(body_to_locations(payload))
            response = json.dumps(data).encode('utf-8')
            self.set_headers()
            self.wfile.write(response)
        except:
            self.send_response(400)


def run():
    try:
        webServer = HTTPServer((HOST, PORT), OpenElevationServer)
        print(f'Server started http://{HOST}:{PORT}')
        webServer.serve_forever()
    except KeyboardInterrupt:
        webServer.server_close()
        print('Server stopped')
        os._exit(1)


if __name__ == "__main__":
    run()

from open-elevation.

Pomax avatar Pomax commented on July 30, 2024

Mind you, when I run this, things mostly work fine, but not when I'm working with coordinates in New Zealand. Calling http://localhost:9000/?locations=-44.9856891,168.321971 yields an error index 14551 is out of bounds for axis 1 with size 10081 in the terminal.

Is there a simple or clever way to check which tiles cover which part of the planet, to see if there's any gaps?

from open-elevation.

aliasfoxkde avatar aliasfoxkde commented on July 30, 2024

Perfect, this was very helpful for what I'm doing. Thanks!

from open-elevation.

davidetedesco1 avatar davidetedesco1 commented on July 30, 2024

Hi where i can get meshes.py?

from open-elevation.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.