Implement GeoJson loader

This commit is contained in:
Markus Koch 2020-05-02 16:27:44 +02:00
parent f9e9726974
commit 25ccfc5df5
5 changed files with 320 additions and 27 deletions

119
src/geojson.c Normal file
View File

@ -0,0 +1,119 @@
#include "geojson.h"
#include "dijkstrasearch.h"
#include "logging.h"
#include <stdlib.h>
#include <glib-object.h>
#include <json-glib/json-glib.h>
int add_geojson_to_dijkstra(GList **nodes,
GList **paths,
char *filename)
{
JsonParser *parser;
JsonNode *root;
JsonArray *arr;
JsonNode *node;
JsonReader *reader;
GError *error;
int i, j;
int i_max, j_max;
char *name = NULL;
int x, y;
int x_last, y_last;
struct _stats {
int nodes;
int paths;
} stats = {.nodes = 0, .paths = 0};
report(LL_INFO, "Loading GeoJson data from %s...", filename);
parser = json_parser_new ();
error = NULL;
json_parser_load_from_file(parser, filename, &error);
if (error)
{
report(LL_ERROR, "Unable to parse `%s': %s\n", filename, error->message);
g_error_free(error);
g_object_unref(parser);
return EXIT_FAILURE;
}
root = json_parser_get_root(parser);
arr = json_node_get_array(root);
if (arr) {
i_max = json_array_get_length(arr);
for (i = 0; i < i_max; i++)
{
node = json_array_get_element(arr, i);
if (node) {
reader = json_reader_new(node);
json_reader_read_member(reader, "properties");
if (json_reader_get_error(reader)) {
g_object_unref(reader);
continue;
}
json_reader_read_member(reader, "name");
name = strdup(json_reader_get_string_value(reader));
json_reader_end_member(reader); // name
json_reader_end_member(reader); // properties
json_reader_read_member(reader, "geometry");
json_reader_read_member(reader, "coordinates");
if (json_reader_is_array(reader)) {
j_max = json_reader_count_elements(reader);
for (j = 0; j < j_max; j++) {
json_reader_read_element(reader, j);
if (json_reader_is_array(reader)) {
stats.nodes++;
json_reader_read_element(reader, 0);
x = json_reader_get_int_value(reader);
json_reader_end_element(reader);
json_reader_read_element(reader, 1);
y = json_reader_get_int_value(reader);
json_reader_end_element(reader);
if (j > 0) {
stats.paths++;
dijkstra_path_new_to_list(nodes, paths,
x_last, y_last,
x, y,
name, 1);
}
x_last = x;
y_last = y;
} else {
report(LL_WARNING, "err 1\n");
}
json_reader_end_element(reader);
}
} else {
report(LL_WARNING, "err 0\n");
}
json_reader_end_member(reader); // coordinates
json_reader_end_member(reader); // geometry
g_object_unref(reader);
} else {
report(LL_ERROR, "Invalid geojson file.\n");
}
}
} else {
report(LL_ERROR, "Invalid geojson file.\n");
}
report(LL_INFO, "Imported %d nodes and %d paths from GeoJson.",
stats.nodes,
stats.paths);
g_object_unref (parser);
return EXIT_SUCCESS;
}

10
src/geojson.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef GEOJSON_H
#define GEOJSON_H
#include <glib.h>
int add_geojson_to_dijkstra(GList **nodes,
GList **paths,
char *filename);
#endif // GEOJSON_H

60
src/logging.c Normal file
View File

@ -0,0 +1,60 @@
/* ----------------------------------------------------------------------------
* C-Report
* ----------------------------------------------------------------------------
* Author : Markus Koch <markus@notsyncing.net>
* Contributors : None
* License : Mozilla Public License (MPL) Version 2
* ----------------------------------------------------------------------------
*/
#include "logging.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
static enum log_level current_log_level = LL_INFO;
static const char *ll_string[] = {
"\x1B[31m\x1B[1m[X] ",
"\x1B[31m[E] ",
"\x1B[33m[W] ",
"\x1B[32m[I] ",
"\x1B[34m[D] ",
"\x1B[34m[d] ",
"[?] "
};
int should_report(enum log_level log_level)
{
return (log_level <= current_log_level);
}
enum log_level report(enum log_level log_level, const char *format, ...)
{
va_list vargs;
if (log_level > LL_COUNT)
log_level = LL_COUNT;
if (should_report(log_level)) {
va_start(vargs, format);
fprintf(stderr, "%s", ll_string[log_level]);
vfprintf(stderr, format, vargs);
fprintf(stderr, "\x1B[0m\n");
va_end(vargs);
}
return log_level;
}
void set_log_level(enum log_level log_level)
{
if (log_level >= LL_COUNT)
log_level = LL_COUNT - 1;
current_log_level = log_level;
}
enum log_level get_log_level()
{
return current_log_level;
}

28
src/logging.h Normal file
View File

@ -0,0 +1,28 @@
/* ----------------------------------------------------------------------------
* C-Report
* ----------------------------------------------------------------------------
* Author : Markus Koch <markus@notsyncing.net>
* Contributors : None
* License : Mozilla Public License (MPL) Version 2
* ----------------------------------------------------------------------------
*/
#ifndef LOGGING_H
#define LOGGING_H
#include <errno.h>
enum log_level {LL_CRITICAL = 0,
LL_ERROR,
LL_WARNING,
LL_INFO,
LL_DEBUG,
LL_NOISY,
LL_COUNT};
int should_report(enum log_level log_level);
enum log_level report(enum log_level log_level, const char *format, ...);
void set_log_level(enum log_level log_level);
enum log_level get_log_level();
#endif // LOGGING_H

View File

@ -1,10 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include "dijkstrasearch.h"
#include <glib/glist.h>
#include "geojson.h"
#include "logging.h"
int main()
void add_test_map(GList **nodes,
GList **paths)
{
dijkstra_path_new_to_list(nodes,
paths,
0,0,
0,10,
"Vertical",
1);
dijkstra_path_new_to_list(nodes,
paths,
0,5,
10,5,
"Horizontal",
1);
}
void help(const char *exec)
{
fprintf(stderr,
"Usage: %s [OPTION] [FILE]...\n"
"Start the lifo-dijkstraserv routing server.\n\n"
" -s\tset output to silent\n"
" -v\tincrease verbosity. Maybe used multiple times.\n"
" -p\tport number (default 6802)\n",
exec);
}
int main(int argc, char *argv[])
{
int opt;
int i;
GList *nodes = NULL;
GList *paths = NULL;
@ -12,36 +48,76 @@ int main()
struct dijkstra_node *node;
struct dijkstra_path *path;
dijkstra_path_new_to_list(&nodes,
&paths,
0,0,
0,10,
"Vertical",
1);
set_log_level(LL_INFO);
dijkstra_path_new_to_list(&nodes,
&paths,
0,5,
10,5,
"Horizontal",
1);
// Process arguments
while((opt = getopt(argc, argv, "vs")) != -1) {
switch(opt)
{
case 'v':
set_log_level(get_log_level() + 1);
break;
case 's':
set_log_level(0);
break;
case ':':
case '?':
help(argv[0]);
return 1;
default:
break;
}
}
if (optind == argc) {
help(argv[0]);
return 1;
}
/* Parse file list */
for (i = optind; i < argc; ++i) {
add_geojson_to_dijkstra(&nodes, &paths, argv[i]);
}
// add_test_map(&nodes, &paths);
if (should_report(LL_NOISY)) {
for (l = nodes; l != NULL; l = l->next) {
node = (struct dijkstra_node*) l->data;
printf("Node %p: %f,\t%f [%d paths]\n", node, node->position.x, node->position.y, g_list_length(node->paths));
}
printf("\n");
for (l = paths; l != NULL; l = l->next) {
path = (struct dijkstra_path*) l->data;
printf("Path %p: %p (%f,%f) -> %p (%f,%f) \t\"%s\"\n", path,
path->source, path->source->position.x, path->source->position.y,
path->destination, path->destination->position.x, path->destination->position.y,
path->name);
}
printf("\n");
}
report(LL_INFO, "Created graph with %d nodes and %d paths.",
g_list_length(nodes),
g_list_length(paths));
// Free memory
for (l = paths; l != NULL; l = l->next) {
path = (struct dijkstra_path*) l->data;
// TODO: free(path->name);
// Currently, we reuse the existing memory block when for the
// name when cloning streets. As such, clearing it here will
// cause a double free if the street has been split.
free(path);
}
g_list_free(paths);
for (l = nodes; l != NULL; l = l->next) {
node = (struct dijkstra_node*) l->data;
printf("Node %p: %f,\t%f [%d paths]\n", node, node->position.x, node->position.y, g_list_length(node->paths));
free(node);
}
printf("\n");
g_list_free(nodes);
for (l = paths; l != NULL; l = l->next) {
path = (struct dijkstra_path*) l->data;
printf("Path %p: %p (%f,%f) -> %p (%f,%f) \t\"%s\"\n", path,
path->source, path->source->position.x, path->source->position.y,
path->destination, path->destination->position.x, path->destination->position.y,
path->name);
}
printf("\nDone.\n");
// TODO: Free memory
return 0;
}