Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Outlines barbs and text #251

Merged
merged 36 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a266340
Saving code
maartenplieger Feb 15, 2023
2acb8bd
Merge branch 'master' of https://github.com/KNMI/adaguc-server into o…
maartenplieger Feb 15, 2023
0c3dea4
Update from master
maartenplieger Feb 15, 2023
367f808
Merge branch 'shadeintervalnearest' of https://github.com/KNMI/adaguc…
maartenplieger Feb 15, 2023
536f91e
Fixing tests again
maartenplieger Feb 15, 2023
15361dc
Functionality works, tests have to be fixed and added
maartenplieger Feb 15, 2023
056f916
Merged
maartenplieger Mar 8, 2023
06da594
Merge branch 'ubuntu22' of github.com:KNMI/adaguc-server into outline…
maartenplieger Mar 8, 2023
8473858
Fixing tests
maartenplieger Mar 8, 2023
79c7701
StrokeWidth for text is now configurable
maartenplieger Mar 9, 2023
b1c6134
Merged from master
maartenplieger Mar 9, 2023
73e665a
Merged
maartenplieger Apr 17, 2023
7d2a9a6
Updated tests
maartenplieger Apr 19, 2023
8589d1f
Added test
maartenplieger Apr 19, 2023
9bf8b05
2.8.7 wrapping up
maartenplieger Apr 19, 2023
e4e05ed
Back to yapf
maartenplieger Apr 19, 2023
7ec546d
Merged
maartenplieger May 10, 2023
78542e5
Merged
maartenplieger May 10, 2023
630611c
Finetuning
maartenplieger May 10, 2023
1490189
Updated with master
maartenplieger May 19, 2023
31ba7ac
Updated with master
maartenplieger May 19, 2023
60f4934
Updated with master
maartenplieger May 19, 2023
08a7c52
Merged from master
maartenplieger Jun 1, 2023
24ce885
Improving barb renderings
maartenplieger Jun 2, 2023
d87d400
More comments resolved
maartenplieger Jun 2, 2023
e69b837
Added test for dashed contourlines too
maartenplieger Jun 2, 2023
7c1ad31
Fix test
maartenplieger Jun 2, 2023
6d5351a
Merge branch 'master' of github.com:KNMI/adaguc-server into outlines-…
maartenplieger Jun 21, 2023
612be1e
Moved function
maartenplieger Jun 21, 2023
65a2d76
Using samen PI everywhere
maartenplieger Jun 21, 2023
0562239
Switch Cairo stroked text to use FreeType font.
lukas-phaf Jun 28, 2023
953578a
Fix test in ARM docker container by allowing high leeway for some pix…
lukas-phaf Jun 29, 2023
71fef57
Convert png to 32 bit to avoid palette differences.
lukas-phaf Jun 29, 2023
91aed45
Fix 49 knots windbarb for GD.
lukas-phaf Jun 29, 2023
90d5e83
Switch to always use pi (M_PI) from <math.h>. Remove some unused code.
lukas-phaf Jun 30, 2023
56308e1
Reverted change for toknots processor
maartenplieger Jun 30, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
"valarray": "cpp",
"variant": "cpp",
"shared_mutex": "cpp",
"regex": "cpp"
"regex": "cpp",
"numbers": "cpp"
},
"cmake.buildDirectory": "${workspaceFolder}/bin",
"cmake.configureOnOpen": true,
Expand Down
2 changes: 1 addition & 1 deletion CCDFDataModel/CCDFPNGIO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ class BoundingBox {
double east;
double west;
};
#define pi 3.141592654
#define pi M_PI

class P {
public:
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ USER root
LABEL maintainer="adaguc@knmi.nl"

# Version should be same as in Definitions.h
LABEL version="2.10.4"
LABEL version="2.10.5"

######### First stage (build) ############

Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
**Version 2.10.5 2023-06-02**
- Contourlines can have dashes
- Contour text can have an outline
- Windbarbs have a white outline

**Version 2.10.4 2023-06-01**
- Fix: Racmo datasets with rotated_pole projection does work again

Expand Down
213 changes: 212 additions & 1 deletion adagucserverEC/CCairoPlotter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#ifdef ADAGUC_USE_CAIRO
// #define MEASURETIME

#include <cairo-ft.h>
#include "CStopWatch.h"
const char *CCairoPlotter::className = "CCairoPlotter";

Expand Down Expand Up @@ -323,7 +324,7 @@ int CCairoPlotter::_drawFreeTypeText(int x, int y, int &w, int &h, float angle,
pen.y = (my_target_height - y) * 64;
bool c3seen = false;
/* Using the 8859-15 standard */
for (n = 0; n < num_chars; n++) { /* set transformation */
for (n = 0; n < num_chars; n++) { /* set transformation */

FT_Set_Transform(face, &matrix, &pen); /* load glyph image into the slot (erase previous one) */

Expand Down Expand Up @@ -535,11 +536,19 @@ void CCairoPlotter::lineTo(float x1, float y1, float width) {
cairo_set_line_width(cr, width);
cairo_line_to(cr, x1 + 0.5, y1 + 0.5);
}

void CCairoPlotter::endLine() {
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
cairo_stroke(cr);
}

void CCairoPlotter::endLine(const double *dashes, int num_dashes) {
cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER);
cairo_set_dash(cr, dashes, num_dashes, 0);
cairo_stroke(cr);
cairo_set_dash(cr, 0, 0, 0);
}

void CCairoPlotter::line(float x1, float y1, float x2, float y2) {
cairo_set_source_rgba(cr, rr, rg, rb, ra);
cairo_move_to(cr, x1 + 0.5, y1 + 0.5);
Expand Down Expand Up @@ -653,6 +662,56 @@ void CCairoPlotter::drawText(int x, int y, double angle, const char *text) {
_drawFreeTypeText(x, y, w, h, angle, text, true);
}

void CCairoPlotter::drawStrokedText(int x, int y, double angle, const char *text, float fontSize, float strokeWidth, CColor bgcolor, CColor fgcolor) {
if (library == NULL) {
int status = initializeFreeType();
if (status != 0) {
// TODO
}
}

cairo_save(cr);

cairo_font_face_t *ct = cairo_ft_font_face_create_for_ft_face(face, 0);
cairo_set_font_face (cr, ct);
cairo_set_font_size(cr, fontSize);

// Save the current path, because we might be drawing something like contour lines, which should not be stroked.
cairo_path_t *cp = cairo_copy_path(cr);

cairo_new_path(cr);
cairo_set_dash(cr, 0, 0, 0);

cairo_move_to(cr, x, y);
cairo_rotate(cr, angle);
cairo_text_path(cr, text);
if (strokeWidth > 0) {
cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, bgcolor.r / 255., bgcolor.g / 255., bgcolor.b / 255., .2);
cairo_set_line_width(cr, 2.5 + strokeWidth);
cairo_stroke_preserve(cr);

cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, bgcolor.r / 255., bgcolor.g / 255., bgcolor.b / 255., 1);
cairo_set_line_width(cr, 1.5 + strokeWidth);
cairo_stroke_preserve(cr);
}

cairo_set_antialias(cr, CAIRO_ANTIALIAS_BEST);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, fgcolor.r / 255., fgcolor.g / 255., fgcolor.b / 255., 1);
cairo_fill(cr);

cairo_close_path(cr);

cairo_restore(cr);
// Put the original path back
cairo_append_path(cr, cp);
cairo_path_destroy(cp);
}

void CCairoPlotter::writeToPng24Stream(FILE *fp, unsigned char) { writeARGBPng(width, height, ARGBByteBuffer, fp, 24, false); }

void CCairoPlotter::writeToPng8Stream(FILE *fp, unsigned char, bool use8bitpalAlpha) { writeARGBPng(width, height, ARGBByteBuffer, fp, 8, use8bitpalAlpha); }
Expand Down Expand Up @@ -1044,3 +1103,155 @@ void CCairoPlotter::writeToWebP32Stream(FILE *fp, unsigned char, int quality) {
}

#endif

static int drawBarbTriangle(cairo_t *cr, int x, int y, int nPennants, double direction, double shaftLength, double barbLengthWithFlip, int nrPos) {
int pos = 0;
double dx1 = cos(direction) * (shaftLength);
double dy1 = sin(direction) * (shaftLength);
double wx1 = double(x) - dx1;
double wy1 = double(y) + dy1; // wind barb top (flag side)

for (int i = 0; i < nPennants; i++) {
double wx3 = wx1 + pos * dx1 / nrPos;
double wy3 = wy1 - pos * dy1 / nrPos;
pos++;
double hx3 = wx1 + pos * dx1 / nrPos + cos(M_PI + direction + M_PI / 2) * barbLengthWithFlip;
double hy3 = wy1 - pos * dy1 / nrPos - sin(M_PI + direction + M_PI / 2) * barbLengthWithFlip;
pos++;
double wx4 = wx1 + pos * dx1 / nrPos;
double wy4 = wy1 - pos * dy1 / nrPos;

double ptx[3] = {wx3, hx3, wx4};
double pty[3] = {wy3, hy3, wy4};

cairo_move_to(cr, ptx[0], pty[0]);
for (int j = 1; j < 3; j++) {
cairo_line_to(cr, ptx[j], pty[j]);
}
}
return pos;
}

void CCairoPlotter::drawBarb(int x, int y, double direction, double strength, CColor barbColor, CColor outlineColor, bool drawOutline, float lineWidth, bool toKnots, bool flip, bool drawText) {
// Barb settings
float centerDiscRadius = 3;
int shaftLength = 37;
int barbLength = 12;
int halfBarbLength = 6;

// Preserve path
cairo_save(cr);
cairo_path_t *cp = cairo_copy_path(cr);
cairo_new_path(cr);
cairo_set_line_width(cr, lineWidth);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);

int strengthInKnots = round(strength);
if (toKnots) {
strengthInKnots = round(strength * 3600 / 1852.);
}

// Rounded to the nearest 5 kts
int strengthInKnotsRoundedToFive = round((strengthInKnots + 2) / 5) * 5;

int nPennants = strengthInKnotsRoundedToFive / 50;
int nBarbs = (strengthInKnotsRoundedToFive % 50) / 10 + 0.5;
bool hasHalfBarb = strengthInKnotsRoundedToFive % 10 >= 5;
float flipFactor = flip ? -1 : 1;
int barbLengthWithFlip = int(-barbLength * flipFactor);
int halfBarbLengthWithFlip = int(-halfBarbLength * flipFactor);

if (strengthInKnotsRoundedToFive <= 2) {
// https://www.weather.gov/hfo/windbarbinfo
// When wind speeds are 2 kts or less, a small open circle is used.
cairo_arc(cr, x, y, 6, 0, 2 * M_PI);
} else {

double dx1 = cos(direction) * (shaftLength);
double dy1 = sin(direction) * (shaftLength);

double wx1 = double(x) - dx1;
double wy1 = double(y) + dy1; // wind barb top (flag side)

// Draw small center circle
cairo_arc(cr, x, y, centerDiscRadius, 0, 2 * M_PI);

// Draw main shaft from center to end
cairo_move_to(cr, wx1, wy1);
cairo_line_to(cr, x - cos(direction) * (centerDiscRadius), y + sin(direction) * (centerDiscRadius));

// Draw flags
int nrPos = 10;
int pos = drawBarbTriangle(cr, x, y, nPennants, direction, shaftLength, barbLengthWithFlip, nrPos);

// Draw full Barb
if (nPennants > 0) pos++;
for (int i = 0; i < nBarbs; i++) {
double wx3 = wx1 + pos * dx1 / nrPos;
double wy3 = wy1 - pos * dy1 / nrPos;
double hx3 = wx3 - cos(M_PI / 2 - direction + (2 - float(flipFactor) * 0.1) * M_PI / 2) * barbLengthWithFlip; // was: +cos
double hy3 = wy3 - sin(M_PI / 2 - direction + (2 - float(flipFactor) * 0.1) * M_PI / 2) * barbLengthWithFlip; // was: -sin
cairo_move_to(cr, wx3, wy3);
cairo_line_to(cr, hx3, hy3);
pos++;
}

if ((nPennants + nBarbs) == 0) pos++;

// Draw half Barb
if (hasHalfBarb) {
double wx3 = wx1 + pos * dx1 / nrPos;
double wy3 = wy1 - pos * dy1 / nrPos;
double hx3 = wx3 - cos(M_PI / 2 - direction + (2 - float(flipFactor) * 0.1) * M_PI / 2) * halfBarbLengthWithFlip;
double hy3 = wy3 - sin(M_PI / 2 - direction + (2 - float(flipFactor) * 0.1) * M_PI / 2) * halfBarbLengthWithFlip;

cairo_move_to(cr, wx3, wy3);
cairo_line_to(cr, hx3, hy3);
pos++;
}
}
// No dash
cairo_set_dash(cr, 0, 0, 0);

if (drawOutline) {
cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, outlineColor.r / 255., outlineColor.g / 255., outlineColor.b / 255., .2);
cairo_set_line_width(cr, 5.5);
cairo_stroke_preserve(cr);

cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, outlineColor.r / 255., outlineColor.g / 255., outlineColor.b / 255., 1);
cairo_set_line_width(cr, 4.5);
cairo_stroke_preserve(cr);
}

// Stroke thin version
cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
cairo_set_source_rgba(cr, barbColor.r / 255., barbColor.g / 255., barbColor.b / 255., 1);
cairo_set_line_width(cr, lineWidth);
cairo_stroke(cr);

if (strengthInKnotsRoundedToFive > 2) {
drawBarbTriangle(cr, x, y, nPennants, direction, shaftLength, barbLengthWithFlip, 10);
cairo_close_path(cr);
cairo_set_source_rgba(cr, barbColor.r / 255., barbColor.g / 255., barbColor.b / 255., 1);
cairo_fill_preserve(cr);
}

// End end restore
cairo_close_path(cr);
cairo_restore(cr);
cairo_append_path(cr, cp);
cairo_path_destroy(cp);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);

CT::string text;
text.print("%d", strengthInKnots);
if (drawText) {
this->drawStrokedText(x - cos(direction + M_PI) * 15 - 5, y + sin(direction + M_PI) * 12 + 5, 0, text.c_str(), 12, 1 * drawOutline, outlineColor, barbColor);
}
}
4 changes: 4 additions & 0 deletions adagucserverEC/CCairoPlotter.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include FT_FREETYPE_H
#include <stdio.h>
#include <math.h>
#include "CColor.h"

#include "COctTreeColorQuantizer.h"

Expand Down Expand Up @@ -108,6 +109,7 @@ class CCairoPlotter {
void lineTo(float x1, float y1);
void lineTo(float x1, float y1, float width);
void endLine();
void endLine(const double *dashes, int num_dashes);
void line(float x1, float y1, float x2, float y2);
void line(float x1, float y1, float x2, float y2, float width);
void circle(int x, int y, int r);
Expand All @@ -117,12 +119,14 @@ class CCairoPlotter {
void poly(float x[], float y[], int n, bool closePath, bool fill);
void poly(float x[], float y[], int n, float lineWidth, bool closePath, bool fill);
void drawText(int x, int y, double angle, const char *text);
void drawStrokedText(int x, int y, double angle, const char *text, float fontSize, float strokeWidth, CColor bgcolor, CColor fgcolor);

void writeToPng8Stream(FILE *fp, unsigned char alpha, bool use8bitpalAlpha);
void writeToPng24Stream(FILE *fp, unsigned char alpha);
void writeToPng32Stream(FILE *fp, unsigned char alpha);
void writeToWebP32Stream(FILE *fp, unsigned char alpha, int quality);
void setToSurface(cairo_surface_t *png);
void drawBarb(int x, int y, double direction, double strength, CColor color, CColor outlineColor, bool drawOutline, float lineWidth, bool toKnots, bool flip, bool drawText);
};

#endif /* CCAIROPLOTTER_H_ */
Expand Down
21 changes: 12 additions & 9 deletions adagucserverEC/CColor.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* Project: ADAGUC Server
* Purpose: ADAGUC OGC Server
* Author: Maarten Plieger, plieger "at" knmi.nl
* Date: 2013-06-01
* Date: 2022-06-30
*
******************************************************************************
*
* Copyright 2013, Royal Netherlands Meteorological Institute (KNMI)
* Copyright 2022, Royal Netherlands Meteorological Institute (KNMI)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,10 +22,13 @@
* limitations under the License.
*
******************************************************************************/
#ifndef CColor_H
#define CColor_H
#include <stdlib.h>
#include <CServerConfig_CPPXSD.h>
#include <stdio.h>
#include <string.h>

#define CSERVER_HEXDIGIT_TO_DEC(DIGIT) (DIGIT > 96 ? DIGIT - 87 : DIGIT > 64 ? DIGIT - 55 : DIGIT - 48) // Converts "9" to 9, "A" to 10 and "a" to 10

#ifndef CCOLOR_H
#define CCOLOR_H
class CColor {
public:
unsigned char r, g, b, a;
Expand All @@ -42,10 +45,10 @@ class CColor {
this->a = a;
}
CColor(const char *color) { parse(color); }
/**
* color can have format #RRGGBB or #RRGGBBAA
*/
void parse(const char *color) {
/**
* color can have format #RRGGBB or #RRGGBBAA
*/
size_t l = strlen(color);

if (l == 7 && color[0] == '#') {
Expand Down
Loading