[core] allow changing the orientation

You can now change the orientation of north to be to the right, bottom, left in addition to the default of top
This commit is contained in:
Konstantin Käfer
2015-11-16 16:32:09 +01:00
parent 62412af6ab
commit 4fc8226838
12 changed files with 136 additions and 7 deletions

View File

@@ -133,6 +133,10 @@ public:
void setPitch(double pitch, const Duration& = Duration::zero());
double getPitch() const;
// North Orientation
void setNorthOrientation(NorthOrientation);
NorthOrientation getNorthOrientation() const;
// Size
uint16_t getWidth() const;
uint16_t getHeight() const;

View File

@@ -50,6 +50,8 @@ private:
static std::shared_ptr<const mbgl::SpriteImage>
makeSpriteImage(int width, int height, float pixelRatio);
void nextOrientation();
void addRandomPointAnnotations(int count);
void addRandomShapeAnnotations(int count);
void addRandomCustomPointAnnotations(int count);

View File

@@ -100,6 +100,14 @@ struct MetersBounds {
}
};
// Determines the orientation of the map.
enum class NorthOrientation : uint8_t {
Upwards, // Default
Rightwards,
Downwards,
Leftwards,
};
} // namespace mbgl
#endif

View File

@@ -38,6 +38,7 @@ void perspective(mat4& out, double fovy, double aspect, double near, double far)
void copy(mat4& out, const mat4& a);
void translate(mat4& out, const mat4& a, double x, double y, double z);
void rotate_x(mat4& out, const mat4& a, double rad);
void rotate_y(mat4& out, const mat4& a, double rad);
void rotate_z(mat4& out, const mat4& a, double rad);
void scale(mat4& out, const mat4& a, double x, double y, double z);
void multiply(mat4& out, const mat4& a, const mat4& b);

View File

@@ -92,6 +92,7 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("- Press `X` to reset the transform\n");
printf("- Press `N` to reset north\n");
printf("- Press `R` to toggle any available `night` style class\n");
printf("- Press `Z` to cycle through north orientations\n");
printf("\n");
printf("- Press `1` through `6` to add increasing numbers of point annotations for testing\n");
printf("- Press `7` through `0` to add increasing numbers of shape annotations for testing\n");
@@ -153,6 +154,9 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
if (!mods)
view->map->resetNorth();
break;
case GLFW_KEY_Z:
view->nextOrientation();
break;
case GLFW_KEY_Q:
view->clearAnnotations();
break;
@@ -218,6 +222,16 @@ GLFWView::makeSpriteImage(int width, int height, float pixelRatio) {
return std::make_shared<mbgl::SpriteImage>(width, height, pixelRatio, std::move(pixels));
}
void GLFWView::nextOrientation() {
using NO = mbgl::NorthOrientation;
switch (map->getNorthOrientation()) {
case NO::Upwards: map->setNorthOrientation(NO::Rightwards); break;
case NO::Rightwards: map->setNorthOrientation(NO::Downwards); break;
case NO::Downwards: map->setNorthOrientation(NO::Leftwards); break;
default: map->setNorthOrientation(NO::Upwards); break;
}
}
void GLFWView::addRandomCustomPointAnnotations(int count) {
std::vector<mbgl::PointAnnotation> points;

View File

@@ -343,6 +343,18 @@ double Map::getPitch() const {
}
#pragma mark - North Orientation
void Map::setNorthOrientation(NorthOrientation orientation) {
transform->setNorthOrientation(orientation);
update(Update::Repaint);
}
NorthOrientation Map::getNorthOrientation() const {
return transform->getNorthOrientation();
}
#pragma mark - Projection
MetersBounds Map::getWorldBoundsMeters() const {

View File

@@ -498,6 +498,17 @@ double Transform::getPitch() const {
return state.pitch;
}
#pragma mark - North Orientation
void Transform::setNorthOrientation(NorthOrientation orientation) {
state.orientation = orientation;
state.constrain(state.scale, state.x, state.y);
}
NorthOrientation Transform::getNorthOrientation() const {
return state.getNorthOrientation();
}
#pragma mark - Transition
void Transform::startTransition(std::function<double(double)> easing,

View File

@@ -52,6 +52,10 @@ public:
void setPitch(double pitch, const Duration& = Duration::zero());
double getPitch() const;
// North Orientation
void setNorthOrientation(NorthOrientation);
NorthOrientation getNorthOrientation() const;
// Transitions
bool inTransition() const;
Update updateTransitions(const TimePoint& now);

View File

@@ -37,10 +37,17 @@ void TransformState::getProjMatrix(mat4& projMatrix) const {
// After the rotateX, z values are in pixel units. Convert them to
// altitude unites. 1 altitude unit = the screen height.
matrix::scale(projMatrix, projMatrix, 1, -1, 1.0f / getHeight());
matrix::scale(projMatrix, projMatrix, 1, -1, 1.0f / (rotatedNorth() ? getWidth() : getHeight()));
matrix::rotate_x(projMatrix, projMatrix, getPitch());
matrix::rotate_z(projMatrix, projMatrix, getAngle());
using NO = NorthOrientation;
switch (getNorthOrientation()) {
case NO::Rightwards: matrix::rotate_y(projMatrix, projMatrix, getPitch()); break;
case NO::Downwards: matrix::rotate_x(projMatrix, projMatrix, -getPitch()); break;
case NO::Leftwards: matrix::rotate_y(projMatrix, projMatrix, -getPitch()); break;
default: matrix::rotate_x(projMatrix, projMatrix, getPitch()); break;
}
matrix::rotate_z(projMatrix, projMatrix, getAngle() + getNorthOrientationAngle());
matrix::translate(projMatrix, projMatrix, pixel_x() - getWidth() / 2.0f,
pixel_y() - getHeight() / 2.0f, 0);
@@ -72,6 +79,24 @@ uint16_t TransformState::getHeight() const {
return height;
}
#pragma mark - North Orientation
NorthOrientation TransformState::getNorthOrientation() const {
return orientation;
}
double TransformState::getNorthOrientationAngle() const {
double angleOrientation = 0;
if (orientation == NorthOrientation::Rightwards) {
angleOrientation += M_PI / 2.0f;
} else if (orientation == NorthOrientation::Downwards) {
angleOrientation += M_PI;
} else if (orientation == NorthOrientation::Leftwards) {
angleOrientation -= M_PI / 2.0f;
}
return angleOrientation;
}
#pragma mark - Position
LatLng TransformState::getLatLng() const {
@@ -318,21 +343,26 @@ mat4 TransformState::getPixelMatrix() const {
#pragma mark - (private helper functions)
bool TransformState::rotatedNorth() const {
using NO = NorthOrientation;
return (orientation == NO::Leftwards || orientation == NO::Rightwards);
}
void TransformState::constrain(double& scale_, double& x_, double& y_) const {
// Constrain minimum scale to avoid zooming out far enough to show off-world areas.
if (constrainMode == ConstrainMode::WidthAndHeight) {
scale_ = std::max(scale_, static_cast<double>(width / util::tileSize));
scale_ = std::max(scale_, static_cast<double>((rotatedNorth() ? height : width) / util::tileSize));
}
scale_ = std::max(scale_, static_cast<double>(height / util::tileSize));
scale_ = std::max(scale_, static_cast<double>((rotatedNorth() ? width : height) / util::tileSize));
// Constrain min/max pan to avoid showing off-world areas.
if (constrainMode == ConstrainMode::WidthAndHeight) {
double max_x = (scale_ * util::tileSize - width) / 2;
double max_x = (scale_ * util::tileSize - (rotatedNorth() ? height : width)) / 2;
x_ = std::max(-max_x, std::min(x_, max_x));
}
double max_y = (scale_ * util::tileSize - height) / 2;
double max_y = (scale_ * util::tileSize - (rotatedNorth() ? width : height)) / 2;
y_ = std::max(-max_y, std::min(y_, max_y));
}

View File

@@ -34,6 +34,10 @@ public:
uint16_t getWidth() const;
uint16_t getHeight() const;
// North Orientation
NorthOrientation getNorthOrientation() const;
double getNorthOrientationAngle() const;
std::array<float, 2> locationCoordinate(float lon, float lat) const;
void getLonLat(double &lon, double &lat) const;
@@ -74,12 +78,15 @@ public:
TileCoordinate pointToCoordinate(const PrecisionPoint&) const;
private:
bool rotatedNorth() const;
void constrain(double& scale, double& x, double& y) const;
// Limit the amount of zooming possible on the map.
double min_scale = std::pow(2, 0);
double max_scale = std::pow(2, 18);
NorthOrientation orientation = NorthOrientation::Upwards;
// logical dimensions
uint16_t width = 0, height = 0;

View File

@@ -40,6 +40,7 @@ void Painter::renderSDF(SymbolBucket &bucket,
exMatrix = extrudeMatrix;
s = state.getAltitude();
gammaScale = 1.0f;
matrix::rotate_z(exMatrix, exMatrix, state.getNorthOrientationAngle());
}
matrix::scale(exMatrix, exMatrix, s, s, 1);
@@ -218,6 +219,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, const SymbolLayer& layer, const
s = 4096.0f / util::tileSize / id.overscaling / std::pow(2, state.getZoom() - id.z);
} else {
exMatrix = extrudeMatrix;
matrix::rotate_z(exMatrix, exMatrix, state.getNorthOrientationAngle());
s = state.getAltitude();
}
matrix::scale(exMatrix, exMatrix, s, s, 1);

View File

@@ -214,6 +214,40 @@ void matrix::rotate_x(mat4& out, const mat4& a, double rad) {
out[11] = a23 * c - a13 * s;
}
void matrix::rotate_y(mat4& out, const mat4& a, double rad) {
double s = std::sin(rad),
c = std::cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (&a != &out) { // If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
}
// Perform axis-specific matrix multiplication
out[0] = a00 * c - a20 * s;
out[1] = a01 * c - a21 * s;
out[2] = a02 * c - a22 * s;
out[3] = a03 * c - a23 * s;
out[8] = a00 * s + a20 * c;
out[9] = a01 * s + a21 * c;
out[10] = a02 * s + a22 * c;
out[11] = a03 * s + a23 * c;
}
void matrix::rotate_z(mat4& out, const mat4& a, double rad) {
double s = std::sin(rad),
c = std::cos(rad),