<repo_name>FarazKhalidZaki/tplmaps3d<file_sep>/core/src/data/mvtSource.cpp
#include <util/geom.h>
#include "mvtSource.h"
#include "util/mapProjection.h"

#include "tileData.h"
#include "tile/tileID.h"
#include "tile/tile.h"
#include "tile/tileTask.h"
#include "util/pbfParser.h"
#include "platform.h"

namespace Tangram {


MVTSource::MVTSource(const std::string& _name, const std::string& _urlTemplate, int32_t _maxZoom) :
    DataSource(_name, _urlTemplate, _maxZoom) {
}

std::shared_ptr<TileData> MVTSource::parse(const TileTask& _task, const MapProjection& _projection) const {

    auto tileData = std::make_shared<TileData>();

    auto& task = static_cast<const DownloadTileTask&>(_task);

    protobuf::message item(task.rawTileData->data(), task.rawTileData->size());
    BoundingBox tileBounds(_projection.TileBounds(task.tileId()));
    glm::dvec2 tileOrigin = {tileBounds.min.x, tileBounds.max.y*-1.0};
    double tileInverseScale = 1.0 / tileBounds.width();

    PbfParser::ParserContext ctx(m_id);
    const auto projFn = [&](glm::dvec2 _lonLat){
        glm::dvec2 tmp = _projection.LonLatToMeters(_lonLat);
        return Point {
                (tmp.x - tileOrigin.x) * tileInverseScale,
                (tmp.y - tileOrigin.y) * tileInverseScale,
                0
        };
    };
    while(item.next()) {
        if(item.tag == 3) {
            tileData->layers.push_back(PbfParser::getLayer(ctx, item.getMessage(), projFn));
        } else {
            item.skip();
        }
    }
    return tileData;
}

}
<file_sep>/core/src/AxisAlignmentBoundingBox.hpp
//
//  AxisAlignmentBoundingBox.hpp
//  tangram
//
//  Created by <NAME> on 22/06/2016.
//
//

#ifndef AxisAlignmentBoundingBox_hpp
#define AxisAlignmentBoundingBox_hpp

#include <stdio.h>

struct PointD {
    double x;
    double y;
    PointD():x(0.0),y(0.0){}
    PointD(double x, double y):x(x),y(y) {}
};

struct ScreenSize {
    double x;
    double y;
    ScreenSize(double x, double y): x(x), y(y) {};
};

class AxisAlignmentBoundingBox {
    PointD min;
    PointD max;
public:
    
    AxisAlignmentBoundingBox();
    
    void setCenter(PointD);
    PointD getCenter();
    
    void setWidth(double);
    double getWidth();
    
    void setHeight(double);
    double getHeight();
    
    void expandTo(double x, double y);
    
};

#endif /* AxisAlignmentBoundingBox_hpp */
<file_sep>/core/src/tangram.cpp
#include "tangram.h"

#include "platform.h"
#include "scene/scene.h"
#include "scene/sceneLoader.h"
#include "style/material.h"
#include "style/style.h"
#include "labels/labels.h"
#include "text/fontContext.h"
#include "tile/tileManager.h"
#include "tile/tile.h"
#include "gl/error.h"
#include "gl/shaderProgram.h"
#include "gl/renderState.h"
#include "gl/primitives.h"
#include "marker/marker.h"
#include "marker/markerManager.h"
#include "util/asyncWorker.h"
#include "util/inputHandler.h"
#include "tile/tileCache.h"
#include "util/fastmap.h"
#include "view/view.h"
#include "data/clientGeoJsonSource.h"
#include "gl.h"
#include "gl/hardware.h"
#include "util/ease.h"
#include "util/jobQueue.h"
#include "debug/textDisplay.h"
#include "debug/frameInfo.h"

#include <cmath>
#include <bitset>

namespace Tangram {

const static size_t MAX_WORKERS = 2;

enum class EaseField { position, zoom, rotation, tilt };

class Map::Impl {

public:

    void setScene(std::shared_ptr<Scene>& _scene);

    void setEase(EaseField _f, Ease _e);
    void clearEase(EaseField _f);

    void setPositionNow(double _lon, double _lat);
    void setZoomNow(float _z);
    void setRotationNow(float _radians);
    void setTiltNow(float _radians);

    void setPixelScale(float _pixelsPerPoint);

    std::mutex tilesMutex;
    std::mutex sceneMutex;

    RenderState renderState;
    JobQueue jobQueue;
    View view;
    Labels labels;
    AsyncWorker asyncWorker;
    InputHandler inputHandler{view};
    TileWorker tileWorker{MAX_WORKERS};
    TileManager tileManager{tileWorker};
    MarkerManager markerManager;

    std::vector<SceneUpdate> sceneUpdates;
    std::array<Ease, 4> eases;

    std::shared_ptr<Scene> scene = std::make_shared<Scene>();
    std::shared_ptr<Scene> nextScene = nullptr;

    bool cacheGlState;

};

void Map::Impl::setEase(EaseField _f, Ease _e) {
    eases[static_cast<size_t>(_f)] = _e;
    requestRender();
}
void Map::Impl::clearEase(EaseField _f) {
    static Ease none = {};
    eases[static_cast<size_t>(_f)] = none;
}

static std::bitset<8> g_flags = 0;

Map::Map() {

    impl.reset(new Impl());

}

Map::~Map() {
    // The unique_ptr to Impl will be automatically destroyed when Map is destroyed.
    TextDisplay::Instance().deinit();
    Primitives::deinit();
}

void Map::Impl::setScene(std::shared_ptr<Scene>& _scene) {
    {
        std::lock_guard<std::mutex> lock(sceneMutex);
        scene = _scene;
    }

    scene->setPixelScale(view.pixelScale());

    auto& camera = scene->camera();
    view.setCameraType(camera.type);

    switch (camera.type) {
    case CameraType::perspective:
        view.setVanishingPoint(camera.vanishingPoint.x, camera.vanishingPoint.y);
        if (camera.fovStops) {
            view.setFieldOfViewStops(camera.fovStops);
        } else {
            view.setFieldOfView(camera.fieldOfView);
        }
        break;
    case CameraType::isometric:
        view.setObliqueAxis(camera.obliqueAxis.x, camera.obliqueAxis.y);
        break;
    case CameraType::flat:
        break;
    }

    if (camera.maxTiltStops) {
        view.setMaxPitchStops(camera.maxTiltStops);
    } else {
        view.setMaxPitch(camera.maxTilt);
    }

    if (scene->useScenePosition) {
        glm::dvec2 projPos = view.getMapProjection().LonLatToMeters(scene->startPosition);
        view.setPosition(projPos.x, projPos.y);
        view.setZoom(scene->startZoom);
    }

    inputHandler.setView(view);
    tileManager.setDataSources(_scene->dataSources());
    tileWorker.setScene(_scene);
    markerManager.setScene(_scene);
    setPixelScale(view.pixelScale());

    bool animated = scene->animated() == Scene::animate::yes;

    if (scene->animated() == Scene::animate::none) {
        for (const auto& style : scene->styles()) {
            animated |= style->isAnimated();
        }
    }

    if (animated != isContinuousRendering()) {
        setContinuousRendering(animated);
    }
}

void Map::loadScene(const char* _scenePath, bool _useScenePosition) {
    LOG("Loading scene file: %s", _scenePath);

    // Copy old scene
    auto scene = std::make_shared<Scene>(_scenePath);
    scene->useScenePosition = _useScenePosition;

    if (SceneLoader::loadScene(scene)) {
        impl->setScene(scene);
    }
}

void Map::loadSceneAsync(const char* _scenePath, bool _useScenePosition, MapReady _platformCallback) {
    LOG("Loading scene file (async): %s", _scenePath);

    {
        std::lock_guard<std::mutex> lock(impl->sceneMutex);
        impl->sceneUpdates.clear();
        impl->nextScene = std::make_shared<Scene>(_scenePath);
        impl->nextScene->useScenePosition = _useScenePosition;
    }

    runAsyncTask([scene = impl->nextScene, _platformCallback, &jobQueue = impl->jobQueue, this](){

            bool ok = SceneLoader::loadScene(scene);

            jobQueue.add([scene, ok, _platformCallback, this]() {
                    {
                        std::lock_guard<std::mutex> lock(impl->sceneMutex);
                        if (scene == impl->nextScene) {
                            impl->nextScene.reset();
                        } else { return; }
                    }

                    if (ok) {
                        auto s = scene;
                        impl->setScene(s);
                        applySceneUpdates();
                        if (_platformCallback) { _platformCallback(); }
                    }
                });
        });
}

void Map::queueSceneUpdate(const char* _path, const char* _value) {
    std::lock_guard<std::mutex> lock(impl->sceneMutex);
    impl->sceneUpdates.push_back({_path, _value});
}

void Map::applySceneUpdates() {

    LOG("Applying %d scene updates", impl->sceneUpdates.size());

    if (impl->nextScene) {
        // Changes are automatically applied once the scene is loaded
        return;
    }

    std::vector<SceneUpdate> updates;
    {
        std::lock_guard<std::mutex> lock(impl->sceneMutex);
        if (impl->sceneUpdates.empty()) { return; }

        impl->nextScene = std::make_shared<Scene>(*impl->scene);
        impl->nextScene->useScenePosition = false;

        updates = impl->sceneUpdates;
        impl->sceneUpdates.clear();
    }

    runAsyncTask([scene = impl->nextScene, updates = std::move(updates), &jobQueue = impl->jobQueue, this](){

            SceneLoader::applyUpdates(scene->config(), updates);

            bool ok = SceneLoader::applyConfig(scene->config(), scene);

            jobQueue.add([scene, ok, this]() {
                    if (scene == impl->nextScene) {
                        std::lock_guard<std::mutex> lock(impl->sceneMutex);
                        impl->nextScene.reset();
                    } else { return; }

                    if (ok) {
                        auto s = scene;
                        impl->setScene(s);
                        applySceneUpdates();
                    }
                });
        });
}

void Map::resize(int _newWidth, int _newHeight) {

    LOGS("resize: %d x %d", _newWidth, _newHeight);
    LOG("resize: %d x %d", _newWidth, _newHeight);

    glViewport(0, 0, _newWidth, _newHeight);

    impl->view.setSize(_newWidth, _newHeight);

    Primitives::setResolution(impl->renderState, _newWidth, _newHeight);
}

bool Map::update(float _dt) {

    // Wait until font resources are fully loaded
    if (impl->scene->fontContext()->resourceLoad > 0) {
        return false;
    }

    FrameInfo::beginUpdate();

    impl->jobQueue.runJobs();

    impl->scene->updateTime(_dt);

    bool viewComplete = true;
    bool markersNeedUpdate = false;

    for (auto& ease : impl->eases) {
        if (!ease.finished()) {
            ease.update(_dt);
            viewComplete = false;
        }
    }

    impl->inputHandler.update(_dt);

    impl->view.update();

    impl->markerManager.update(static_cast<int>(impl->view.getZoom()));

    for (const auto& style : impl->scene->styles()) {
        style->onBeginUpdate();
    }

    {
        std::lock_guard<std::mutex> lock(impl->tilesMutex);
        ViewState viewState {
            impl->view.getMapProjection(),
            impl->view.changedOnLastUpdate(),
            glm::dvec2{ impl->view.getPosition().x, -impl->view.getPosition().y },
            impl->view.getZoom()
        };

        impl->tileManager.updateTileSets(viewState, impl->view.getVisibleTiles());

        auto& tiles = impl->tileManager.getVisibleTiles();
        auto& markers = impl->markerManager.markers();

        for (const auto& marker : markers) {
            marker->update(_dt, impl->view);
            markersNeedUpdate |= marker->isEasing();
        }

        if (impl->view.changedOnLastUpdate() ||
            impl->tileManager.hasTileSetChanged()) {

            for (const auto& tile : tiles) {
                tile->update(_dt, impl->view);
            }
            impl->labels.updateLabelSet(impl->view, _dt, impl->scene->styles(), tiles, markers,
                                        *impl->tileManager.getTileCache());
        } else {
            impl->labels.updateLabels(impl->view, _dt, impl->scene->styles(), tiles, markers);
        }
    }

    FrameInfo::endUpdate();

    bool viewChanged = impl->view.changedOnLastUpdate();
    bool tilesChanged = impl->tileManager.hasTileSetChanged();
    bool tilesLoading = impl->tileManager.hasLoadingTiles();
    bool labelsNeedUpdate = impl->labels.needUpdate();
    bool resourceLoading = (impl->scene->resourceLoad > 0);
    bool nextScene = bool(impl->nextScene);

    if (viewChanged || tilesChanged || tilesLoading || labelsNeedUpdate || resourceLoading || nextScene) {
        viewComplete = false;
    }

    // Request render if labels are in fading states or markers are easing.
    if (labelsNeedUpdate || markersNeedUpdate) { requestRender(); }

    return viewComplete;
}

void Map::render() {

    FrameInfo::beginFrame();

    // Invalidate render states for new frame
    if (!impl->cacheGlState) {
        impl->renderState.invalidate();
    }

    // Run render-thread tasks
    impl->renderState.jobQueue.runJobs();

    // Set up openGL for new frame
    impl->renderState.depthMask(GL_TRUE);
    auto& color = impl->scene->background();
    impl->renderState.clearColor(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
    GL_CHECK(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));

    for (const auto& style : impl->scene->styles()) {
        style->onBeginFrame(impl->renderState);
    }

    {
        std::lock_guard<std::mutex> lock(impl->tilesMutex);

        // Loop over all styles
        for (const auto& style : impl->scene->styles()) {

            style->onBeginDrawFrame(impl->renderState, impl->view, *(impl->scene));

            // Loop over all tiles in m_tileSet
            for (const auto& tile : impl->tileManager.getVisibleTiles()) {
                style->draw(impl->renderState, *tile);
            }

            for (const auto& marker : impl->markerManager.markers()) {
                style->draw(impl->renderState, *marker);
            }

            style->onEndDrawFrame();
        }
    }

    impl->labels.drawDebug(impl->renderState, impl->view);

    FrameInfo::draw(impl->renderState, impl->view, impl->tileManager);
}

int Map::getViewportHeight() {
    return impl->view.getHeight();
}

int Map::getViewportWidth() {
    return impl->view.getWidth();
}

float Map::getPixelScale() {
    return impl->view.pixelScale();
}

void Map::captureSnapshot(unsigned int* _data) {
    GL_CHECK(glReadPixels(0, 0, impl->view.getWidth(), impl->view.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)_data));
}

void Map::Impl::setPositionNow(double _lon, double _lat) {

    glm::dvec2 meters = view.getMapProjection().LonLatToMeters({ _lon, _lat});
    view.setPosition(meters.x, meters.y);
    inputHandler.cancelFling();
    requestRender();

}

void Map::setPosition(double _lon, double _lat) {

    impl->setPositionNow(_lon, _lat);
    impl->clearEase(EaseField::position);

}

void Map::setPositionEased(double _lon, double _lat, float _duration, EaseType _e) {

    double lon_start, lat_start;
    getPosition(lon_start, lat_start);
    auto cb = [=](float t) { impl->setPositionNow(ease(lon_start, _lon, t, _e), ease(lat_start, _lat, t, _e)); };
    impl->setEase(EaseField::position, { _duration, cb });

}

void Map::getPosition(double& _lon, double& _lat) {

    glm::dvec2 meters(impl->view.getPosition().x, impl->view.getPosition().y);
    glm::dvec2 degrees = impl->view.getMapProjection().MetersToLonLat(meters);
    _lon = degrees.x;
    _lat = degrees.y;

}

void Map::Impl::setZoomNow(float _z) {

    view.setZoom(_z);
    inputHandler.cancelFling();
    requestRender();

}

void Map::setZoom(float _z) {

    impl->setZoomNow(_z);
    impl->clearEase(EaseField::zoom);

}

void Map::setZoomEased(float _z, float _duration, EaseType _e) {

    float z_start = getZoom();
    auto cb = [=](float t) { impl->setZoomNow(ease(z_start, _z, t, _e)); };
    impl->setEase(EaseField::zoom, { _duration, cb });

}

float Map::getZoom() {

    return impl->view.getZoom();

}

void Map::Impl::setRotationNow(float _radians) {

    view.setRoll(_radians);
    requestRender();

}

void Map::setRotation(float _radians) {

    impl->setRotationNow(_radians);
    impl->clearEase(EaseField::rotation);

}

void Map::setRotationEased(float _radians, float _duration, EaseType _e) {

    float radians_start = getRotation();

    // Ease over the smallest angular distance needed
    float radians_delta = glm::mod(_radians - radians_start, (float)TWO_PI);
    if (radians_delta > PI) { radians_delta -= TWO_PI; }
    _radians = radians_start + radians_delta;

    auto cb = [=](float t) { impl->setRotationNow(ease(radians_start, _radians, t, _e)); };
    impl->setEase(EaseField::rotation, { _duration, cb });

}

float Map::getRotation() {

    return impl->view.getRoll();

}


void Map::Impl::setTiltNow(float _radians) {

    view.setPitch(_radians);
    requestRender();

}

void Map::setTilt(float _radians) {

    impl->setTiltNow(_radians);
    impl->clearEase(EaseField::tilt);

}

void Map::setTiltEased(float _radians, float _duration, EaseType _e) {

    float tilt_start = getTilt();
    auto cb = [=](float t) { impl->setTiltNow(ease(tilt_start, _radians, t, _e)); };
    impl->setEase(EaseField::tilt, { _duration, cb });

}

float Map::getTilt() {

    return impl->view.getPitch();

}

bool Map::screenPositionToLngLat(double _x, double _y, double* _lng, double* _lat) {

    double intersection = impl->view.screenToGroundPlane(_x, _y);
    glm::dvec3 eye = impl->view.getPosition();
    glm::dvec2 meters(_x + eye.x, _y + eye.y);
    glm::dvec2 lngLat = impl->view.getMapProjection().MetersToLonLat(meters);
    *_lng = lngLat.x;
    *_lat = lngLat.y;

    return (intersection >= 0);
}

bool Map::lngLatToScreenPosition(double _lng, double _lat, double* _x, double* _y) {
    bool clipped = false;

    glm::vec2 screenCoords = impl->view.lonLatToScreenPosition(_lng, _lat, clipped);

    *_x = screenCoords.x;
    *_y = screenCoords.y;

    float width = impl->view.getWidth();
    float height = impl->view.getHeight();
    bool withinViewport = *_x >= 0. && *_x <= width && *_y >= 0. && *_y <= height;

    return !clipped && withinViewport;
}

void Map::setPixelScale(float _pixelsPerPoint) {

    impl->setPixelScale(_pixelsPerPoint);

}

void Map::Impl::setPixelScale(float _pixelsPerPoint) {

    view.setPixelScale(_pixelsPerPoint);
    scene->setPixelScale(_pixelsPerPoint);
    for (auto& style : scene->styles()) {
        style->setPixelScale(_pixelsPerPoint);
    }

}

void Map::setCameraType(int _type) {

    impl->view.setCameraType(static_cast<CameraType>(_type));
    requestRender();

}

int Map::getCameraType() {

    return static_cast<int>(impl->view.cameraType());

}

void Map::addDataSource(std::shared_ptr<DataSource> _source) {
    std::lock_guard<std::mutex> lock(impl->tilesMutex);
    impl->tileManager.addClientDataSource(_source);
}

bool Map::removeDataSource(DataSource& source) {
    std::lock_guard<std::mutex> lock(impl->tilesMutex);
    return impl->tileManager.removeClientDataSource(source);
}

void Map::clearDataSource(DataSource& _source, bool _data, bool _tiles) {
    std::lock_guard<std::mutex> lock(impl->tilesMutex);

    if (_tiles) { impl->tileManager.clearTileSet(_source.id()); }
    if (_data) { _source.clearData(); }

    requestRender();
}

MarkerID Map::markerAdd() {
    return impl->markerManager.add();
}

bool Map::markerRemove(MarkerID _marker) {
    bool success = impl->markerManager.remove(_marker);
    requestRender();
    return success;
}

bool Map::markerSetPoint(MarkerID _marker, LngLat _lngLat) {
    bool success = impl->markerManager.setPoint(_marker, _lngLat);
    requestRender();
    return success;
}

bool Map::markerSetPointEased(MarkerID _marker, LngLat _lngLat, float _duration, EaseType ease) {
    bool success = impl->markerManager.setPointEased(_marker, _lngLat, _duration, ease);
    requestRender();
    return success;
}

bool Map::markerSetPolyline(MarkerID _marker, LngLat* _coordinates, int _count) {
    bool success = impl->markerManager.setPolyline(_marker, _coordinates, _count);
    requestRender();
    return success;
}

bool Map::markerSetPolygon(MarkerID _marker, LngLat* _coordinates, int* _counts, int _rings) {
    bool success = impl->markerManager.setPolygon(_marker, _coordinates, _counts, _rings);
    requestRender();
    return success;
}

bool Map::markerSetStyling(MarkerID _marker, const char* _styling) {
    bool success = impl->markerManager.setStyling(_marker, _styling);
    requestRender();
    return success;
}

bool Map::markerSetVisible(MarkerID _marker, bool _visible) {
    bool success = impl->markerManager.setVisible(_marker, _visible);
    requestRender();
    return success;
}

void Map::markerRemoveAll() {
    impl->markerManager.removeAll();
    requestRender();
}

void Map::handleTapGesture(float _posX, float _posY) {

    impl->inputHandler.handleTapGesture(_posX, _posY);

}

void Map::handleDoubleTapGesture(float _posX, float _posY) {

    impl->inputHandler.handleDoubleTapGesture(_posX, _posY);

}

void Map::handlePanGesture(float _startX, float _startY, float _endX, float _endY) {

    impl->inputHandler.handlePanGesture(_startX, _startY, _endX, _endY);

}

void Map::handleFlingGesture(float _posX, float _posY, float _velocityX, float _velocityY) {

    impl->inputHandler.handleFlingGesture(_posX, _posY, _velocityX, _velocityY);

}

void Map::handlePinchGesture(float _posX, float _posY, float _scale, float _velocity) {

    impl->inputHandler.handlePinchGesture(_posX, _posY, _scale, _velocity);

}

void Map::handleRotateGesture(float _posX, float _posY, float _radians) {

    impl->inputHandler.handleRotateGesture(_posX, _posY, _radians);

}

void Map::handleShoveGesture(float _distance) {

    impl->inputHandler.handleShoveGesture(_distance);

}

void Map::setupGL() {

    LOG("setup GL");

    impl->tileManager.clearTileSets();

    // Reconfigure the render states. Increases context 'generation'.
    // The OpenGL context has been destroyed since the last time resources were
    // created, so we invalidate all data that depends on OpenGL object handles.
    impl->renderState.increaseGeneration();
    impl->renderState.invalidate();

    // Set default primitive render color
    Primitives::setColor(impl->renderState, 0xffffff);

    // Load GL extensions and capabilities
    Hardware::loadExtensions();
    Hardware::loadCapabilities();

    Hardware::printAvailableExtensions();
}

void Map::useCachedGlState(bool _useCache) {
    impl->cacheGlState = _useCache;
}

const std::vector<TouchItem>& Map::pickFeaturesAt(float _x, float _y) {
    return impl->labels.getFeaturesAtPoint(impl->view, 0, impl->scene->styles(),
                                           impl->tileManager.getVisibleTiles(),
                                           _x, _y);
}

void Map::runAsyncTask(std::function<void()> _task) {
    impl->asyncWorker.enqueue(std::move(_task));
}
    void Map::zoomToShowSegment(std::vector<Tangram::LngLat> route, ScreenSize screenSize, float tilt,float rotation, float ratio) {
        // Make sure we have some points to work with
        if (route.empty()) {
            return;
        }

        setRotation(0);
        setTilt(tilt);

        // Determine the smallest axis-aligned box that contains the route longitude and latitude
        auto start = route.front();
        //auto finish = route.back();
        AxisAlignmentBoundingBox routeBounds;

        routeBounds.setCenter(PointD(start.longitude, start.latitude));

        for (auto p: route) {
            routeBounds.expandTo(p.longitude, p.latitude);
        }


        // Add some padding to the box
        double padding = 0.10;
        routeBounds.setWidth((1.0 + padding) * routeBounds.getWidth());
        routeBounds.setHeight((1.0 + padding) * routeBounds.getHeight());

        // Determine the bounds of the current view in longitude and latitude
        float pixleScale = impl->view.   pixelScale();
        ScreenSize screen = ScreenSize(screenSize.x*pixleScale, screenSize.y*pixleScale);

        float upperOffset = ratio;
        float lowerOffset = 1-ratio;

        LOG("UpperOffset = %f",upperOffset);
        LOG("UpperOffset = %f",lowerOffset);

        // Take half of the y dimension to allow space for other UI elements

        double x = 0.0;
        double y = screen.y * upperOffset;
        double *lng = new double;
        double *lat = new double;

        screenPositionToLngLat(x, y, lng, lat);
        LngLat viewMin(*lng, *lat);

        x = screen.x;
        y = screen.y * lowerOffset;

        screenPositionToLngLat(x, y, lng, lat);
        LngLat viewMax(*lng, *lat);


        // Determine the amount of re-scaling needed to view the route
        double scaleX = routeBounds.getWidth() / std::abs(viewMax.longitude - viewMin.longitude);
        double scaleY = routeBounds.getHeight() / std::abs(viewMax.latitude - viewMin.latitude);
        double zoomDelta = -std::log(std::max(scaleX, scaleY)) / std::log(2.0);

        // Update map position and zoom

        float z = getZoom() + zoomDelta;
        Map::setZoomEased(z,1.0f);
        //if (getZoom() == z) {
        Map::setPositionEased(routeBounds.getCenter().x, routeBounds.getCenter().y,1.0f);
        //}
        setRotation(rotation);
    }
    double degreesToRadians(double degrees) {
        return degrees * M_PI / 180.0;
    }

    double radiansToDegrees(double radians) {
        return radians * 180.0/M_PI;
    }

    float Map::rotationForSegment(std::vector<Tangram::LngLat> segment,float azimuth) {

        LOG("azmith %f",azimuth);
        if (azimuth<0) //Degrees
            azimuth+=(float) 360.0;
        azimuth = 0.0;

        auto point1 = segment.front();
        auto point2 = segment.back();

        double lat1 = degreesToRadians(point1.latitude);
        double lon1 = degreesToRadians(point1.longitude);

        double lat2 = degreesToRadians(point2.latitude);
        double lon2 = degreesToRadians(point2.longitude);

        double dLon = lon2 - lon1;

        double y = sin(dLon) * cos(lat2);
        double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
        double radiansBearing = atan2(y, x);

        //LOG("radianBearing %f",radiansBearing);

        if(radiansBearing < 0.0)
            radiansBearing += 2*M_PI;

        float bearTo = radiansToDegrees(radiansBearing);

        LOG("Bearing %f",bearTo);

        float rotation = bearTo - azimuth;

        LOG("Rotation %f",rotation);

        if (rotation < 0) {
            rotation = rotation + 360;
        }

        rotation = 360-rotation;

        LOG("Final Rotation %f",rotation);

        rotation = degreesToRadians(rotation);
        setRotationEased(rotation,1.0f);
        return rotation;
    }


    void setDebugFlag(DebugFlags _flag, bool _on) {

    g_flags.set(_flag, _on);
    // m_view->setZoom(m_view->getZoom()); // Force the view to refresh

}

bool getDebugFlag(DebugFlags _flag) {

    return g_flags.test(_flag);

}

void toggleDebugFlag(DebugFlags _flag) {

    g_flags.flip(_flag);
    // m_view->setZoom(m_view->getZoom()); // Force the view to refresh

    // Rebuild tiles for debug modes that needs it
    // if (_flag == DebugFlags::proxy_colors
    //  || _flag == DebugFlags::draw_all_labels
    //  || _flag == DebugFlags::tile_bounds
    //  || _flag == DebugFlags::tile_infos) {
    //     if (m_tileManager) {
    //         std::lock_guard<std::mutex> lock(m_tilesMutex);
    //         m_tileManager->clearTileSets();
    //     }
    // }
}

    double distanceBetweenUserAndSegment(std::vector<Tangram::LngLat> segment, Tangram::LngLat location) {
        double minDistanceCalculated = -1;

        for (size_t it = 0; it != segment.size()-1; it++) {

            Tangram::LngLat first = segment.at(it);
            Tangram::LngLat second = segment.at(it+1);

            double pointLnA[] = {first.latitude, first.longitude};
            double pointLnB[] = {second.latitude, second.longitude};
            double pointUser[] = {location.latitude, location.longitude};

            MathUtils mathUtil;
            double distancePartialSegment = mathUtil.lineToPointDistance2D(pointLnA, pointLnB, pointUser, true);
            distancePartialSegment *= 100000;           // Conversion into meters

            if (it == 0) {
                minDistanceCalculated = distancePartialSegment;
            } else {
                if (distancePartialSegment < minDistanceCalculated)
                    minDistanceCalculated = distancePartialSegment;
            }

        }

        return minDistanceCalculated;
    }
}
<file_sep>/core/src/MathUtils.hpp
//
//  MathUtils.hpp
//  tangram
//
//  Created by <NAME> on 28/06/2016.
//
//

#ifndef MathUtils_hpp
#define MathUtils_hpp

#include <stdio.h>
#include "math.h"
#include "cmath"
#include "tangram.h"
namespace Tangram {
    
class MathUtils {
public:
    double dotProduct(double pointA[], double pointB[], double pointC[]);
    double crossProduct(double pointA[], double pointB[], double pointC[]);
    double distance(double pointA[], double pointB[]);
    double lineToPointDistance2D(double pointA[], double pointB[], double pointC[], bool isSegment);
    
};
}
#endif /* MathUtils_hpp */
<file_sep>/core/src/MathUtils.cpp
//
//  MathUtils.cpp
//  tangram
//
//  Created by <NAME> on 28/06/2016.
//
//

#include "MathUtils.hpp"


namespace Tangram {
    double MathUtils::dotProduct(double *pointA, double *pointB, double *pointC) {
        double AB[2];
        double BC[2];
        AB[0] = pointB[0] - pointA[0];
        AB[1] = pointB[1] - pointA[1];
        BC[0] = pointC[0] - pointB[0];
        BC[1] = pointC[1] - pointB[1];
        //double dot = AB[0] * BC[0] + AB[1] * BC[1];
        
        return AB[0] * BC[0] + AB[1] * BC[1];
    }
    
    double MathUtils::crossProduct(double *pointA, double *pointB, double *pointC) {
        double AB[2];
        double AC[2];
        
        AB[0] = pointB[0] - pointA[0];
        AB[1] = pointB[1] - pointA[1];
        AC[0] = pointC[0] - pointA[0];
        AC[1] = pointC[1] - pointA[1];
        //double cross = AB[0] * AC[1] - AB[1] * AC[0];
        
        return AB[0] * AC[1] - AB[1] * AC[0];
    }
    
    double MathUtils::distance(double *pointA, double *pointB) {
        double d1 = pointA[0] - pointB[0];
        double d2 = pointA[1] - pointB[1];
        
        return sqrt(d1 * d1 + d2 * d2);
    }
    
    double MathUtils::lineToPointDistance2D(double *pointA, double *pointB, double *pointC, bool isSegment) {
        double dist = crossProduct(pointA, pointB, pointC) / distance(pointA, pointB);
        if (isSegment) {
            double dot1 = dotProduct(pointA, pointB, pointC);
            if (dot1 > 0)
            return distance(pointB, pointC);
            
            double dot2 = dotProduct(pointB, pointA, pointC);
            if (dot2 > 0)
            return distance(pointA, pointC);
        }
        return std::abs(dist);
    }
};
<file_sep>/core/src/AxisAlignmentBoundingBox.cpp
//
//  AxisAlignmentBoundingBox.cpp
//  tangram
//
//  Created by <NAME> on 22/06/2016.
//
//

#include <algorithm>
#include "AxisAlignmentBoundingBox.hpp"
///Setters and Getters

AxisAlignmentBoundingBox::AxisAlignmentBoundingBox() {
    min = PointD();
    max = PointD();
}

//Center
void AxisAlignmentBoundingBox::setCenter(PointD c) {
    double hw = 0.5 * getWidth();
    double hh = 0.5 * getHeight();
    max = PointD(c.x + hw, c.y + hh);
    min = PointD(c.x - hw, c.y - hh);
}

PointD AxisAlignmentBoundingBox::getCenter() {
    return PointD(0.5 * (max.x + min.x), 0.5 * (max.y + min.y));
}


//Width
void AxisAlignmentBoundingBox::setWidth(double w) {
    PointD c = getCenter();
    max.x = c.x + 0.5 * w;
    min.x = c.x - 0.5 * w;
}

double AxisAlignmentBoundingBox::getWidth() {
    return max.x - min.x;
}

//Height

void AxisAlignmentBoundingBox::setHeight(double h) {
    PointD c = getCenter();
    max.y = c.y + 0.5 * h;
    min.y = c.y - 0.5 * h;
}

double AxisAlignmentBoundingBox::getHeight() {
    return max.y - min.y;
}

///
void AxisAlignmentBoundingBox::expandTo(double x, double y) {
    max.x = std::max(max.x, x);
    max.y = std::max(max.y, y);
    min.x = std::min(min.x, x);
    min.y = std::min(min.y, y);
}


