Selaa lähdekoodia

initial commit

Patrick Brosi 5 vuotta sitten
commit
debbe3c1b0
65 muutettua tiedostoa jossa 16527 lisäystä ja 0 poistoa
  1. 71 0
      CMakeLists.txt
  2. 151 0
      cmake/GetGitRevisionDescription.cmake
  3. 38 0
      cmake/GetGitRevisionDescription.cmake.in
  4. 12 0
      cmake/MacPlistMacros.cmake
  5. 133 0
      cmake/cpplint.cmake
  6. 6233 0
      cpplint.py
  7. 12 0
      src/CMakeLists.txt
  8. 19 0
      src/osmfixer/CMakeLists.txt
  9. 17 0
      src/osmfixer/FixerMain.cpp
  10. 13 0
      src/osmfixer/_config.h.in
  11. 12 0
      src/util/CMakeLists.txt
  12. 136 0
      src/util/Misc.h
  13. 116 0
      src/util/Nullable.h
  14. 231 0
      src/util/String.h
  15. BIN
      src/util/geo/.PolyLine.h.swp
  16. 54 0
      src/util/geo/BezierCurve.h
  17. 70 0
      src/util/geo/BezierCurve.tpp
  18. 91 0
      src/util/geo/Box.h
  19. 1544 0
      src/util/geo/Geo.h
  20. 32 0
      src/util/geo/GeoGraph.h
  21. 89 0
      src/util/geo/Grid.h
  22. 228 0
      src/util/geo/Grid.tpp
  23. 28 0
      src/util/geo/Line.h
  24. 50 0
      src/util/geo/Point.h
  25. 143 0
      src/util/geo/PolyLine.h
  26. 731 0
      src/util/geo/PolyLine.tpp
  27. 41 0
      src/util/geo/Polygon.h
  28. 35 0
      src/util/geo/output/GeoGraphJsonOutput.h
  29. 63 0
      src/util/geo/output/GeoGraphJsonOutput.tpp
  30. 34 0
      src/util/geo/output/GeoJsonOutput.cpp
  31. 40 0
      src/util/geo/output/GeoJsonOutput.h
  32. 48 0
      src/util/geo/output/GeoJsonOutput.tpp
  33. 33 0
      src/util/graph/Algorithm.h
  34. 32 0
      src/util/graph/Algorithm.tpp
  35. 7 0
      src/util/graph/Dijkstra.cpp
  36. 113 0
      src/util/graph/Dijkstra.h
  37. 175 0
      src/util/graph/Dijkstra.tpp
  38. 41 0
      src/util/graph/DirGraph.h
  39. 59 0
      src/util/graph/DirGraph.tpp
  40. 58 0
      src/util/graph/DirNode.h
  41. 153 0
      src/util/graph/DirNode.tpp
  42. 7 0
      src/util/graph/EDijkstra.cpp
  43. 139 0
      src/util/graph/EDijkstra.h
  44. 258 0
      src/util/graph/EDijkstra.tpp
  45. 41 0
      src/util/graph/Edge.h
  46. 41 0
      src/util/graph/Edge.tpp
  47. 48 0
      src/util/graph/Graph.h
  48. 76 0
      src/util/graph/Graph.tpp
  49. 47 0
      src/util/graph/Node.h
  50. 401 0
      src/util/graph/ShortestPath.h
  51. 1 0
      src/util/graph/ShortestPath.tpp
  52. 41 0
      src/util/graph/UndirGraph.h
  53. 59 0
      src/util/graph/UndirGraph.tpp
  54. 54 0
      src/util/graph/UndirNode.h
  55. 130 0
      src/util/graph/UndirNode.tpp
  56. 343 0
      src/util/http/Server.cpp
  57. 139 0
      src/util/http/Server.h
  58. 173 0
      src/util/json/Writer.cpp
  59. 108 0
      src/util/json/Writer.h
  60. 54 0
      src/util/log/Log.h
  61. 6 0
      src/util/tests/CMakeLists.txt
  62. 1456 0
      src/util/tests/TestMain.cpp
  63. 1446 0
      src/util/tests/lest.h
  64. 182 0
      src/util/xml/XmlWriter.cpp
  65. 91 0
      src/util/xml/XmlWriter.h

+ 71 - 0
CMakeLists.txt

@@ -0,0 +1,71 @@
1
+cmake_minimum_required (VERSION 2.8)
2
+
3
+project (osmfixer)
4
+
5
+if (CMAKE_BUILD_TYPE)
6
+	string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
7
+endif()
8
+if (CMAKE_BUILD_TYPE STREQUAL "DEBUG")
9
+	set(CPPLINT "${CMAKE_SOURCE_DIR}/cpplint.py")
10
+	include(cmake/cpplint.cmake)
11
+endif()
12
+
13
+set(CPPLINT_PROJECT_ROOT "src")
14
+
15
+enable_testing()
16
+
17
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
18
+set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/build")
19
+
20
+
21
+find_package(OpenMP)
22
+if (OPENMP_FOUND)
23
+	set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
24
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
25
+endif()
26
+
27
+
28
+# set compiler flags, see http://stackoverflow.com/questions/7724569/debug-vs-release-in-cmake
29
+if(OPENMP_FOUND)
30
+	set(CMAKE_CXX_FLAGS            "-fopenmp -Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wextra -Wno-implicit-fallthrough -pedantic")
31
+else()
32
+	message(WARNING "Configuring without OpenMP!")
33
+	set(CMAKE_CXX_FLAGS            "-Ofast -fno-signed-zeros -fno-trapping-math -Wall -Wno-format-extra-args -Wextra -Wformat-nonliteral -Wformat-security -Wformat=2 -Wextra -Wno-implicit-fallthrough -pedantic")
34
+endif()
35
+set(CMAKE_CXX_FLAGS_DEBUG          "-Og -g -DLOGLEVEL=3")
36
+set(CMAKE_CXX_FLAGS_MINSIZEREL     "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
37
+set(CMAKE_CXX_FLAGS_RELEASE        "${CMAKE_CXX_FLAGS} -DLOGLEVEL=2")
38
+set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -g -DLOGLEVEL=3")
39
+
40
+# export compile commands to tools like clang
41
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
42
+
43
+# Compiler-specific C++11 activation.
44
+if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
45
+	execute_process(
46
+		COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
47
+	if ((GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8))
48
+		set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
49
+	else ()
50
+		message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.8 or greater!")
51
+	endif ()
52
+elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
53
+	#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++11")
54
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
55
+else ()
56
+	message(FATAL_ERROR "Your C++ compiler does not support C++11.")
57
+endif ()
58
+
59
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
60
+
61
+# http://brianmilco.blogspot.de/2012/11/cmake-automatically-use-git-tags-as.html
62
+include(GetGitRevisionDescription)
63
+git_get_tag(VERSION_GIT)
64
+get_git_is_dirty(VERSION_GIT_IS_DIRTY)
65
+if ("${VERSION_GIT_IS_DIRTY}" STREQUAL "")
66
+	set(VERSION_GIT_FULL "${VERSION_GIT}")
67
+else()
68
+	set(VERSION_GIT_FULL "${VERSION_GIT}-${VERSION_GIT_IS_DIRTY}")
69
+endif()
70
+
71
+add_subdirectory(src)

+ 151 - 0
cmake/GetGitRevisionDescription.cmake

@@ -0,0 +1,151 @@
1
+# - Returns a version string from Git
2
+#
3
+# These functions force a re-configure on each git commit so that you can
4
+# trust the values of the variables in your build system.
5
+#
6
+#  get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
7
+#
8
+# Returns the refspec and sha hash of the current head revision
9
+#
10
+#  git_describe(<var> [<additional arguments to git describe> ...])
11
+#
12
+# Returns the results of git describe on the source tree, and adjusting
13
+# the output so that it tests false if an error occurs.
14
+#
15
+#  git_get_exact_tag(<var> [<additional arguments to git describe> ...])
16
+#
17
+# Returns the results of git describe --exact-match on the source tree,
18
+# and adjusting the output so that it tests false if there was no exact
19
+# matching tag.
20
+#
21
+# Requires CMake 2.6 or newer (uses the 'function' command)
22
+#
23
+# Original Author:
24
+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
25
+# http://academic.cleardefinition.com
26
+# Iowa State University HCI Graduate Program/VRAC
27
+#
28
+# Copyright Iowa State University 2009-2010.
29
+# Distributed under the Boost Software License, Version 1.0.
30
+# (See accompanying file LICENSE_1_0.txt or copy at
31
+# http://www.boost.org/LICENSE_1_0.txt)
32
+
33
+if(__get_git_revision_description)
34
+	return()
35
+endif()
36
+set(__get_git_revision_description YES)
37
+
38
+# We must run the following at "include" time, not at function call time,
39
+# to find the path to this module rather than the path to a calling list file
40
+get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
41
+
42
+function(get_git_head_revision _refspecvar _hashvar)
43
+	set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}")
44
+	set(GIT_DIR "${GIT_PARENT_DIR}/.git")
45
+	while(NOT EXISTS "${GIT_DIR}")	# .git dir not found, search parent directories
46
+		set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
47
+		get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
48
+		if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
49
+			# We have reached the root directory, we are not in git
50
+			set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
51
+			set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
52
+			return()
53
+		endif()
54
+		set(GIT_DIR "${GIT_PARENT_DIR}/.git")
55
+	endwhile()
56
+	set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
57
+	if(NOT EXISTS "${GIT_DATA}")
58
+		file(MAKE_DIRECTORY "${GIT_DATA}")
59
+	endif()
60
+
61
+	if(NOT EXISTS "${GIT_DIR}/HEAD")
62
+		return()
63
+	endif()
64
+	set(HEAD_FILE "${GIT_DATA}/HEAD")
65
+	configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
66
+
67
+	configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
68
+		"${GIT_DATA}/grabRef.cmake"
69
+		@ONLY)
70
+	include("${GIT_DATA}/grabRef.cmake")
71
+
72
+	set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
73
+	set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
74
+endfunction()
75
+
76
+function(get_git_is_dirty _var)
77
+	if(NOT GIT_FOUND)
78
+		find_package(Git QUIET)
79
+	endif()
80
+
81
+	execute_process(COMMAND
82
+		"${GIT_EXECUTABLE}"
83
+        diff-index --name-only HEAD --
84
+		WORKING_DIRECTORY
85
+		"${CMAKE_SOURCE_DIR}"
86
+		RESULT_VARIABLE
87
+		res
88
+		OUTPUT_VARIABLE
89
+		out
90
+		ERROR_QUIET
91
+		OUTPUT_STRIP_TRAILING_WHITESPACE)
92
+	if(NOT res EQUAL 0)
93
+		set(out "${out}-${res}-NOTFOUND")
94
+	endif()
95
+
96
+    if (NOT "${out}" STREQUAL "")
97
+        set(IS_DIRTY "dirty")
98
+    else()
99
+        set(IS_DIRTY "")
100
+    endif()
101
+	set(${_var} "${IS_DIRTY}" PARENT_SCOPE)
102
+endfunction()
103
+
104
+function(git_describe _var)
105
+	if(NOT GIT_FOUND)
106
+		find_package(Git QUIET)
107
+	endif()
108
+	get_git_head_revision(refspec hash)
109
+	if(NOT GIT_FOUND)
110
+		set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
111
+		return()
112
+	endif()
113
+	if(NOT hash)
114
+		set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
115
+		return()
116
+	endif()
117
+
118
+	# TODO sanitize
119
+	#if((${ARGN}" MATCHES "&&") OR
120
+	#	(ARGN MATCHES "||") OR
121
+	#	(ARGN MATCHES "\\;"))
122
+	#	message("Please report the following error to the project!")
123
+	#	message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
124
+	#endif()
125
+
126
+	#message(STATUS "Arguments to execute_process: ${ARGN}")
127
+
128
+	execute_process(COMMAND
129
+		"${GIT_EXECUTABLE}"
130
+		describe
131
+		${hash}
132
+		${ARGN}
133
+		WORKING_DIRECTORY
134
+		"${CMAKE_SOURCE_DIR}"
135
+		RESULT_VARIABLE
136
+		res
137
+		OUTPUT_VARIABLE
138
+		out
139
+		ERROR_QUIET
140
+		OUTPUT_STRIP_TRAILING_WHITESPACE)
141
+	if(NOT res EQUAL 0)
142
+		set(out "${out}-${res}-NOTFOUND")
143
+	endif()
144
+
145
+	set(${_var} "${out}" PARENT_SCOPE)
146
+endfunction()
147
+
148
+function(git_get_tag _var)
149
+	git_describe(out --tags ${ARGN})
150
+	set(${_var} "${out}" PARENT_SCOPE)
151
+endfunction()

+ 38 - 0
cmake/GetGitRevisionDescription.cmake.in

@@ -0,0 +1,38 @@
1
+# 
2
+# Internal file for GetGitRevisionDescription.cmake
3
+#
4
+# Requires CMake 2.6 or newer (uses the 'function' command)
5
+#
6
+# Original Author:
7
+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
8
+# http://academic.cleardefinition.com
9
+# Iowa State University HCI Graduate Program/VRAC
10
+#
11
+# Copyright Iowa State University 2009-2010.
12
+# Distributed under the Boost Software License, Version 1.0.
13
+# (See accompanying file LICENSE_1_0.txt or copy at
14
+# http://www.boost.org/LICENSE_1_0.txt)
15
+
16
+set(HEAD_HASH)
17
+
18
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
19
+
20
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
21
+if(HEAD_CONTENTS MATCHES "ref")
22
+	# named branch
23
+	string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
24
+	if(EXISTS "@GIT_DIR@/${HEAD_REF}")
25
+		configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
26
+	elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
27
+		configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
28
+		set(HEAD_HASH "${HEAD_REF}")
29
+	endif()
30
+else()
31
+	# detached HEAD
32
+	configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
33
+endif()
34
+
35
+if(NOT HEAD_HASH)
36
+	file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
37
+	string(STRIP "${HEAD_HASH}" HEAD_HASH)
38
+endif()

+ 12 - 0
cmake/MacPlistMacros.cmake

@@ -0,0 +1,12 @@
1
+# Mac Plist Macros
2
+
3
+FUNCTION (GET_VERSION_PLIST PLISTFILE OUTVAR)
4
+	SET (PVERSION "")
5
+	IF (EXISTS ${PLISTFILE})
6
+		FILE (READ "${PLISTFILE}" info_plist)
7
+		STRING (REGEX REPLACE "\n" "" info_plist "${info_plist}")
8
+		STRING (REGEX MATCH "<key>CFBundleShortVersionString</key>[ \t]*<string>([0-9\\.]*)</string>" PLISTVERSION "${info_plist}")
9
+		STRING (REGEX REPLACE "<key>CFBundleShortVersionString</key>[ \t]*<string>([0-9\\.]*)</string>" "\\1" PVERSION "${PLISTVERSION}")
10
+	ENDIF (EXISTS ${PLISTFILE})
11
+	SET (${OUTVAR} ${PVERSION} PARENT_SCOPE)
12
+ENDFUNCTION (GET_VERSION_PLIST)

+ 133 - 0
cmake/cpplint.cmake

@@ -0,0 +1,133 @@
1
+#
2
+# CMake module to C++ static analysis against 
3
+# Google C++ Style Guide (https://google.github.io/styleguide/cppguide.html)
4
+#
5
+# For more detials please follow links:
6
+#
7
+# - https://github.com/google/styleguide
8
+# - https://pypi.python.org/pypi/cpplint
9
+# - https://github.com/theandrewdavis/cpplint
10
+#
11
+# Copyright (c) 2016 Piotr L. Figlarek
12
+# 
13
+# Usage
14
+# -----
15
+# Include this module via CMake include(...) command and then add each source directory 
16
+# via introduced by this module cpplint_add_subdirectory(...) function. Added directory 
17
+# will be recursivelly scanned and all available files will be checked. 
18
+#
19
+# Example
20
+# -------
21
+# # include CMake module
22
+# include(cmake/cpplint.cmake)
23
+#
24
+# # add all source code directories
25
+# cpplint_add_subdirectory(core)
26
+# cpplint_add_subdirectory(modules/c-bind)
27
+#
28
+# License (MIT)
29
+# -------------
30
+# Permission is hereby granted, free of charge, to any person obtaining a copy
31
+# of this software and associated documentation files (the "Software"), to deal
32
+# in the Software without restriction, including without limitation the rights
33
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34
+# copies of the Software, and to permit persons to whom the Software is
35
+# furnished to do so, subject to the following conditions:
36
+#
37
+# The above copyright notice and this permission notice shall be included in all
38
+# copies or substantial portions of the Software.
39
+#
40
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
46
+# SOFTWARE.
47
+
48
+
49
+# select files extensions to check
50
+option(CPPLINT_TEST_C_FILES     "Check *.c files"     ON)
51
+option(CPPLINT_TEST_H_FILES     "Check *.h files"     ON)
52
+option(CPPLINT_TEST_CPP_FILES   "Check *.cpp files"   ON)
53
+option(CPPLINT_TEST_HPP_FILES   "Check *.hpp files"   ON)
54
+option(CPPLINT_TEST_TPP_FILES   "Check *.tpp files"   ON)
55
+
56
+# target to run cpplint.py for all configured sources
57
+set(CPPLINT_TARGET lint CACHE STRING "Name of C++ style checker target") 
58
+
59
+# project root directory
60
+set(CPPLINT_PROJECT_ROOT "${PROJECT_SOURCE_DIR}" CACHE STRING "Project ROOT directory")
61
+
62
+
63
+# find cpplint.py script
64
+if(CPPLINT)
65
+    message(STATUS "cpplint parser: ${CPPLINT}")
66
+else()
67
+    message(FATAL_ERROR "cpplint script: NOT FOUND! "
68
+		"Please set the CPPLINT variable.")
69
+endif()
70
+
71
+
72
+# common target to concatenate all cpplint.py targets
73
+add_custom_target(${CPPLINT_TARGET} ALL)
74
+
75
+
76
+# use cpplint.py to check source code files inside DIR directory
77
+function(cpplint_add_subdirectory DIR)
78
+    # create relative path to the directory
79
+    set(ABSOLUTE_DIR ${CMAKE_CURRENT_LIST_DIR}/${DIR})
80
+
81
+    # add *.c files
82
+    if(CPPLINT_TEST_C_FILES)
83
+        set(EXTENSIONS       ${EXTENSIONS}c,)
84
+        set(FILES_TO_CHECK   ${FILES_TO_CHECK} ${ABSOLUTE_DIR}/*.c)
85
+    endif()
86
+
87
+    # add *.h files
88
+    if(CPPLINT_TEST_H_FILES)
89
+        set(EXTENSIONS       ${EXTENSIONS}h,)
90
+        set(FILES_TO_CHECK   ${FILES_TO_CHECK} ${ABSOLUTE_DIR}/*.h)
91
+    endif()
92
+
93
+    # add *.cpp files
94
+    if(CPPLINT_TEST_CPP_FILES)
95
+        set(EXTENSIONS       ${EXTENSIONS}cpp,)
96
+        set(FILES_TO_CHECK   ${FILES_TO_CHECK} ${ABSOLUTE_DIR}/*.cpp)
97
+    endif()
98
+
99
+    # add *.hpp files
100
+    if(CPPLINT_TEST_HPP_FILES)
101
+        set(EXTENSIONS       ${EXTENSIONS}hpp,)
102
+        set(FILES_TO_CHECK   ${FILES_TO_CHECK} ${ABSOLUTE_DIR}/*.hpp)
103
+    endif()
104
+
105
+    # add *.tpp files
106
+    if(CPPLINT_TEST_TPP_FILES)
107
+        set(EXTENSIONS       ${EXTENSIONS}tpp,)
108
+        set(FILES_TO_CHECK   ${FILES_TO_CHECK} ${ABSOLUTE_DIR}/*.tpp)
109
+    endif()
110
+
111
+    # find all source files inside project
112
+    file(GLOB_RECURSE LIST_OF_FILES ${FILES_TO_CHECK})
113
+
114
+    # create valid target name for this check
115
+    string(REGEX REPLACE "/" "." TEST_NAME ${DIR})
116
+    set(TARGET_NAME ${CPPLINT_TARGET}.${TEST_NAME})
117
+
118
+    # perform cpplint check
119
+    add_custom_target(${TARGET_NAME}
120
+        COMMAND ${CPPLINT} "--extensions=${EXTENSIONS}"
121
+                           "--root=${CPPLINT_PROJECT_ROOT}"
122
+						   "--quiet"
123
+                           ${LIST_OF_FILES}
124
+        DEPENDS ${LIST_OF_FILES}
125
+        COMMENT "cpplint: Checking source code style"
126
+    )
127
+
128
+    # run this target when root cpplint.py test is triggered
129
+    add_dependencies(${CPPLINT_TARGET} ${TARGET_NAME})
130
+
131
+    # add this test to CTest
132
+    add_test(${TARGET_NAME} ${CMAKE_MAKE_PROGRAM} ${TARGET_NAME})
133
+endfunction()

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 6233 - 0
cpplint.py


+ 12 - 0
src/CMakeLists.txt

@@ -0,0 +1,12 @@
1
+set(OSMFIXER_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_BINARY_DIR})
2
+
3
+if (COMMAND cpplint_add_subdirectory)
4
+	cpplint_add_subdirectory(osmfixer)
5
+endif()
6
+
7
+include_directories(
8
+	${OSMFIXER_INCLUDE_DIR}
9
+)
10
+
11
+add_subdirectory(util)
12
+add_subdirectory(osmfixer)

+ 19 - 0
src/osmfixer/CMakeLists.txt

@@ -0,0 +1,19 @@
1
+file(GLOB_RECURSE osmfixer_SRC *.cpp)
2
+
3
+set(osmfixer_main FixerMain.cpp)
4
+
5
+list(REMOVE_ITEM osmfixer_SRC ${osmfixer_main})
6
+
7
+include_directories(
8
+	${OSMFIXER_INCLUDE_DIR}
9
+)
10
+
11
+configure_file (
12
+  "_config.h.in"
13
+  "_config.h"
14
+)
15
+
16
+add_executable(osmfixer ${osmfixer_main})
17
+add_library(osmfixer_dep ${osmfixer_SRC})
18
+
19
+target_link_libraries(osmfixer osmfixer_dep util ${Boost_LIBRARIES} -lpthread)

+ 17 - 0
src/osmfixer/FixerMain.cpp

@@ -0,0 +1,17 @@
1
+// Copyright 2019, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include <iostream>
6
+
7
+// _____________________________________________________________________________
8
+int main(int argc, char** argv) {
9
+  // disable output buffering for standard output
10
+  setbuf(stdout, NULL);
11
+
12
+  // initialize randomness
13
+  srand(time(NULL) + rand());  // NOLINT
14
+
15
+
16
+  std::cout << "Hello." << std::endl;
17
+}

+ 13 - 0
src/osmfixer/_config.h.in

@@ -0,0 +1,13 @@
1
+// Copyright 2017
2
+// Author: Patrick Brosi
3
+
4
+#ifndef SRC_PFAEDLE_CONFIG_H_
5
+#define SRC_PFAEDLE_CONFIG_H_
6
+
7
+// version number from cmake version module
8
+#define VERSION_FULL "@VERSION_GIT_FULL@"
9
+
10
+// version number from cmake version module
11
+#define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
12
+
13
+#endif  // SRC_PFAEDLE_CONFIG_H_N

+ 12 - 0
src/util/CMakeLists.txt

@@ -0,0 +1,12 @@
1
+file(GLOB_RECURSE util_SRC *.cpp)
2
+list(REMOVE_ITEM util_SRC TestMain.cpp)
3
+add_library(util ${util_SRC})
4
+
5
+find_package( ZLIB )
6
+if (ZLIB_FOUND)
7
+	include_directories( ${ZLIB_INCLUDE_DIRS} )
8
+	target_link_libraries( util ${ZLIB_LIBRARIES} )
9
+	add_definitions( -DZLIB_FOUND=${ZLIB_FOUND} )
10
+endif( ZLIB_FOUND )
11
+
12
+add_subdirectory(tests)

+ 136 - 0
src/util/Misc.h

@@ -0,0 +1,136 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_MISC_H_
6
+#define UTIL_MISC_H_
7
+
8
+#include <cmath>
9
+#include <cstring>
10
+#include <chrono>
11
+#include <sstream>
12
+#include <unistd.h>
13
+#include <sys/types.h>
14
+#include <pwd.h>
15
+
16
+#define UNUSED(expr) do { (void)(expr); } while (0)
17
+#define TIME() std::chrono::high_resolution_clock::now()
18
+#define TOOK(t1, t2) (std::chrono::duration_cast<microseconds>(t2 - t1).count() / 1000.0)
19
+#define T_START(n)  auto _tstart_##n = std::chrono::high_resolution_clock::now()
20
+#define T_STOP(n) (std::chrono::duration_cast<microseconds>(std::chrono::high_resolution_clock::now() - _tstart_##n).count() / 1000.0)
21
+
22
+namespace util {
23
+
24
+// cached first 10 powers of 10
25
+static int pow10[10] = {
26
+    1,           10,          100,           1000,          10000,
27
+    100000,      1000000,     10000000,      100000000,     1000000000};
28
+
29
+// _____________________________________________________________________________
30
+inline uint64_t factorial(uint64_t n) {
31
+  if (n == 1) return n;
32
+  return n * factorial(n - 1);
33
+}
34
+
35
+// _____________________________________________________________________________
36
+inline uint64_t atoul(const char* p) {
37
+  uint64_t ret = 0;
38
+
39
+  while (*p) {
40
+    ret = ret * 10 + (*p++ - '0');
41
+  }
42
+
43
+  return ret;
44
+}
45
+
46
+// _____________________________________________________________________________
47
+inline bool isFloatingPoint(const std::string& str) {
48
+  std::stringstream ss(str);
49
+  double f;
50
+  ss >> std::noskipws >> f;
51
+  return ss.eof() && ! ss.fail();
52
+}
53
+
54
+// _____________________________________________________________________________
55
+inline double atof(const char* p, uint8_t mn) {
56
+  // this atof implementation works only on "normal" float strings like
57
+  // 56.445 or -345.00, but should be faster than std::atof
58
+  double ret = 0.0;
59
+  bool neg = false;
60
+  if (*p == '-') {
61
+    neg = true;
62
+    p++;
63
+  }
64
+
65
+  while (*p >= '0' && *p <= '9') {
66
+    ret = ret * 10.0 + (*p - '0');
67
+    p++;
68
+  }
69
+
70
+  if (*p == '.') {
71
+    p++;
72
+    double f = 0;
73
+    uint8_t n = 0;
74
+
75
+    for (; n < mn && *p >= '0' && *p <= '9'; n++, p++) {
76
+      f = f * 10.0 + (*p - '0');
77
+    }
78
+
79
+    if (n < 10)
80
+      ret += f / pow10[n];
81
+    else
82
+      ret += f / std::pow(10, n);
83
+  }
84
+
85
+  if (neg) return -ret;
86
+  return ret;
87
+}
88
+
89
+// _____________________________________________________________________________
90
+inline double atof(const char* p) { return atof(p, 38); }
91
+
92
+// _____________________________________________________________________________
93
+inline std::string getHomeDir() {
94
+  // parse implicit paths
95
+  const char* homedir = 0;
96
+  char* buf = 0;
97
+
98
+  if ((homedir = getenv("HOME")) == 0) {
99
+    homedir = "";
100
+    struct passwd pwd;
101
+    struct passwd* result;
102
+    size_t bufsize;
103
+    bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
104
+    if (bufsize == static_cast<size_t>(-1)) bufsize = 0x4000;
105
+    buf = static_cast<char*>(malloc(bufsize));
106
+    if (buf != 0) {
107
+      getpwuid_r(getuid(), &pwd, buf, bufsize, &result);
108
+      if (result != NULL) homedir = result->pw_dir;
109
+    }
110
+  }
111
+
112
+  std::string ret(homedir);
113
+  if (buf) free(buf);
114
+
115
+  return ret;
116
+}
117
+
118
+// _____________________________________________________________________________
119
+inline std::string getTmpDir() {
120
+  // first, check if an env variable is set
121
+  const char* tmpdir = getenv("TMPDIR");
122
+  if (tmpdir && std::strlen(tmpdir)) return std::string(tmpdir);
123
+
124
+  // second, check if /tmp is writable
125
+  if (access("/tmp/", W_OK) == 0) return "/tmp";
126
+
127
+  // third, check if the cwd is writable
128
+  if (access(".", W_OK) == 0)  return ".";
129
+
130
+  // lastly, return the users home directory as a fallback
131
+  return getHomeDir();
132
+}
133
+
134
+}  // namespace util
135
+
136
+#endif  // UTIL_MISC_H_

+ 116 - 0
src/util/Nullable.h

@@ -0,0 +1,116 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include <stdexcept>
6
+
7
+#ifndef UTIL_NULLABLE_H_
8
+#define UTIL_NULLABLE_H_
9
+
10
+namespace util {
11
+
12
+template<typename T>
13
+class Nullable {
14
+ public:
15
+  Nullable()
16
+   : val(), null(true) {}
17
+  Nullable(T* valPointer)
18
+   : val(), null(true) {
19
+   if (valPointer) {
20
+     assign(*valPointer);
21
+   }
22
+  }
23
+  Nullable(const T& value)
24
+   : val(value), null(false) {}
25
+  Nullable(const Nullable& other)
26
+   : val(other.val), null(other.isNull()) {}
27
+
28
+  Nullable& operator=(const Nullable& other) {
29
+    if (!other.isNull()) val = other.get();
30
+    null = other.isNull();
31
+    return *this;
32
+  }
33
+
34
+  T operator=(const T& other) {
35
+    assign(other);
36
+    return val;
37
+  }
38
+
39
+  /**
40
+   * Passing through comparision operators
41
+   */
42
+
43
+  bool operator==(const Nullable& other) const {
44
+    return (other.isNull() && isNull()) || other.get() == get();
45
+  }
46
+
47
+  bool operator!=(const Nullable& other) const {
48
+    return !(*this == other);
49
+  }
50
+
51
+  bool operator<(const Nullable& other) const {
52
+    return !other.isNull() && !isNull() && get() < other.get();
53
+  }
54
+
55
+  bool operator>(const Nullable& other) const {
56
+    return !(*this < other || *this == other);
57
+  }
58
+
59
+  bool operator<=(const Nullable& other) const {
60
+    return *this < other || *this == other;
61
+  }
62
+
63
+  bool operator>=(const Nullable& other) const {
64
+    return *this > other || *this == other;
65
+  }
66
+
67
+  bool operator==(const T& other) const {
68
+    return !isNull() && other == get();
69
+  }
70
+
71
+  bool operator!=(const T& other) const {
72
+    return !(*this == other);
73
+  }
74
+
75
+  bool operator<(const T& other) const {
76
+    return !isNull() && get() < other;
77
+  }
78
+
79
+  bool operator>(const T& other) const {
80
+    return !(*this < other || *this == other);
81
+  }
82
+
83
+  bool operator<=(const T& other) const {
84
+    return *this < other || *this == other;
85
+  }
86
+
87
+  bool operator>=(const T& other) const {
88
+    return *this > other || *this == other;
89
+  }
90
+
91
+  operator T() const {
92
+    return get();
93
+  }
94
+
95
+  bool isNull() const {
96
+    return null;
97
+  }
98
+
99
+  T get() const {
100
+    if (!isNull()) return val;
101
+    else throw std::runtime_error("Trying to retrieve value of NULL object.");
102
+  }
103
+
104
+private:
105
+  void assign(T v) {
106
+    val = v;
107
+    null = false;
108
+  }
109
+
110
+  T val;
111
+  bool null;
112
+};
113
+
114
+}
115
+
116
+#endif  // UTIL_NULLABLE_H_

+ 231 - 0
src/util/String.h

@@ -0,0 +1,231 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_STRING_H_
6
+#define UTIL_STRING_H_
7
+
8
+#include <algorithm>
9
+#include <cstring>
10
+#include <sstream>
11
+#include <string>
12
+#include <vector>
13
+
14
+namespace util {
15
+
16
+// _____________________________________________________________________________
17
+inline std::string urlDecode(const std::string& encoded) {
18
+  std::string decoded;
19
+  for (size_t i = 0; i < encoded.size(); ++i) {
20
+    char c = encoded[i];
21
+    if (c == '%') {
22
+      std::string ah = encoded.substr(i + 1, 2);
23
+      char* nonProced = 0;
24
+      char hexVal = strtol(ah.c_str(), &nonProced, 16);
25
+
26
+      if (ah.find_first_of("+-") > 1 && ah.size() - strlen(nonProced) == 2) {
27
+        c = hexVal;
28
+        i += 2;
29
+      }
30
+    } else if (c == '+') {
31
+      c = ' ';
32
+    }
33
+    decoded += c;
34
+  }
35
+  return decoded;
36
+}
37
+
38
+// _____________________________________________________________________________
39
+inline std::string jsonStringEscape(const std::string& unescaped) {
40
+  std::string escaped;
41
+  for (size_t i = 0; i < unescaped.size(); ++i) {
42
+    if (unescaped[i] == '"' || unescaped[i] == '\\') {
43
+      escaped += "\\";
44
+    }
45
+    if (iscntrl(unescaped[i])) {
46
+      escaped += " ";
47
+    }
48
+    escaped += unescaped[i];
49
+  }
50
+  return escaped;
51
+}
52
+
53
+// _____________________________________________________________________________
54
+inline bool replace(std::string& subj, const std::string& from,
55
+                    const std::string& to) {
56
+  if (from.empty()) return false;
57
+  size_t start_pos = subj.find(from);
58
+  if (start_pos != std::string::npos) {
59
+    subj.replace(start_pos, from.length(), to);
60
+    return true;
61
+  }
62
+
63
+  return false;
64
+}
65
+
66
+// _____________________________________________________________________________
67
+inline bool replaceAll(std::string& subj, const std::string& from,
68
+                       const std::string& to) {
69
+  if (from.empty()) return false;
70
+  bool found = false;
71
+  size_t s = subj.find(from, 0);
72
+  for (; s != std::string::npos; s = subj.find(from, s + to.length())) {
73
+    found = true;
74
+    subj.replace(s, from.length(), to);
75
+  }
76
+
77
+  return found;
78
+}
79
+
80
+// _____________________________________________________________________________
81
+inline std::string unixBasename(const std::string& pathname) {
82
+  return {std::find_if(pathname.rbegin(), pathname.rend(),
83
+                       [](char c) { return c == '/'; })
84
+              .base(),
85
+          pathname.end()};
86
+}
87
+
88
+// _____________________________________________________________________________
89
+template <typename T>
90
+inline std::string toString(T obj) {
91
+  std::stringstream ss;
92
+  ss << obj;
93
+  return ss.str();
94
+}
95
+
96
+// _____________________________________________________________________________
97
+inline std::vector<std::string> split(std::string in, char sep) {
98
+  std::stringstream ss(in);
99
+  std::vector<std::string> ret(1);
100
+  while (std::getline(ss, ret.back(), sep)) {
101
+    ret.push_back("");
102
+  }
103
+  ret.pop_back();
104
+  return ret;
105
+}
106
+
107
+// _____________________________________________________________________________
108
+inline std::string ltrim(std::string str) {
109
+  str.erase(0, str.find_first_not_of(" \t\n\v\f\r"));
110
+  return str;
111
+}
112
+
113
+// _____________________________________________________________________________
114
+inline std::string rtrim(std::string str) {
115
+  str.erase(str.find_last_not_of(" \t\n\v\f\r") + 1);
116
+  return str;
117
+}
118
+
119
+// _____________________________________________________________________________
120
+inline std::string trim(std::string str) { return ltrim(rtrim(str)); }
121
+
122
+// _____________________________________________________________________________
123
+inline size_t editDist(const std::string& s1, const std::string& s2) {
124
+  // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++
125
+  size_t len1 = s1.size();
126
+  size_t len2 = s2.size();
127
+  std::vector<size_t> cur(len2 + 1);
128
+  std::vector<size_t> prev(len2 + 1);
129
+
130
+  for (size_t i = 0; i < prev.size(); i++) prev[i] = i;
131
+
132
+  for (size_t i = 0; i < len1; i++) {
133
+    cur[0] = i + 1;
134
+    for (size_t j = 0; j < len2; j++) {
135
+      cur[j + 1] =
136
+          std::min(prev[1 + j] + 1,
137
+                   std::min(cur[j] + 1, prev[j] + (s1[i] == s2[j] ? 0 : 1)));
138
+    }
139
+    std::swap(cur, prev);
140
+  }
141
+
142
+  return prev[len2];
143
+}
144
+
145
+// _____________________________________________________________________________
146
+inline size_t prefixEditDist(const std::string& prefix, const std::string& s,
147
+                             size_t deltaMax) {
148
+  // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++
149
+  size_t len1 = prefix.size();
150
+  size_t len2 = std::min(s.size(), prefix.size() + deltaMax + 1);
151
+  std::vector<size_t> d((len1 + 1) * (len2 + 1));
152
+
153
+  d[0] = 0;
154
+  for (size_t i = 1; i <= len1; ++i) d[i * (len2 + 1)] = i;
155
+  for (size_t i = 1; i <= len2; ++i) d[ i] = i;
156
+
157
+  for (size_t i = 1; i <= len1; i++) {
158
+    for (size_t j = 1; j <= len2; j++) {
159
+      d[i * (len2 + 1) + j] = std::min(std::min(d[(i - 1) * (len2 + 1) + j] + 1, d[i * (len2 + 1) + j - 1] + 1),
160
+                         d[(i - 1) * (len2 + 1) + j - 1] + (prefix[i - 1] == s[j - 1] ? 0 : 1));
161
+    }
162
+  }
163
+
164
+  // take min of last row
165
+  size_t deltaMin = std::max(std::max(deltaMax + 1, prefix.size()), s.size());
166
+  for (size_t i = 0; i <= len2; i++) {
167
+    if (d[len1 * (len2 + 1) + i] < deltaMin) deltaMin = d[len1 * (len2 + 1) + i];
168
+  }
169
+
170
+  return deltaMin;
171
+}
172
+
173
+// _____________________________________________________________________________
174
+inline size_t prefixEditDist(const std::string& prefix, const std::string& s) {
175
+  return prefixEditDist(prefix, s, s.size());
176
+}
177
+
178
+// _____________________________________________________________________________
179
+inline std::string toUpper(std::string str) {
180
+  std::transform(str.begin(), str.end(),str.begin(), toupper);
181
+  return str;
182
+}
183
+
184
+// _____________________________________________________________________________
185
+inline std::string toLower(std::string str) {
186
+  std::transform(str.begin(), str.end(),str.begin(), tolower);
187
+  return str;
188
+}
189
+
190
+// _____________________________________________________________________________
191
+template <class Iter>
192
+inline std::string implode(Iter begin, const Iter& end, const char* del) {
193
+  std::stringstream ss;
194
+  size_t i = 0;
195
+  while (begin != end) {
196
+    if (i != 0) ss << del;
197
+    ss << *begin;
198
+    begin++;
199
+    i++;
200
+  }
201
+
202
+  return ss.str();
203
+}
204
+
205
+// _____________________________________________________________________________
206
+inline std::string normalizeWhiteSpace(const std::string& input) {
207
+  std::string ret;
208
+  bool ws = false;
209
+  for (size_t i = 0; i < input.size(); i++) {
210
+    if (std::isspace(input[i])) {
211
+      if (!ws) {
212
+        ret += " ";
213
+        ws = true;
214
+      }
215
+      continue;
216
+    } else {
217
+      ws = false;
218
+      ret += input[i];
219
+    }
220
+  }
221
+  return ret;
222
+}
223
+
224
+// _____________________________________________________________________________
225
+template <typename T>
226
+inline std::string implode(const std::vector<T>& vec, const char* del) {
227
+  return implode(vec.begin(), vec.end(), del);
228
+}
229
+}
230
+
231
+#endif  // UTIL_STRING_H_

BIN
src/util/geo/.PolyLine.h.swp


+ 54 - 0
src/util/geo/BezierCurve.h

@@ -0,0 +1,54 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_BEZIERCURVE_H_
6
+#define UTIL_GEO_BEZIERCURVE_H_
7
+
8
+#include <vector>
9
+#include "util/geo/Geo.h"
10
+#include "util/geo/PolyLine.h"
11
+
12
+namespace util {
13
+namespace geo {
14
+
15
+struct CubicPolynom {
16
+  CubicPolynom(double a, double b, double c, double d, double x)
17
+      : a(a), b(b), c(c), d(d), x(x) {}
18
+  CubicPolynom() : a(0), b(0), c(0), d(0), x(0) {}
19
+  double a, b, c, d, x;
20
+
21
+  double valueAt(double x) const;
22
+};
23
+
24
+/**
25
+ * Bezier curve
26
+ */
27
+template <typename T>
28
+class BezierCurve {
29
+ public:
30
+  BezierCurve(const Point<T>& a, const Point<T>& b, const Point<T>& c, const Point<T>& d);
31
+
32
+  const PolyLine<T>& render(double d);
33
+
34
+ private:
35
+  double _d;
36
+
37
+  // the x and y polynoms for this spline
38
+  CubicPolynom _xp, _yp;
39
+
40
+  // store the rendered polyline for quicker access
41
+  PolyLine<T> _rendered;
42
+  bool _didRender;
43
+
44
+  void recalcPolynoms(const Point<T>& x, const Point<T>& b, const Point<T>& c,
45
+                      const Point<T>& d);
46
+
47
+  Point<T> valueAt(double t) const;
48
+};
49
+
50
+#include "util/geo/BezierCurve.tpp"
51
+}
52
+}
53
+
54
+#endif  // UTIL_GEO_BEZIERCURVE_H_

+ 70 - 0
src/util/geo/BezierCurve.tpp

@@ -0,0 +1,70 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename T>
7
+BezierCurve<T>::BezierCurve(const Point<T>& a, const Point<T>& b,
8
+                            const Point<T>& c, const Point<T>& d)
9
+    : _d(dist(a, d)) {
10
+  assert(_d > 0);
11
+  recalcPolynoms(a, b, c, d);
12
+}
13
+
14
+// _____________________________________________________________________________
15
+template <typename T>
16
+void BezierCurve<T>::recalcPolynoms(const Point<T>& a, const Point<T>& b,
17
+                                    const Point<T>& c, const Point<T>& d) {
18
+  _xp.a = a.getX();
19
+  _xp.b = 3.0 * (b.getX() - a.getX());
20
+  _xp.c = 3.0 * (c.getX() - b.getX()) - _xp.b;
21
+  _xp.d = d.getX() - a.getX() - _xp.c - _xp.b;
22
+
23
+  _yp.a = a.getY();
24
+  _yp.b = 3.0 * (b.getY() - a.getY());
25
+  _yp.c = 3.0 * (c.getY() - b.getY()) - _yp.b;
26
+  _yp.d = d.getY() - a.getY() - _yp.c - _yp.b;
27
+
28
+  _didRender = false;
29
+}
30
+
31
+// _____________________________________________________________________________
32
+template <typename T>
33
+Point<T> BezierCurve<T>::valueAt(double t) const {
34
+  return Point<T>(_xp.valueAt(t), _yp.valueAt(t));
35
+}
36
+
37
+// _____________________________________________________________________________
38
+template <typename T>
39
+const PolyLine<T>& BezierCurve<T>::render(double d) {
40
+  assert(d > 0);
41
+  if (_didRender) return _rendered;
42
+
43
+  if (_d == 0) {
44
+    _rendered << Point<T>(_xp.a, _yp.a) << Point<T>(_xp.a, _yp.a);
45
+    return _rendered;
46
+  }
47
+
48
+  _rendered.empty();
49
+  double n = _d / d, dt = 1 / n, t = 0;
50
+
51
+  bool cancel = false;
52
+  while (true) {
53
+    _rendered << valueAt(t);
54
+    t += dt;
55
+    if (cancel) break;
56
+    if (t > 1) {
57
+      t = 1;
58
+      cancel = true;
59
+    }
60
+  }
61
+
62
+  _didRender = true;
63
+  return _rendered;
64
+}
65
+
66
+// _____________________________________________________________________________
67
+double CubicPolynom::valueAt(double atx) const {
68
+  double dx = atx - x;
69
+  return a + b * dx + c * dx * dx + d * dx * dx * dx;
70
+}

+ 91 - 0
src/util/geo/Box.h

@@ -0,0 +1,91 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_BOX_H_
6
+#define UTIL_GEO_BOX_H_
7
+
8
+#include "./Point.h"
9
+
10
+namespace util {
11
+namespace geo {
12
+
13
+template <typename T>
14
+class Box {
15
+ public:
16
+  // maximum inverse box as default value of box
17
+  Box()
18
+      : _ll(std::numeric_limits<T>::max(), std::numeric_limits<T>::max()),
19
+        _ur(std::numeric_limits<T>::lowest(), std::numeric_limits<T>::lowest()) {}
20
+  Box(const Point<T>& ll, const Point<T>& ur) : _ll(ll), _ur(ur) {}
21
+  const Point<T>& getLowerLeft() const { return _ll; }
22
+  const Point<T>& getUpperRight() const { return _ur; }
23
+
24
+  Point<T>& getLowerLeft() { return _ll; }
25
+  Point<T>& getUpperRight() { return _ur; }
26
+
27
+  void setLowerLeft(const Point<T>& ll) { _ll = ll; }
28
+  void setUpperRight(const Point<T>& ur) { _ur = ur; }
29
+
30
+  bool operator==(const Box<T>& b) const {
31
+    return getLowerLeft() == b.getLowerLeft() &&
32
+           getUpperRight() == b.getUpperRight();
33
+  }
34
+
35
+  bool operator!=(const Box<T>& p) const { return !(*this == p); }
36
+
37
+ private:
38
+  Point<T> _ll, _ur;
39
+};
40
+
41
+template <typename T>
42
+class RotatedBox {
43
+ public:
44
+  RotatedBox() : _box(), _deg(0), _center() {}
45
+  RotatedBox(const Box<T>& box)
46
+      : _box(box),
47
+        _deg(0),
48
+        _center(Point<T>(
49
+            (box.getUpperRight().getX() - box.getLowerLeft().getX()) / T(2),
50
+            (box.getUpperRight().getY() - box.getLowerLeft().getY()) / T(2))) {}
51
+  RotatedBox(const Point<T>& ll, const Point<T>& ur)
52
+      : _box(ll, ur),
53
+        _deg(0),
54
+        _center(Point<T>((ur.getX() - ll.getX()) / T(2),
55
+                         (ur.getY() - ll.getY()) / T(2))) {}
56
+  RotatedBox(const Box<T>& box, double deg)
57
+      : _box(box),
58
+        _deg(deg),
59
+        _center(Point<T>(
60
+            (box.getUpperRight().getX() - box.getLowerLeft().getX()) / T(2),
61
+            (box.getUpperRight().getY() - box.getLowerLeft().getY()) / T(2))) {}
62
+  RotatedBox(const Point<T>& ll, const Point<T>& ur, double deg)
63
+      : _box(ll, ur),
64
+        _deg(deg),
65
+        _center(Point<T>((ur.getX() - ll.getX()) / T(2),
66
+                         (ur.getY() - ll.getY()) / T(2))) {}
67
+  RotatedBox(const Box<T>& box, double deg, const Point<T>& center)
68
+      : _box(box), _deg(deg), _center(center) {}
69
+  RotatedBox(const Point<T>& ll, const Point<T>& ur, double deg,
70
+             const Point<T>& center)
71
+      : _box(ll, ur), _deg(deg), _center(center) {}
72
+
73
+  const Box<T>& getBox() const { return _box; }
74
+  Box<T>& getBox() { return _box; }
75
+
76
+  double getDegree() const { return _deg; }
77
+  const Point<T>& getCenter() const { return _center; }
78
+  Point<T>& getCenter() { return _center; }
79
+
80
+  void setDegree(double deg) { _deg = deg; }
81
+
82
+ private:
83
+  Box<T> _box;
84
+  double _deg;
85
+  Point<T> _center;
86
+};
87
+
88
+}  // namespace geo
89
+}  // namespace util
90
+
91
+#endif  // UTIL_GEO_BOX_H_

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1544 - 0
src/util/geo/Geo.h


+ 32 - 0
src/util/geo/GeoGraph.h

@@ -0,0 +1,32 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEOGRAPH_H_
6
+#define UTIL_GEOGRAPH_H_
7
+
8
+#include <map>
9
+#include "util/geo/Geo.h"
10
+#include "util/json/Writer.h"
11
+
12
+namespace util {
13
+namespace geograph {
14
+
15
+template<typename T>
16
+class GeoEdgePL {
17
+ public:
18
+  virtual const util::geo::Line<T>* getGeom() const = 0;
19
+  virtual json::Dict getAttrs() const = 0;
20
+};
21
+
22
+template<typename T>
23
+class GeoNodePL {
24
+ public:
25
+  virtual const util::geo::Point<T>* getGeom() const = 0;
26
+  virtual json::Dict getAttrs() const = 0;
27
+};
28
+
29
+}  // namespace geograph
30
+}  // namespace util
31
+
32
+#endif  // UTIL_GEOGRAPH_H_

+ 89 - 0
src/util/geo/Grid.h

@@ -0,0 +1,89 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_GRID_H_
6
+#define UTIL_GEO_GRID_H_
7
+
8
+#include <set>
9
+#include <vector>
10
+#include <map>
11
+#include "util/geo/Geo.h"
12
+
13
+namespace util {
14
+namespace geo {
15
+
16
+class GridException : public std::runtime_error {
17
+ public:
18
+  GridException(std::string const& msg) : std::runtime_error(msg) {}
19
+};
20
+
21
+template <typename V, template <typename> class G, typename T>
22
+class Grid {
23
+ public:
24
+  // initialization of a point grid with cell width w and cell height h
25
+  // that covers the area of bounding box bbox
26
+  Grid(double w, double h, const Box<T>& bbox);
27
+
28
+  // initialization of a point grid with cell width w and cell height h
29
+  // that covers the area of bounding box bbox
30
+  // optional parameters specifies whether a value->cell index
31
+  // should be kept (true by default!)
32
+  Grid(double w, double h, const Box<T>& bbox, bool buildValIdx);
33
+
34
+  // the empty grid
35
+  Grid();
36
+  // the empty grid
37
+  Grid(bool buildValIdx);
38
+
39
+  // add object t to this grid
40
+  void add(G<T> geom, V val);
41
+  void add(size_t x, size_t y, V val);
42
+
43
+  void get(const Box<T>& btbox, std::set<V>* s) const;
44
+  void get(const G<T>& geom, double d, std::set<V>* s) const;
45
+  void get(size_t x, size_t y, std::set<V>* s) const;
46
+  void remove(V val);
47
+
48
+  void getNeighbors(const V& val, double d, std::set<V>* s) const;
49
+  void getCellNeighbors(const V& val, size_t d, std::set<V>* s) const;
50
+  void getCellNeighbors(size_t x, size_t y, size_t xPerm, size_t yPerm,
51
+                        std::set<V>* s) const;
52
+
53
+  std::set<std::pair<size_t, size_t> > getCells(const V& val) const;
54
+
55
+  size_t getXWidth() const;
56
+  size_t getYHeight() const;
57
+
58
+ private:
59
+  double _width;
60
+  double _height;
61
+
62
+  double _cellWidth;
63
+  double _cellHeight;
64
+
65
+  Box<T> _bb;
66
+
67
+  size_t _counter;
68
+
69
+  size_t _xWidth;
70
+  size_t _yHeight;
71
+
72
+  bool _hasValIdx;
73
+
74
+  std::vector<std::vector<std::set<V> > > _grid;
75
+  std::map<V, std::set<std::pair<size_t, size_t> > > _index;
76
+  std::set<V> _removed;
77
+
78
+  Box<T> getBox(size_t x, size_t y) const;
79
+
80
+  size_t getCellXFromX(double lon) const;
81
+  size_t getCellYFromY(double lat) const;
82
+};
83
+
84
+#include "util/geo/Grid.tpp"
85
+
86
+}  // namespace geo
87
+}  // namespace util
88
+
89
+#endif  // UTIL_GEO_GRID_H_

+ 228 - 0
src/util/geo/Grid.tpp

@@ -0,0 +1,228 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosip@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename V, template <typename> class G, typename T>
7
+Grid<V, G, T>::Grid(bool bldIdx)
8
+    : _width(0),
9
+      _height(0),
10
+      _cellWidth(0),
11
+      _cellHeight(0),
12
+      _xWidth(0),
13
+      _yHeight(0),
14
+      _hasValIdx(bldIdx) {}
15
+
16
+// _____________________________________________________________________________
17
+template <typename V, template <typename> class G, typename T>
18
+Grid<V, G, T>::Grid() : Grid<V, G, T>(true) {}
19
+
20
+// _____________________________________________________________________________
21
+template <typename V, template <typename> class G, typename T>
22
+Grid<V, G, T>::Grid(double w, double h, const Box<T>& bbox)
23
+    : Grid<V, G, T>(w, h, bbox, true) {}
24
+
25
+// _____________________________________________________________________________
26
+template <typename V, template <typename> class G, typename T>
27
+Grid<V, G, T>::Grid(double w, double h, const Box<T>& bbox, bool bValIdx)
28
+    : _cellWidth(fabs(w)),
29
+      _cellHeight(fabs(h)),
30
+      _bb(bbox),
31
+      _hasValIdx(bValIdx) {
32
+  _width =
33
+      bbox.getUpperRight().getX() - bbox.getLowerLeft().getX();
34
+  _height =
35
+      bbox.getUpperRight().getY() - bbox.getLowerLeft().getY();
36
+
37
+  if (_width < 0 || _height < 0) {
38
+    _width = 0;
39
+    _height = 0;
40
+    _xWidth = 0;
41
+    _yHeight = 0;
42
+    return;
43
+  }
44
+
45
+  _xWidth = ceil(_width / _cellWidth);
46
+  _yHeight = ceil(_height / _cellHeight);
47
+
48
+  // resize rows
49
+  _grid.resize(_xWidth);
50
+
51
+  // resize columns
52
+  for (size_t i = 0; i < _xWidth; i++) {
53
+    _grid[i].resize(_yHeight);
54
+  }
55
+}
56
+
57
+// _____________________________________________________________________________
58
+template <typename V, template <typename> class G, typename T>
59
+void Grid<V, G, T>::add(G<T> geom, V val) {
60
+  Box<T> box = getBoundingBox(geom);
61
+  size_t swX = getCellXFromX(box.getLowerLeft().getX());
62
+  size_t swY = getCellYFromY(box.getLowerLeft().getY());
63
+
64
+  size_t neX = getCellXFromX(box.getUpperRight().getX());
65
+  size_t neY = getCellYFromY(box.getUpperRight().getY());
66
+
67
+  for (size_t x = swX; x <= neX && x < _grid.size(); x++) {
68
+    for (size_t y = swY; y <= neY && y < _grid[x].size(); y++) {
69
+      if (intersects(geom, getBox(x, y))) {
70
+        add(x, y, val);
71
+      }
72
+    }
73
+  }
74
+}
75
+
76
+// _____________________________________________________________________________
77
+template <typename V, template <typename> class G, typename T>
78
+void Grid<V, G, T>::add(size_t x, size_t y, V val) {
79
+  _grid[x][y].insert(val);
80
+  if (_hasValIdx) _index[val].insert(std::pair<size_t, size_t>(x, y));
81
+}
82
+
83
+// _____________________________________________________________________________
84
+template <typename V, template <typename> class G, typename T>
85
+void Grid<V, G, T>::get(const Box<T>& box, std::set<V>* s) const {
86
+  size_t swX = getCellXFromX(box.getLowerLeft().getX());
87
+  size_t swY = getCellYFromY(box.getLowerLeft().getY());
88
+
89
+  size_t neX = getCellXFromX(box.getUpperRight().getX());
90
+  size_t neY = getCellYFromY(box.getUpperRight().getY());
91
+
92
+  for (size_t x = swX; x <= neX && x >= 0 && x < _xWidth; x++)
93
+    for (size_t y = swY; y <= neY && y >= 0 && y < _yHeight; y++) get(x, y, s);
94
+}
95
+
96
+// _____________________________________________________________________________
97
+template <typename V, template <typename> class G, typename T>
98
+void Grid<V, G, T>::get(const G<T>& geom, double d, std::set<V>* s) const {
99
+  Box<T> a = getBoundingBox(geom);
100
+  Box<T> b(Point<T>(a.getLowerLeft().getX() - d,
101
+                    a.getLowerLeft().getY() - d),
102
+           Point<T>(a.getUpperRight().getX() + d,
103
+                    a.getUpperRight().getY() + d));
104
+  return get(b, s);
105
+}
106
+
107
+// _____________________________________________________________________________
108
+template <typename V, template <typename> class G, typename T>
109
+void Grid<V, G, T>::get(size_t x, size_t y, std::set<V>* s) const {
110
+  if (_hasValIdx) {
111
+    s->insert(_grid[x][y].begin(), _grid[x][y].end());
112
+  } else {
113
+    // if we dont have a value index, we have a set of deleted nodes.
114
+    // in this case, only insert if not deleted
115
+    std::copy_if(_grid[x][y].begin(), _grid[x][y].end(),
116
+                 std::inserter(*s, s->end()),
117
+                 [&](const V& v) { return Grid<V, G, T>::_removed.count(v) == 0; });
118
+  }
119
+}
120
+
121
+// _____________________________________________________________________________
122
+template <typename V, template <typename> class G, typename T>
123
+void Grid<V, G, T>::remove(V val) {
124
+  if (_hasValIdx) {
125
+    auto i = _index.find(val);
126
+    if (i == _index.end()) return;
127
+
128
+    for (auto pair : i->second) {
129
+      _grid[pair.first][pair.second].erase(
130
+          _grid[pair.first][pair.second].find(val));
131
+    }
132
+
133
+    _index.erase(i);
134
+  } else {
135
+    _removed.insert(val);
136
+  }
137
+}
138
+
139
+// _____________________________________________________________________________
140
+template <typename V, template <typename> class G, typename T>
141
+void Grid<V, G, T>::getNeighbors(const V& val, double d, std::set<V>* s) const {
142
+  if (!_hasValIdx) throw GridException("No value index build!");
143
+  auto it = _index.find(val);
144
+  if (it == _index.end()) return;
145
+
146
+  size_t xPerm = ceil(d / _cellWidth);
147
+  size_t yPerm = ceil(d / _cellHeight);
148
+
149
+  for (auto pair : it->second) {
150
+    getCellNeighbors(pair.first, pair.second, xPerm, yPerm, s);
151
+  }
152
+}
153
+
154
+// _____________________________________________________________________________
155
+template <typename V, template <typename> class G, typename T>
156
+void Grid<V, G, T>::getCellNeighbors(const V& val, size_t d,
157
+                                     std::set<V>* s) const {
158
+  if (!_hasValIdx) throw GridException("No value index build!");
159
+  auto it = _index.find(val);
160
+  if (it == _index.end()) return;
161
+
162
+  for (auto pair : it->second) {
163
+    getCellNeighbors(pair.first, pair.second, d, d, s);
164
+  }
165
+}
166
+
167
+// _____________________________________________________________________________
168
+template <typename V, template <typename> class G, typename T>
169
+void Grid<V, G, T>::getCellNeighbors(size_t cx, size_t cy, size_t xPerm,
170
+                                     size_t yPerm, std::set<V>* s) const {
171
+  size_t swX = xPerm > cx ? 0 : cx - xPerm;
172
+  size_t swY = yPerm > cy ? 0 : cy - yPerm;
173
+
174
+  size_t neX = xPerm + cx + 1 > _xWidth ? _xWidth : cx + xPerm + 1;
175
+  size_t neY = yPerm + cy + 1 > _yHeight ? _yHeight : cy + yPerm + 1;
176
+
177
+  for (size_t x = swX; x < neX; x++) {
178
+    for (size_t y = swY; y < neY; y++) {
179
+      s->insert(_grid[x][y].begin(), _grid[x][y].end());
180
+    }
181
+  }
182
+}
183
+
184
+// _____________________________________________________________________________
185
+template <typename V, template <typename> class G, typename T>
186
+std::set<std::pair<size_t, size_t> > Grid<V, G, T>::getCells(
187
+    const V& val) const {
188
+  if (!_hasValIdx) throw GridException("No value index build!");
189
+  return _index.find(val)->second;
190
+}
191
+
192
+// _____________________________________________________________________________
193
+template <typename V, template <typename> class G, typename T>
194
+Box<T> Grid<V, G, T>::getBox(size_t x, size_t y) const {
195
+  Point<T> sw(_bb.getLowerLeft().getX() + x * _cellWidth,
196
+              _bb.getLowerLeft().getY() + y * _cellHeight);
197
+  Point<T> ne(_bb.getLowerLeft().getX() + (x + 1) * _cellWidth,
198
+              _bb.getLowerLeft().getY() + (y + 1) * _cellHeight);
199
+  return Box<T>(sw, ne);
200
+}
201
+
202
+// _____________________________________________________________________________
203
+template <typename V, template <typename> class G, typename T>
204
+size_t Grid<V, G, T>::getCellXFromX(double x) const {
205
+  float dist = x - _bb.getLowerLeft().getX();
206
+  if (dist < 0) dist = 0;
207
+  return floor(dist / _cellWidth);
208
+}
209
+
210
+// _____________________________________________________________________________
211
+template <typename V, template <typename> class G, typename T>
212
+size_t Grid<V, G, T>::getCellYFromY(double y) const {
213
+  float dist = y - _bb.getLowerLeft().getY();
214
+  if (dist < 0) dist = 0;
215
+  return floor(dist / _cellHeight);
216
+}
217
+
218
+// _____________________________________________________________________________
219
+template <typename V, template <typename> class G, typename T>
220
+size_t Grid<V, G, T>::getXWidth() const {
221
+  return _xWidth;
222
+}
223
+
224
+// _____________________________________________________________________________
225
+template <typename V, template <typename> class G, typename T>
226
+size_t Grid<V, G, T>::getYHeight() const {
227
+  return _yHeight;
228
+}

+ 28 - 0
src/util/geo/Line.h

@@ -0,0 +1,28 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_LINE_H_
6
+#define UTIL_GEO_LINE_H_
7
+
8
+#include <vector>
9
+#include "./Point.h"
10
+
11
+namespace util {
12
+namespace geo {
13
+
14
+template <typename T>
15
+class Line : public std::vector<Point<T>> {
16
+  using std::vector<Point<T>>::vector;
17
+};
18
+
19
+template <typename T>
20
+using LineSegment = std::pair<Point<T>, Point<T>>;
21
+
22
+template <typename T>
23
+using MultiLine = std::vector<Line<T>>;
24
+
25
+}  // namespace geo
26
+}  // namespace util
27
+
28
+#endif  // UTIL_GEO_LINE_H_

+ 50 - 0
src/util/geo/Point.h

@@ -0,0 +1,50 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_POINT_H_
6
+#define UTIL_GEO_POINT_H_
7
+
8
+#include <vector>
9
+
10
+namespace util {
11
+namespace geo {
12
+
13
+template <typename T>
14
+class Point {
15
+ public:
16
+  Point() : _x(0), _y(0) {}
17
+  Point(T x, T y) : _x(x), _y(y) {}
18
+  T getX() const { return _x; }
19
+  T getY() const { return _y; }
20
+
21
+  void setX(T x) { _x = x; }
22
+  void setY(T y) { _y = y; }
23
+
24
+  Point<T> operator+(const Point<T>& p) const {
25
+    return Point<T>(_x + p.getX(), _y + p.getY());
26
+  }
27
+
28
+  Point<T> operator-(const Point<T>& p) const {
29
+    return Point<T>(_x - p.getX(), _y - p.getY());
30
+  }
31
+
32
+  bool operator==(const Point<T>& p) const {
33
+    return p.getX() == _x && p.getY() == _y;
34
+  }
35
+
36
+  bool operator!=(const Point<T>& p) const {
37
+    return !(*this == p);
38
+  }
39
+
40
+ private:
41
+  T _x, _y;
42
+};
43
+
44
+template <typename T>
45
+using MultiPoint = std::vector<Point<T>>;
46
+
47
+}  // namespace geo
48
+}  // namespace util
49
+
50
+#endif  // UTIL_GEO_POINT_H_

+ 143 - 0
src/util/geo/PolyLine.h

@@ -0,0 +1,143 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_POLYLINE_H_
6
+#define UTIL_GEO_POLYLINE_H_
7
+
8
+#include <cfloat>
9
+#include <ostream>
10
+#include <iomanip>
11
+#include <string>
12
+#include <set>
13
+#include <vector>
14
+#include "Geo.h"
15
+
16
+namespace util {
17
+namespace geo {
18
+
19
+static const double MAX_EQ_DISTANCE = 15;
20
+static const double AVERAGING_STEP = 20;
21
+
22
+// legacy code, will be removed in the future
23
+
24
+template <typename T>
25
+struct LinePoint {
26
+  LinePoint() : lastIndex(0), totalPos(-1), p() {}
27
+
28
+  LinePoint(size_t i, double pos, const Point<T>& p)
29
+      : lastIndex(i), totalPos(pos), p(p) {}
30
+  size_t lastIndex;
31
+  double totalPos;
32
+  Point<T> p;
33
+};
34
+
35
+template <typename T>
36
+struct LinePointCmp {
37
+  bool operator()(const LinePoint<T>& lh, const LinePoint<T>& rh) const {
38
+    return lh.totalPos < rh.totalPos;
39
+  }
40
+};
41
+
42
+
43
+template <typename T>
44
+using LinePointPair = std::pair<LinePoint<T>, LinePoint<T>>;
45
+template <typename T>
46
+using SharedSegment = std::pair<LinePointPair<T>, LinePointPair<T>>;
47
+
48
+template <typename T>
49
+struct SharedSegments {
50
+  std::vector<SharedSegment<T>> segments;
51
+};
52
+
53
+template <typename T>
54
+class PolyLine {
55
+ public:
56
+  PolyLine();
57
+  PolyLine(const Point<T>& from, const Point<T>& to);
58
+  PolyLine(const Line<T>& l);
59
+
60
+  PolyLine& operator<<(const Point<T>& p);
61
+  PolyLine& operator>>(const Point<T>& p);
62
+
63
+  void reverse();
64
+  PolyLine getReversed() const;
65
+
66
+  void offsetPerp(double units);
67
+
68
+  PolyLine getPerpOffsetted(double units) const;
69
+
70
+  const Line<T>& getLine() const;
71
+
72
+  double distTo(const PolyLine<T>& g) const;
73
+  double distTo(const Point<T>& p) const;
74
+
75
+  SharedSegments<T> getSharedSegments(const PolyLine<T>& pl, double dmax) const;
76
+
77
+  double getLength() const;
78
+
79
+  // return point at dist
80
+  LinePoint<T> getPointAtDist(double dist) const;
81
+
82
+  // return point at [0..1]
83
+  LinePoint<T> getPointAt(double dist) const;
84
+
85
+  PolyLine<T> getSegment(double a, double b) const;
86
+  PolyLine<T> getSegmentAtDist(double dista, double distb) const;
87
+  PolyLine<T> getSegment(const LinePoint<T>& start, const LinePoint<T>& end) const;
88
+  PolyLine<T> getSegment(const Point<T>& a, const Point<T>& b) const;
89
+
90
+  std::set<LinePoint<T>, LinePointCmp<T>> getIntersections(const PolyLine<T>& g) const;
91
+
92
+  static PolyLine<T> average(const std::vector<const PolyLine<T>*>& lines);
93
+  static PolyLine<T> average(const std::vector<const PolyLine<T>*>& lines,
94
+                          const std::vector<double>& weights);
95
+
96
+  void simplify(double d);
97
+  void empty();
98
+
99
+  void smoothenOutliers(double d);
100
+
101
+  std::pair<size_t, double> nearestSegment(const Point<T>& p) const;
102
+  std::pair<size_t, double> nearestSegmentAfter(const Point<T>& p,
103
+                                                size_t after) const;
104
+
105
+  LinePoint<T> projectOn(const Point<T>& p) const;
106
+  LinePoint<T> projectOnAfter(const Point<T>& p, size_t after) const;
107
+
108
+  void move(double vx, double vy);
109
+
110
+  std::pair<double, double> getSlopeBetween(double ad, double bd) const;
111
+  std::pair<double, double> getSlopeBetweenDists(double ad, double bd) const;
112
+
113
+  // equality operator, will hold frechet-distance equality check in
114
+  // the dmax
115
+  bool operator==(const PolyLine& rhs) const;
116
+  bool contains(const PolyLine& rhs, double dmax) const;
117
+  bool equals(const PolyLine& rhs) const;
118
+  bool equals(const PolyLine& rhs, double dmax) const;
119
+
120
+  std::string getWKT() const;
121
+
122
+  PolyLine getOrthoLineAtDist(double d, double lengt) const;
123
+
124
+  Point<T> interpolate(const Point<T>& a, const Point<T>& b, double p) const;
125
+
126
+  void fixTopology(double maxl);
127
+  void applyChaikinSmooth(size_t depth);
128
+
129
+  const Point<T>& front() const;
130
+  const Point<T>& back() const;
131
+
132
+ private:
133
+  std::set<LinePoint<T>, LinePointCmp<T>> getIntersections(const PolyLine& p,
134
+                                                     size_t a, size_t b) const;
135
+  Line<T> _line;
136
+};
137
+
138
+#include "util/geo/PolyLine.tpp"
139
+
140
+}  // namespace geo
141
+}  // namespace util
142
+
143
+#endif  // UTIL_GEO_POLYLINE_H_

+ 731 - 0
src/util/geo/PolyLine.tpp

@@ -0,0 +1,731 @@
1
+// Copyright 2016, University of Freibur
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename T>
7
+PolyLine<T>::PolyLine() {}
8
+
9
+// _____________________________________________________________________________
10
+template <typename T>
11
+PolyLine<T>::PolyLine(const Point<T>& from, const Point<T>& to) {
12
+  *this << from << to;
13
+}
14
+
15
+// _____________________________________________________________________________
16
+template <typename T>
17
+PolyLine<T>::PolyLine(const Line<T>& l) : _line(l) {}
18
+
19
+// _____________________________________________________________________________
20
+template <typename T>
21
+PolyLine<T>& PolyLine<T>::operator<<(const Point<T>& p) {
22
+  _line.push_back(p);
23
+  return *this;
24
+}
25
+
26
+// _____________________________________________________________________________
27
+template <typename T>
28
+PolyLine<T>& PolyLine<T>::operator>>(const Point<T>& p) {
29
+  _line.insert(_line.begin(), p);
30
+  return *this;
31
+}
32
+
33
+// _____________________________________________________________________________
34
+template <typename T>
35
+void PolyLine<T>::reverse() {
36
+  std::reverse(_line.begin(), _line.end());
37
+}
38
+
39
+// _____________________________________________________________________________
40
+template <typename T>
41
+PolyLine<T> PolyLine<T>::getReversed() const {
42
+  PolyLine ret = *this;
43
+  ret.reverse();
44
+  return ret;
45
+}
46
+
47
+// _____________________________________________________________________________
48
+template <typename T>
49
+const Line<T>& PolyLine<T>::getLine() const {
50
+  return _line;
51
+}
52
+
53
+// _____________________________________________________________________________
54
+template <typename T>
55
+PolyLine<T> PolyLine<T>::getPerpOffsetted(double units) const {
56
+  PolyLine p = *this;
57
+  p.offsetPerp(units);
58
+  return p;
59
+}
60
+
61
+// _____________________________________________________________________________
62
+template <typename T>
63
+void PolyLine<T>::offsetPerp(double units) {
64
+  /*
65
+   * calculate perpendicular offset of a polyline
66
+   *
67
+   * there doesn't seem to be any library which reliably does that,
68
+   * so we do it ourself here until we find one...
69
+   */
70
+
71
+  if (fabs(units) < 0.001) return;
72
+
73
+  assert(getLength() > 0);
74
+
75
+  if (_line.size() < 2) return;
76
+
77
+  Line<T> ret;
78
+  Point<T> lastP = _line.front();
79
+
80
+  Point<T> *lastIns = 0, *befLastIns = 0;
81
+
82
+  for (size_t i = 1; i < _line.size(); i++) {
83
+    Point<T> curP = _line[i];
84
+
85
+    double n1 = lastP.getY() - curP.getY();
86
+    double n2 = curP.getX() - lastP.getX();
87
+    double n = sqrt(n1 * n1 + n2 * n2);
88
+
89
+    // if n == 0, the segment is effectively a point
90
+    // we would get into all sorts of troubles if we tried to offset a point...
91
+    if (!(n > 0)) continue;
92
+
93
+    n1 = n1 / n;
94
+    n2 = n2 / n;
95
+
96
+    lastP.setX(lastP.getX() + (n1 * units));
97
+    lastP.setY(lastP.getY() + (n2 * units));
98
+
99
+    curP.setX(curP.getX() + (n1 * units));
100
+    curP.setY(curP.getY() + (n2 * units));
101
+
102
+    if (lastIns && befLastIns &&
103
+        lineIntersects(*lastIns, *befLastIns, lastP, curP)) {
104
+      *lastIns = intersection(*lastIns, *befLastIns, lastP, curP);
105
+
106
+      double d = dist(lastP, *lastIns);
107
+      double d2 = distToSegment(*lastIns, *befLastIns, lastP);
108
+
109
+      if (d > fabs(units) * 2 && d2 < d - (fabs(units))) {
110
+        PolyLine pl(*lastIns, *befLastIns);
111
+        PolyLine pll(*lastIns, curP);
112
+        pl = pl.getSegment(0, (d - (fabs(units))) / pl.getLength());
113
+        pll = pll.getSegment(0, (d - (fabs(units))) / pll.getLength());
114
+
115
+        ret.push_back(pll.back());
116
+        *lastIns = pl.back();
117
+
118
+        ret.push_back(curP);
119
+      } else {
120
+        ret.push_back(curP);
121
+      }
122
+    } else {
123
+      ret.push_back(lastP);
124
+      ret.push_back(curP);
125
+    }
126
+
127
+    lastIns = &ret[ret.size() - 1];
128
+    befLastIns = &ret[ret.size() - 2];
129
+
130
+    lastP = _line[i];
131
+  }
132
+
133
+  _line = ret;
134
+
135
+  // heuristics
136
+  simplify(1);
137
+  fixTopology(fabs(2 * 3.14 * units));
138
+}
139
+
140
+// _____________________________________________________________________________
141
+template <typename T>
142
+PolyLine<T> PolyLine<T>::getSegment(double a, double b) const {
143
+  if (a > b) {
144
+    double c = a;
145
+    a = b;
146
+    b = c;
147
+  }
148
+  LinePoint<T> start = getPointAt(a);
149
+  LinePoint<T> end = getPointAt(b);
150
+
151
+  return getSegment(start, end);
152
+}
153
+
154
+// _____________________________________________________________________________
155
+template <typename T>
156
+PolyLine<T> PolyLine<T>::getSegmentAtDist(double a, double b) const {
157
+  if (a > b) {
158
+    double c = a;
159
+    a = b;
160
+    b = c;
161
+  }
162
+  LinePoint<T> start = getPointAtDist(a);
163
+  LinePoint<T> end = getPointAtDist(b);
164
+
165
+  return getSegment(start, end);
166
+}
167
+
168
+// _____________________________________________________________________________
169
+template <typename T>
170
+PolyLine<T> PolyLine<T>::getSegment(const Point<T>& a,
171
+                                    const Point<T>& b) const {
172
+  LinePoint<T> start = projectOn(a);
173
+  LinePoint<T> end = projectOnAfter(b, start.lastIndex);
174
+
175
+  return getSegment(start, end);
176
+}
177
+
178
+// _____________________________________________________________________________
179
+template <typename T>
180
+PolyLine<T> PolyLine<T>::getSegment(const LinePoint<T>& start,
181
+                                    const LinePoint<T>& end) const {
182
+  PolyLine ret;
183
+  ret << start.p;
184
+
185
+  if (start.lastIndex + 1 <= end.lastIndex) {
186
+    ret._line.insert(ret._line.end(), _line.begin() + start.lastIndex + 1,
187
+                     _line.begin() + end.lastIndex + 1);
188
+  }
189
+  ret << end.p;
190
+
191
+  // find a more performant way to clear the result of above
192
+  ret.simplify(0);
193
+
194
+  return ret;
195
+}
196
+
197
+// _____________________________________________________________________________
198
+template <typename T>
199
+LinePoint<T> PolyLine<T>::getPointAtDist(double atDist) const {
200
+  if (atDist > getLength()) atDist = getLength();
201
+  if (atDist < 0) atDist = 0;
202
+
203
+  double dist = 0;
204
+
205
+  if (_line.size() == 1) return LinePoint<T>(0, 0, _line[0]);
206
+
207
+  const Point<T>* last = &_line[0];
208
+
209
+  for (size_t i = 1; i < _line.size(); i++) {
210
+    const Point<T>& cur = _line[i];
211
+    double d = geo::dist(*last, cur);
212
+    dist += d;
213
+
214
+    if (dist > atDist) {
215
+      double p = (d - (dist - atDist));
216
+      return LinePoint<T>(i - 1, atDist / getLength(),
217
+                          interpolate(*last, cur, p));
218
+    }
219
+
220
+    last = &_line[i];
221
+  }
222
+
223
+  return LinePoint<T>(_line.size() - 1, 1, _line.back());
224
+}
225
+
226
+// _____________________________________________________________________________
227
+template <typename T>
228
+LinePoint<T> PolyLine<T>::getPointAt(double at) const {
229
+  at *= getLength();
230
+  return getPointAtDist(at);
231
+}
232
+
233
+// _____________________________________________________________________________
234
+template <typename T>
235
+Point<T> PolyLine<T>::interpolate(const Point<T>& a, const Point<T>& b,
236
+                                  double p) const {
237
+  double n1 = b.getX() - a.getX();
238
+  double n2 = b.getY() - a.getY();
239
+  double n = sqrt(n1 * n1 + n2 * n2);
240
+  n1 = n1 / n;
241
+  n2 = n2 / n;
242
+  return Point<T>(a.getX() + (n1 * p),
243
+                  a.getY() + (n2 * p));
244
+}
245
+
246
+// _____________________________________________________________________________
247
+template <typename T>
248
+double PolyLine<T>::distTo(const PolyLine<T>& g) const {
249
+  return dist(_line, g.getLine());
250
+}
251
+
252
+// _____________________________________________________________________________
253
+template <typename T>
254
+double PolyLine<T>::distTo(const Point<T>& p) const {
255
+  return dist(_line, p);
256
+}
257
+
258
+// _____________________________________________________________________________
259
+template <typename T>
260
+double PolyLine<T>::getLength() const {
261
+  return len(_line);
262
+}
263
+
264
+// _____________________________________________________________________________
265
+template <typename T>
266
+PolyLine<T> PolyLine<T>::average(const std::vector<const PolyLine<T>*>& lines,
267
+                                 const std::vector<double>& weights) {
268
+  bool weighted = lines.size() == weights.size();
269
+  double stepSize;
270
+
271
+  double longestLength = DBL_MIN;  // avoid recalc of length on each comparision
272
+  for (const PolyLine* p : lines) {
273
+    if (p->getLength() > longestLength) {
274
+      longestLength = p->getLength();
275
+    }
276
+  }
277
+
278
+  PolyLine ret;
279
+  double total = 0;
280
+
281
+  for (size_t i = 0; i < lines.size(); ++i) {
282
+    if (weighted) {
283
+      total += weights[i];
284
+    } else {
285
+      total += 1;
286
+    }
287
+  }
288
+
289
+  stepSize = AVERAGING_STEP / longestLength;
290
+  bool end = false;
291
+  for (double a = 0; !end; a += stepSize) {
292
+    if (a > 1) {
293
+      a = 1;
294
+      end = true;
295
+    }
296
+    double x = 0, y = 0;
297
+
298
+    for (size_t i = 0; i < lines.size(); ++i) {
299
+      const PolyLine* pl = lines[i];
300
+      Point<T> p = pl->getPointAt(a).p;
301
+      if (weighted) {
302
+        x += p.getX() * weights[i];
303
+        y += p.getY() * weights[i];
304
+      } else {
305
+        x += p.getX();
306
+        y += p.getY();
307
+      }
308
+    }
309
+    ret << Point<T>(x / total, y / total);
310
+  }
311
+
312
+  ret.simplify(0);
313
+
314
+  return ret;
315
+}
316
+
317
+// _____________________________________________________________________________
318
+template <typename T>
319
+PolyLine<T> PolyLine<T>::average(const std::vector<const PolyLine<T>*>& lines) {
320
+  return average(lines, std::vector<double>());
321
+}
322
+
323
+// _____________________________________________________________________________
324
+template <typename T>
325
+std::pair<size_t, double> PolyLine<T>::nearestSegmentAfter(const Point<T>& p,
326
+                                                           size_t a) const {
327
+  // returns the index of the starting point of the nearest segment of p
328
+  assert(a < _line.size());
329
+
330
+  double totalLength = getLength();
331
+  size_t smallest = a;
332
+  double totalDist = 0;
333
+  double dist = DBL_MAX;
334
+  double smallestDist = 0;
335
+
336
+  for (size_t i = smallest + 1; i < _line.size(); i++) {
337
+    Point<T> startP(_line[i - 1]);
338
+    Point<T> endP(_line[i]);
339
+
340
+    if (i > 1) {
341
+      totalDist += geo::dist(_line[i - 2], _line[i - 1]);
342
+    }
343
+
344
+    double curDist = distToSegment(startP, endP, p);
345
+
346
+    if (curDist < dist) {
347
+      dist = curDist;
348
+      smallest = i - 1;
349
+      smallestDist = totalDist;
350
+    }
351
+  }
352
+
353
+  if (totalLength > 0) {
354
+    smallestDist /= totalLength;
355
+  } else {
356
+    smallestDist = 0;
357
+  }
358
+
359
+  return std::pair<size_t, double>(smallest, smallestDist);
360
+}
361
+
362
+// _____________________________________________________________________________
363
+template <typename T>
364
+std::pair<size_t, double> PolyLine<T>::nearestSegment(const Point<T>& p) const {
365
+  return nearestSegmentAfter(p, 0);
366
+}
367
+
368
+// _____________________________________________________________________________
369
+template <typename T>
370
+LinePoint<T> PolyLine<T>::projectOn(const Point<T>& p) const {
371
+  return projectOnAfter(p, 0);
372
+}
373
+
374
+// _____________________________________________________________________________
375
+template <typename T>
376
+LinePoint<T> PolyLine<T>::projectOnAfter(const Point<T>& p, size_t a) const {
377
+  assert(a < _line.size());
378
+  std::pair<size_t, double> bc = nearestSegmentAfter(p, a);
379
+
380
+  Point<T> ret = geo::projectOn(_line[bc.first], p, _line[bc.first + 1]);
381
+
382
+  if (getLength() > 0) {
383
+    bc.second += dist(_line[bc.first], ret) / getLength();
384
+  }
385
+
386
+  return LinePoint<T>(bc.first, bc.second, ret);
387
+}
388
+
389
+// _____________________________________________________________________________
390
+template <typename T>
391
+void PolyLine<T>::simplify(double d) {
392
+  _line = geo::simplify(_line, d);
393
+}
394
+
395
+// _____________________________________________________________________________
396
+template <typename T>
397
+void PolyLine<T>::smoothenOutliers(double d) {
398
+  if (_line.size() < 3) return;
399
+  for (size_t i = 1; i < _line.size() - 3; ++i) {
400
+    double ang = innerProd(_line[i], _line[i - 1], _line[i + 1]);
401
+
402
+    if (dist(_line[i], _line[i + 1]) < d || dist(_line[i], _line[i - 1]) < d) {
403
+      if (ang < 35) {
404
+        _line.erase(_line.begin() + i);
405
+      }
406
+    }
407
+  }
408
+}
409
+
410
+// _____________________________________________________________________________
411
+template <typename T>
412
+bool PolyLine<T>::equals(const PolyLine<T>& rhs) const {
413
+  // TODO: why 100? make global static or configurable or determine in some
414
+  //       way!
415
+  return equals(rhs, 100);
416
+}
417
+
418
+// _____________________________________________________________________________
419
+template <typename T>
420
+bool PolyLine<T>::operator==(const PolyLine<T>& rhs) const {
421
+  // TODO: why 100? make global static or configurable or determine in some
422
+  //       way!
423
+  return equals(rhs, 100);
424
+}
425
+
426
+// _____________________________________________________________________________
427
+template <typename T>
428
+bool PolyLine<T>::equals(const PolyLine<T>& rhs, double dmax) const {
429
+  // check if two lines are equal, THE DIRECTION DOES NOT MATTER HERE!!!!!
430
+
431
+  if (_line.size() == 2 && _line.size() == rhs.getLine().size()) {
432
+    // trivial case, straight line, implement directly
433
+    return (dist(_line[0], rhs.getLine()[0]) < dmax &&
434
+            dist(_line.back(), rhs.back()) < dmax) ||
435
+           (dist(_line[0], rhs.back()) < dmax &&
436
+            dist(_line.back(), rhs.getLine()[0]) < dmax);
437
+  } else {
438
+    return contains(rhs, dmax) && rhs.contains(*this, dmax);
439
+  }
440
+
441
+  return true;
442
+}
443
+
444
+// _____________________________________________________________________________
445
+template <typename T>
446
+bool PolyLine<T>::contains(const PolyLine<T>& rhs, double dmax) const {
447
+  // check if two lines are equal. Line direction does not matter here.
448
+
449
+  for (size_t i = 0; i < rhs.getLine().size(); ++i) {
450
+    double d = dist(rhs.getLine()[i], getLine());
451
+    if (d > dmax) {
452
+      return false;
453
+    }
454
+  }
455
+
456
+  return true;
457
+}
458
+
459
+// _____________________________________________________________________________
460
+template <typename T>
461
+void PolyLine<T>::move(double vx, double vy) {
462
+  for (size_t i = 0; i < _line.size(); i++) {
463
+    _line[i].setX(_line[i].getX() + vx);
464
+    _line[i].setY(_line[i].getY() + vy);
465
+  }
466
+}
467
+
468
+// _____________________________________________________________________________
469
+template <typename T>
470
+SharedSegments<T> PolyLine<T>::getSharedSegments(const PolyLine<T>& pl,
471
+                                                 double dmax) const {
472
+  /**
473
+   * Returns the segments this polyline share with pl
474
+   * atm, this is a very simple distance-based algorithm
475
+   */
476
+  double STEP_SIZE = 2;
477
+  double MAX_SKIPS = 4;
478
+  double MIN_SEG_LENGTH = 1;  // dmax / 2;  // make this configurable!
479
+
480
+  SharedSegments<T> ret;
481
+
482
+  if (distTo(pl) > dmax) return ret;
483
+
484
+  bool in = false, single = true;
485
+  double curDist = 0;
486
+  double curTotalSegDist = 0;
487
+  size_t skips;
488
+
489
+  LinePoint<T> curStartCand, curEndCand, curStartCandCmp, curEndCandCmp;
490
+
491
+  double comp = 0, curSegDist = 0;
492
+  double length = getLength(), plLength = pl.getLength();
493
+
494
+  for (size_t i = 1; i < _line.size(); ++i) {
495
+    const Point<T>& s = _line[i - 1];
496
+    const Point<T>& e = _line[i];
497
+
498
+    bool lastRound = false;
499
+
500
+    double totalDist = dist(s, e);
501
+    while (curSegDist <= totalDist) {
502
+      const Point<T>& curPointer = interpolate(s, e, curSegDist);
503
+
504
+      if (pl.distTo(curPointer) <= dmax) {
505
+        LinePoint<T> curCmpPointer = pl.projectOn(curPointer);
506
+        LinePoint<T> curBackProjectedPointer = projectOn(curCmpPointer.p);
507
+        skips = 0;
508
+
509
+        if (in) {
510
+          curEndCand = curBackProjectedPointer;
511
+          curEndCandCmp = curCmpPointer;
512
+
513
+          single = false;
514
+
515
+          comp = fabs(curStartCand.totalPos * length -
516
+                      curEndCand.totalPos * length) /
517
+                 fabs(curStartCandCmp.totalPos * plLength -
518
+                      curEndCandCmp.totalPos * plLength);
519
+        } else {
520
+          in = true;
521
+          curStartCand = curBackProjectedPointer;
522
+          curStartCandCmp = curCmpPointer;
523
+        }
524
+      } else {
525
+        if (in) {
526
+          skips++;
527
+          if (skips > MAX_SKIPS) {  // TODO: make configurable
528
+            if (comp > 0.8 && comp < 1.2 && !single &&
529
+                (fabs(curStartCand.totalPos * length -
530
+                      curEndCand.totalPos * length) > MIN_SEG_LENGTH &&
531
+                 fabs(curStartCandCmp.totalPos * plLength -
532
+                      curEndCandCmp.totalPos * plLength) > MIN_SEG_LENGTH)) {
533
+              ret.segments.push_back(
534
+                  SharedSegment<T>(std::pair<LinePoint<T>, LinePoint<T>>(
535
+                                       curStartCand, curStartCandCmp),
536
+                                   std::pair<LinePoint<T>, LinePoint<T>>(
537
+                                       curEndCand, curEndCandCmp)));
538
+
539
+              // TODO: only return the FIRST one, make this configuralbe
540
+              return ret;
541
+            }
542
+
543
+            in = false;
544
+            single = true;
545
+          }
546
+        }
547
+      }
548
+
549
+      if (curSegDist + STEP_SIZE > totalDist && !lastRound) {
550
+        lastRound = true;
551
+        double finalStep = totalDist - curSegDist - 0.0005;
552
+        curSegDist += finalStep;
553
+        curDist += finalStep;
554
+      } else {
555
+        curSegDist += STEP_SIZE;
556
+        curDist += STEP_SIZE;
557
+      }
558
+    }
559
+
560
+    curSegDist = curSegDist - totalDist;
561
+    curTotalSegDist += totalDist;
562
+  }
563
+
564
+  if (comp > 0.8 && comp < 1.2 && in && !single &&
565
+      (fabs(curStartCand.totalPos * length - curEndCand.totalPos * length) >
566
+           MIN_SEG_LENGTH &&
567
+       fabs(curStartCandCmp.totalPos * plLength -
568
+            curEndCandCmp.totalPos * plLength) > MIN_SEG_LENGTH)) {
569
+    ret.segments.push_back(SharedSegment<T>(
570
+        std::pair<LinePoint<T>, LinePoint<T>>(curStartCand, curStartCandCmp),
571
+        std::pair<LinePoint<T>, LinePoint<T>>(curEndCand, curEndCandCmp)));
572
+  }
573
+
574
+  return ret;
575
+}
576
+
577
+// _____________________________________________________________________________
578
+template <typename T>
579
+std::set<LinePoint<T>, LinePointCmp<T>> PolyLine<T>::getIntersections(
580
+    const PolyLine<T>& g) const {
581
+  std::set<LinePoint<T>, LinePointCmp<T>> ret;
582
+
583
+  for (size_t i = 1; i < g.getLine().size(); ++i) {
584
+    // for each line segment, check if it intersects with a line segment in g
585
+    const std::set<LinePoint<T>, LinePointCmp<T>> a =
586
+        getIntersections(g, i - 1, i);
587
+    ret.insert(a.begin(), a.end());
588
+  }
589
+
590
+  return ret;
591
+}
592
+
593
+// _____________________________________________________________________________
594
+template <typename T>
595
+std::set<LinePoint<T>, LinePointCmp<T>> PolyLine<T>::getIntersections(
596
+    const PolyLine<T>& p, size_t a, size_t b) const {
597
+  std::set<LinePoint<T>, LinePointCmp<T>> ret;
598
+
599
+  if (dist(p.getLine()[a], p.getLine()[b]) == 0) {
600
+    // we cannot intersect with a point
601
+    return ret;
602
+  }
603
+
604
+  for (size_t i = 1; i < _line.size(); ++i) {
605
+    if (intersects(_line[i - 1], _line[i], p.getLine()[a], p.getLine()[b])) {
606
+      Point<T> isect =
607
+          intersection(_line[i - 1], _line[i], p.getLine()[a], p.getLine()[b]);
608
+      ret.insert(p.projectOn(isect));
609
+    }
610
+  }
611
+
612
+  return ret;
613
+}
614
+
615
+// _____________________________________________________________________________
616
+template <typename T>
617
+PolyLine<T> PolyLine<T>::getOrthoLineAtDist(double d, double length) const {
618
+  Point<T> avgP = getPointAtDist(d).p;
619
+
620
+  double angle = angBetween(getPointAtDist(d - 5).p, getPointAtDist(d + 5).p);
621
+
622
+  double angleX1 = avgP.getX() + cos(angle + M_PI / 2) * length / 2;
623
+  double angleY1 = avgP.getY() + sin(angle + M_PI / 2) * length / 2;
624
+
625
+  double angleX2 = avgP.getX() + cos(angle + M_PI / 2) * -length / 2;
626
+  double angleY2 = avgP.getY() + sin(angle + M_PI / 2) * -length / 2;
627
+
628
+  return PolyLine(Point<T>(angleX1, angleY1), Point<T>(angleX2, angleY2));
629
+}
630
+
631
+// _____________________________________________________________________________
632
+template <typename T>
633
+void PolyLine<T>::empty() {
634
+  _line.empty();
635
+}
636
+
637
+// _____________________________________________________________________________
638
+template <typename T>
639
+std::pair<double, double> PolyLine<T>::getSlopeBetween(double ad,
640
+                                                       double bd) const {
641
+  LinePoint<T> a = getPointAt(ad);
642
+  LinePoint<T> b = getPointAt(bd);
643
+
644
+  double d = dist(a.p, b.p);
645
+
646
+  double dx = (b.p.getX() - a.p.getX()) / d;
647
+  double dy = (b.p.getY() - a.p.getY()) / d;
648
+
649
+  return std::pair<double, double>(dx, dy);
650
+}
651
+
652
+// _____________________________________________________________________________
653
+template <typename T>
654
+std::pair<double, double> PolyLine<T>::getSlopeBetweenDists(double ad,
655
+                                                            double bd) const {
656
+  return getSlopeBetween(ad / getLength(), bd / getLength());
657
+}
658
+
659
+// _____________________________________________________________________________
660
+template <typename T>
661
+std::string PolyLine<T>::getWKT() const {
662
+  std::stringstream ss;
663
+  ss << std::setprecision(12) << geo::getWKT(_line);
664
+
665
+  return ss.str();
666
+}
667
+
668
+// _____________________________________________________________________________
669
+template <typename T>
670
+void PolyLine<T>::fixTopology(double maxl) {
671
+  double distA = 0;
672
+
673
+  for (size_t i = 1; i < _line.size() - 1; i++) {
674
+    double distB =
675
+        distA + dist(_line[i - 1], _line[i]) + dist(_line[i], _line[i + 1]);
676
+    for (size_t j = i + 2; j < _line.size(); j++) {
677
+      if (intersects(_line[i - 1], _line[i], _line[j - 1], _line[j])) {
678
+        Point<T> p =
679
+            intersection(_line[i - 1], _line[i], _line[j - 1], _line[j]);
680
+
681
+        double posA = dist(_line[i - 1], p) + distA;
682
+        double posB = dist(_line[j - 1], p) + distB;
683
+
684
+        if (fabs(posA - posB) < maxl) {
685
+          _line[i] = p;
686
+          _line.erase(_line.begin() + i + 1, _line.begin() + j);
687
+        }
688
+      }
689
+
690
+      distB += dist(_line[j - 1], _line[j]);
691
+    }
692
+    distA += dist(_line[i - 1], _line[i]);
693
+  }
694
+}
695
+
696
+// _____________________________________________________________________________
697
+template <typename T>
698
+void PolyLine<T>::applyChaikinSmooth(size_t depth) {
699
+  for (size_t i = 0; i < depth; i++) {
700
+    Line<T> smooth;
701
+
702
+    smooth.push_back(_line.front());
703
+
704
+    for (size_t i = 1; i < _line.size(); i++) {
705
+      Point<T> pA = _line[i - 1];
706
+      Point<T> pB = _line[i];
707
+
708
+      smooth.push_back(
709
+          Point<T>(0.75 * pA.getX() + 0.25 * pB.getX(),
710
+                   0.75 * pA.getY() + 0.25 * pB.getY()));
711
+      smooth.push_back(
712
+          Point<T>(0.25 * pA.getX() + 0.75 * pB.getX(),
713
+                   0.25 * pA.getY() + 0.75 * pB.getY()));
714
+    }
715
+
716
+    smooth.push_back(_line.back());
717
+    _line = smooth;
718
+  }
719
+}
720
+
721
+// _____________________________________________________________________________
722
+template <typename T>
723
+const Point<T>& PolyLine<T>::front() const {
724
+  return _line.front();
725
+}
726
+
727
+// _____________________________________________________________________________
728
+template <typename T>
729
+const Point<T>& PolyLine<T>::back() const {
730
+  return _line.back();
731
+}

+ 41 - 0
src/util/geo/Polygon.h

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Author: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_POLYGON_H_
6
+#define UTIL_GEO_POLYGON_H_
7
+
8
+#include <vector>
9
+#include "./Box.h"
10
+#include "./Line.h"
11
+#include "./Point.h"
12
+
13
+namespace util {
14
+namespace geo {
15
+
16
+template <typename T>
17
+class Polygon {
18
+ public:
19
+  Polygon() {}
20
+
21
+  Polygon(const Line<T>& l) : _outer(l) {}
22
+  Polygon(const Box<T>& b)
23
+      : _outer({b.getLowerLeft(),
24
+                Point<T>(b.getUpperRight().getX(), b.getLowerLeft().getY()),
25
+                b.getUpperRight(),
26
+                Point<T>(b.getLowerLeft().getX(), b.getUpperRight().getY())}) {}
27
+
28
+  const Line<T>& getOuter() const { return _outer; }
29
+  Line<T>& getOuter() { return _outer; }
30
+
31
+ private:
32
+  Line<T> _outer;
33
+};
34
+
35
+template <typename T>
36
+using MultiPolygon = std::vector<Polygon<T>>;
37
+
38
+}  // namespace geo
39
+}  // namespace util
40
+
41
+#endif  // UTIL_GEO_LINE_H_

+ 35 - 0
src/util/geo/output/GeoGraphJsonOutput.h

@@ -0,0 +1,35 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_OUTPUT_GEOGRAPHJSONOUTPUT_H_
6
+#define UTIL_GEO_OUTPUT_GEOGRAPHJSONOUTPUT_H_
7
+
8
+#include <ostream>
9
+#include <string>
10
+#include "util/String.h"
11
+#include "util/geo/output/GeoJsonOutput.h"
12
+#include "util/graph/Graph.h"
13
+
14
+namespace util {
15
+namespace geo {
16
+namespace output {
17
+
18
+class GeoGraphJsonOutput {
19
+ public:
20
+  inline GeoGraphJsonOutput(){};
21
+  template <typename N, typename E>
22
+  void print(const util::graph::Graph<N, E>& outG, std::ostream& str);
23
+
24
+ private:
25
+  template <typename T>
26
+  Line<T> createLine(const util::geo::Point<T>& a,
27
+                     const util::geo::Point<T>& b);
28
+};
29
+
30
+#include "util/geo/output/GeoGraphJsonOutput.tpp"
31
+}
32
+}
33
+}
34
+
35
+#endif  // UTIL_GEO_OUTPUT_GEOGRAPHJSONOUTPUT_H_

+ 63 - 0
src/util/geo/output/GeoGraphJsonOutput.tpp

@@ -0,0 +1,63 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename T>
7
+Line<T> GeoGraphJsonOutput::createLine(const util::geo::Point<T>& a,
8
+                                       const util::geo::Point<T>& b) {
9
+  Line<T> ret;
10
+  ret.push_back(a);
11
+  ret.push_back(b);
12
+  return ret;
13
+}
14
+
15
+// _____________________________________________________________________________
16
+template <typename N, typename E>
17
+void GeoGraphJsonOutput::print(const util::graph::Graph<N, E>& outG,
18
+                               std::ostream& str) {
19
+  GeoJsonOutput _out(str);
20
+
21
+  // first pass, nodes
22
+  for (util::graph::Node<N, E>* n : outG.getNds()) {
23
+    if (!n->pl().getGeom()) continue;
24
+
25
+    json::Dict props{{"id", util::toString(n)},
26
+                     {"deg", util::toString(n->getDeg())},
27
+                     {"deg_out", util::toString(n->getOutDeg())},
28
+                     {"deg_in", util::toString(n->getInDeg())}};
29
+
30
+    auto addProps = n->pl().getAttrs();
31
+    props.insert(addProps.begin(), addProps.end());
32
+
33
+    _out.print(*n->pl().getGeom(), props);
34
+  }
35
+
36
+  // second pass, edges
37
+  for (graph::Node<N, E>* n : outG.getNds()) {
38
+    for (graph::Edge<N, E>* e : n->getAdjListOut()) {
39
+      // to avoid double output for undirected graphs
40
+      if (e->getFrom() != n) continue;
41
+      json::Dict props{{"from", util::toString(e->getFrom())},
42
+                       {"to", util::toString(e->getTo())},
43
+                       {"id", util::toString(e)}};
44
+
45
+      auto addProps = e->pl().getAttrs();
46
+      props.insert(addProps.begin(), addProps.end());
47
+
48
+      if (!e->pl().getGeom() || !e->pl().getGeom()->size()) {
49
+        if (e->getFrom()->pl().getGeom()) {
50
+          auto a = *e->getFrom()->pl().getGeom();
51
+          if (e->getTo()->pl().getGeom()) {
52
+            auto b = *e->getTo()->pl().getGeom();
53
+            _out.print(createLine(a, b), props);
54
+          }
55
+        }
56
+      } else {
57
+        _out.print(*e->pl().getGeom(), props);
58
+      }
59
+    }
60
+  }
61
+
62
+  _out.flush();
63
+}

+ 34 - 0
src/util/geo/output/GeoJsonOutput.cpp

@@ -0,0 +1,34 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+//
5
+#include "util/geo/output/GeoJsonOutput.h"
6
+
7
+using namespace util;
8
+using namespace geo;
9
+using namespace output;
10
+
11
+// _____________________________________________________________________________
12
+GeoJsonOutput::GeoJsonOutput(std::ostream& str) : _wr(&str, 10, true) {
13
+  _wr.obj();
14
+  _wr.keyVal("type", "FeatureCollection");
15
+  _wr.key("features");
16
+  _wr.arr();
17
+}
18
+
19
+// _____________________________________________________________________________
20
+GeoJsonOutput::GeoJsonOutput(std::ostream& str, json::Val attrs)
21
+    : _wr(&str, 10, true) {
22
+  _wr.obj();
23
+  _wr.keyVal("type", "FeatureCollection");
24
+  _wr.key("properties");
25
+  _wr.val(attrs);
26
+  _wr.key("features");
27
+  _wr.arr();
28
+}
29
+
30
+// _____________________________________________________________________________
31
+GeoJsonOutput::~GeoJsonOutput() { flush(); }
32
+
33
+// _____________________________________________________________________________
34
+void GeoJsonOutput::flush() { _wr.closeAll(); }

+ 40 - 0
src/util/geo/output/GeoJsonOutput.h

@@ -0,0 +1,40 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GEO_OUTPUT_GEOJSONOUTPUT_H_
6
+#define UTIL_GEO_OUTPUT_GEOJSONOUTPUT_H_
7
+
8
+#include <ostream>
9
+#include <string>
10
+#include <map>
11
+#include "util/String.h"
12
+#include "util/geo/Geo.h"
13
+#include "util/json/Writer.h"
14
+
15
+namespace util {
16
+namespace geo {
17
+namespace output {
18
+
19
+class GeoJsonOutput {
20
+ public:
21
+  GeoJsonOutput(std::ostream& str);
22
+  GeoJsonOutput(std::ostream& str, json::Val attrs);
23
+  ~GeoJsonOutput();
24
+  template <typename T>
25
+  void print(const Point<T>& p, json::Val attrs);
26
+  template <typename T>
27
+  void print(const Line<T>& l, json::Val attrs);
28
+  void flush();
29
+
30
+ private:
31
+  json::Writer _wr;
32
+};
33
+
34
+#include "util/geo/output/GeoJsonOutput.tpp"
35
+
36
+}
37
+}
38
+}
39
+
40
+#endif  // UTIL_GEO_OUTPUT_GEOJSONOUTPUT_H_

+ 48 - 0
src/util/geo/output/GeoJsonOutput.tpp

@@ -0,0 +1,48 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename T>
7
+void GeoJsonOutput::print(const Point<T>& p, json::Val attrs) {
8
+  _wr.obj();
9
+  _wr.keyVal("type", "Feature");
10
+
11
+  _wr.key("geometry");
12
+  _wr.obj();
13
+  _wr.keyVal("type", "Point");
14
+  _wr.key("coordinates");
15
+  _wr.arr();
16
+  _wr.val(p.getX());
17
+  _wr.val(p.getY());
18
+  _wr.close();
19
+  _wr.close();
20
+  _wr.key("properties");
21
+  _wr.val(attrs);
22
+  _wr.close();
23
+}
24
+
25
+// _____________________________________________________________________________
26
+template <typename T>
27
+void GeoJsonOutput::print(const Line<T>& line, json::Val attrs) {
28
+  if (!line.size()) return;
29
+  _wr.obj();
30
+  _wr.keyVal("type", "Feature");
31
+
32
+  _wr.key("geometry");
33
+  _wr.obj();
34
+  _wr.keyVal("type", "LineString");
35
+  _wr.key("coordinates");
36
+  _wr.arr();
37
+  for (auto p : line) {
38
+    _wr.arr();
39
+    _wr.val(p.getX());
40
+    _wr.val(p.getY());
41
+    _wr.close();
42
+  }
43
+  _wr.close();
44
+  _wr.close();
45
+  _wr.key("properties");
46
+  _wr.val(attrs);
47
+  _wr.close();
48
+}

+ 33 - 0
src/util/graph/Algorithm.h

@@ -0,0 +1,33 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_ALGORITHM_H_
6
+#define UTIL_GRAPH_ALGORITHM_H_
7
+
8
+#include <stack>
9
+#include "util/graph/Edge.h"
10
+#include "util/graph/UndirGraph.h"
11
+#include "util/graph/Node.h"
12
+
13
+namespace util {
14
+namespace graph {
15
+
16
+using util::graph::Graph;
17
+using util::graph::Node;
18
+using util::graph::Edge;
19
+
20
+// collection of general graph algorithms
21
+class Algorithm {
22
+ public:
23
+  template <typename N, typename E>
24
+  static std::vector<std::set<Node<N, E>*> > connectedComponents(
25
+      const UndirGraph<N, E>& g);
26
+};
27
+
28
+#include "util/graph/Algorithm.tpp"
29
+
30
+}
31
+}
32
+
33
+#endif  // UTIL_GRAPH_ALGORITHM_H_

+ 32 - 0
src/util/graph/Algorithm.tpp

@@ -0,0 +1,32 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+std::vector<std::set<Node<N, E>*> > Algorithm::connectedComponents(
8
+    const UndirGraph<N, E>& g) {
9
+  std::vector<std::set<Node<N, E>*>> ret;
10
+  std::set<Node<N, E>*> visited;
11
+
12
+  for (auto* n : g.getNds()) {
13
+    if (!visited.count(n)) {
14
+      ret.resize(ret.size() + 1);
15
+      std::stack<Node<N, E>*> q;
16
+      q.push(n);
17
+      while (!q.empty()) {
18
+        Node<N, E>* cur = q.top();
19
+        q.pop();
20
+
21
+        ret.back().insert(cur);
22
+        visited.insert(cur);
23
+
24
+        for (auto* e : cur->getAdjList()) {
25
+          if (!visited.count(e->getOtherNd(cur))) q.push(e->getOtherNd(cur));
26
+        }
27
+      }
28
+    }
29
+  }
30
+
31
+  return ret;
32
+}

+ 7 - 0
src/util/graph/Dijkstra.cpp

@@ -0,0 +1,7 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include "util/graph/Dijkstra.h"
6
+
7
+size_t util::graph::Dijkstra::ITERS = 0;

+ 113 - 0
src/util/graph/Dijkstra.h

@@ -0,0 +1,113 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_DIJKSTRA_H_
6
+#define UTIL_GRAPH_DIJKSTRA_H_
7
+
8
+#include <limits>
9
+#include <list>
10
+#include <queue>
11
+#include <set>
12
+#include <set>
13
+#include <unordered_map>
14
+#include "util/graph/Edge.h"
15
+#include "util/graph/Graph.h"
16
+#include "util/graph/Node.h"
17
+#include "util/graph/ShortestPath.h"
18
+
19
+namespace util {
20
+namespace graph {
21
+
22
+using util::graph::Graph;
23
+using util::graph::Node;
24
+using util::graph::Edge;
25
+
26
+// dijkstras algorithm for util graph
27
+class Dijkstra : public ShortestPath<Dijkstra> {
28
+ public:
29
+  template <typename N, typename E, typename C>
30
+  struct RouteNode {
31
+    RouteNode() : n(0), parent(0), d(), h(), e(0) {}
32
+    RouteNode(Node<N, E>* n) : n(n), parent(0), d(), h(), e(0) {}
33
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, Edge<N, E>* e)
34
+        : n(n), parent(parent), d(d), h(), e(e) {}
35
+    RouteNode(Node<N, E>* n, Node<N, E>* parent, C d, C h, Edge<N, E>* e)
36
+        : n(n), parent(parent), d(d), h(h), e(e) {}
37
+
38
+    Node<N, E>* n;
39
+    Node<N, E>* parent;
40
+
41
+    C d;
42
+    C h;
43
+
44
+    Edge<N, E>* e;
45
+
46
+    bool operator<(const RouteNode<N, E, C>& p) const {
47
+      return h > p.h || (h == p.h && d > p.d);
48
+    }
49
+  };
50
+
51
+  template <typename N, typename E, typename C>
52
+  using Settled = std::unordered_map<Node<N, E>*, RouteNode<N, E, C> >;
53
+
54
+  template <typename N, typename E, typename C>
55
+  using PQ = std::priority_queue<RouteNode<N, E, C> >;
56
+
57
+  template <typename N, typename E, typename C>
58
+  struct CostFunc : public ShortestPath::CostFunc<N, E, C> {
59
+    C operator()(const Edge<N, E>* from, const Node<N, E>* n,
60
+                 const Edge<N, E>* to) const {
61
+      UNUSED(from);
62
+      UNUSED(n);
63
+      UNUSED(to);
64
+      return C();
65
+    };
66
+  };
67
+
68
+  template <typename N, typename E, typename C>
69
+  struct HeurFunc : public ShortestPath::HeurFunc<N, E, C> {
70
+    C operator()(const Edge<N, E>* from,
71
+                 const std::set<Edge<N, E>*>& to) const {
72
+      UNUSED(from);
73
+      UNUSED(to);
74
+      return C();
75
+    };
76
+  };
77
+
78
+  template <typename N, typename E, typename C>
79
+  static std::unordered_map<Node<N, E>*, C> shortestPathImpl(
80
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
81
+      const ShortestPath::CostFunc<N, E, C>& costFunc, const ShortestPath::HeurFunc<N, E, C>&,
82
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
83
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNode);
84
+
85
+  template <typename N, typename E, typename C>
86
+  static C shortestPathImpl(const std::set<Node<N, E>*> from, const std::set<Node<N, E>*>& to,
87
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
88
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
89
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
90
+
91
+  template <typename N, typename E, typename C>
92
+  static C shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
93
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
94
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
95
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
96
+
97
+  template <typename N, typename E, typename C>
98
+  static void relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
99
+                    const ShortestPath::CostFunc<N, E, C>& costFunc,
100
+                    const ShortestPath::HeurFunc<N, E, C>& heurFunc, PQ<N, E, C>& pq);
101
+
102
+  template <typename N, typename E, typename C>
103
+  static void buildPath(Node<N, E>* curN, Settled<N, E, C>& settled,
104
+                        NList<N, E>* resNodes, EList<N, E>* resEdges);
105
+
106
+  static size_t ITERS;
107
+};
108
+
109
+#include "util/graph/Dijkstra.tpp"
110
+}
111
+}
112
+
113
+#endif  // UTIL_GRAPH_DIJKSTRA_H_

+ 175 - 0
src/util/graph/Dijkstra.tpp

@@ -0,0 +1,175 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E, typename C>
7
+C Dijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
8
+                             const ShortestPath::CostFunc<N, E, C>& costFunc,
9
+                             const ShortestPath::HeurFunc<N, E, C>& heurFunc,
10
+                             EList<N, E>* resEdges, NList<N, E>* resNodes) {
11
+  if (from->getOutDeg() == 0) return costFunc.inf();
12
+
13
+  Settled<N, E, C> settled;
14
+  PQ<N, E, C> pq;
15
+  bool found = false;
16
+
17
+  pq.emplace(from);
18
+  RouteNode<N, E, C> cur;
19
+
20
+  while (!pq.empty()) {
21
+    Dijkstra::ITERS++;
22
+
23
+    if (settled.find(pq.top().n) != settled.end()) {
24
+      pq.pop();
25
+      continue;
26
+    }
27
+
28
+    cur = pq.top();
29
+    pq.pop();
30
+
31
+    settled[cur.n] = cur;
32
+
33
+    if (to.find(cur.n) != to.end()) {
34
+      found = true;
35
+      break;
36
+    }
37
+
38
+    relax(cur, to, costFunc, heurFunc, pq);
39
+  }
40
+
41
+  if (!found) return costFunc.inf();
42
+
43
+  buildPath(cur.n, settled, resNodes, resEdges);
44
+
45
+  return cur.d;
46
+}
47
+
48
+// _____________________________________________________________________________
49
+template <typename N, typename E, typename C>
50
+C Dijkstra::shortestPathImpl(const std::set<Node<N, E>*> from,
51
+                             const std::set<Node<N, E>*>& to,
52
+                             const ShortestPath::CostFunc<N, E, C>& costFunc,
53
+                             const ShortestPath::HeurFunc<N, E, C>& heurFunc,
54
+                             EList<N, E>* resEdges, NList<N, E>* resNodes) {
55
+  Settled<N, E, C> settled;
56
+  PQ<N, E, C> pq;
57
+  bool found = false;
58
+
59
+  // put all nodes in from onto PQ
60
+  for (auto n : from) pq.emplace(n);
61
+  RouteNode<N, E, C> cur;
62
+
63
+  while (!pq.empty()) {
64
+    Dijkstra::ITERS++;
65
+
66
+    if (settled.find(pq.top().n) != settled.end()) {
67
+      pq.pop();
68
+      continue;
69
+    }
70
+
71
+    cur = pq.top();
72
+    pq.pop();
73
+
74
+    settled[cur.n] = cur;
75
+
76
+    if (to.find(cur.n) != to.end()) {
77
+      found = true;
78
+      break;
79
+    }
80
+
81
+    relax(cur, to, costFunc, heurFunc, pq);
82
+  }
83
+
84
+  if (!found) return costFunc.inf();
85
+
86
+  buildPath(cur.n, settled, resNodes, resEdges);
87
+
88
+  return cur.d;
89
+}
90
+
91
+// _____________________________________________________________________________
92
+template <typename N, typename E, typename C>
93
+std::unordered_map<Node<N, E>*, C> Dijkstra::shortestPathImpl(
94
+    Node<N, E>* from, const std::set<Node<N, E>*>& to,
95
+    const ShortestPath::CostFunc<N, E, C>& costFunc,
96
+    const ShortestPath::HeurFunc<N, E, C>& heurFunc,
97
+    std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
98
+    std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
99
+  std::unordered_map<Node<N, E>*, C> costs;
100
+  if (to.size() == 0) return costs;
101
+  // init costs with inf
102
+  for (auto n : to) costs[n] = costFunc.inf();
103
+
104
+  if (from->getOutDeg() == 0) return costs;
105
+
106
+  Settled<N, E, C> settled;
107
+  PQ<N, E, C> pq;
108
+
109
+  size_t found = 0;
110
+
111
+  pq.emplace(from);
112
+  RouteNode<N, E, C> cur;
113
+
114
+  while (!pq.empty()) {
115
+    Dijkstra::ITERS++;
116
+
117
+    if (settled.find(pq.top().n) != settled.end()) {
118
+      pq.pop();
119
+      continue;
120
+    }
121
+
122
+    cur = pq.top();
123
+    pq.pop();
124
+
125
+    settled[cur.n] = cur;
126
+
127
+    if (to.find(cur.n) != to.end()) {
128
+      found++;
129
+    }
130
+
131
+    if (found == to.size()) break;
132
+
133
+    relax(cur, to, costFunc, heurFunc, pq);
134
+  }
135
+
136
+  for (auto nto : to) {
137
+    if (!settled.count(nto)) continue;
138
+    Node<N, E>* curN = nto;
139
+    costs[nto] = settled[curN].d;
140
+
141
+    buildPath(nto, settled, resNodes[nto], resEdges[nto]);
142
+  }
143
+
144
+  return costs;
145
+}
146
+
147
+// _____________________________________________________________________________
148
+template <typename N, typename E, typename C>
149
+void Dijkstra::relax(RouteNode<N, E, C>& cur, const std::set<Node<N, E>*>& to,
150
+                     const ShortestPath::CostFunc<N, E, C>& costFunc,
151
+                     const ShortestPath::HeurFunc<N, E, C>& heurFunc, PQ<N, E, C>& pq) {
152
+  for (auto edge : cur.n->getAdjListOut()) {
153
+    C newC = costFunc(cur.n, edge, edge->getOtherNd(cur.n));
154
+    newC = cur.d + newC;
155
+    if (costFunc.inf() <= newC) continue;
156
+
157
+    const C& newH = newC + heurFunc(edge->getOtherNd(cur.n), to);
158
+
159
+    pq.emplace(edge->getOtherNd(cur.n), cur.n, newC, newH, &(*edge));
160
+  }
161
+}
162
+
163
+// _____________________________________________________________________________
164
+template <typename N, typename E, typename C>
165
+void Dijkstra::buildPath(Node<N, E>* curN,
166
+                         Settled<N, E, C>& settled, NList<N, E>* resNodes,
167
+                         EList<N, E>* resEdges) {
168
+  while (true) {
169
+    const RouteNode<N, E, C>& curNode = settled[curN];
170
+    if (resNodes) resNodes->push_back(curNode.n);
171
+    if (!curNode.parent) break;
172
+    if (resEdges) resEdges->push_back(curNode.e);
173
+    curN = curNode.parent;
174
+  }
175
+}

+ 41 - 0
src/util/graph/DirGraph.h

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_DIRGRAPH_H_
6
+#define UTIL_GRAPH_DIRGRAPH_H_
7
+
8
+#include <set>
9
+#include <string>
10
+
11
+#include "util/graph/Graph.h"
12
+#include "util/graph/Edge.h"
13
+#include "util/graph/DirNode.h"
14
+
15
+namespace util {
16
+namespace graph {
17
+
18
+template <typename N, typename E>
19
+using UndirEdge = Edge<N, E>;
20
+
21
+template <typename N, typename E>
22
+class DirGraph : public Graph<N, E> {
23
+ public:
24
+  explicit DirGraph();
25
+
26
+  using Graph<N, E>::addEdg;
27
+
28
+  Node<N, E>* addNd();
29
+  Node<N, E>* addNd(DirNode<N, E>* n);
30
+  Node<N, E>* addNd(const N& pl);
31
+  Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p);
32
+
33
+  Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b);
34
+
35
+};
36
+
37
+#include "util/graph/DirGraph.tpp"
38
+}
39
+}
40
+
41
+#endif  // UTIL_GRAPH_DIRGRAPH_H_

+ 59 - 0
src/util/graph/DirGraph.tpp

@@ -0,0 +1,59 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+DirGraph<N, E>::DirGraph() {}
8
+
9
+// _____________________________________________________________________________
10
+template <typename N, typename E>
11
+Node<N, E>* DirGraph<N, E>::addNd(const N& pl) {
12
+  return addNd(new DirNode<N, E>(pl));
13
+}
14
+
15
+// _____________________________________________________________________________
16
+template <typename N, typename E>
17
+Node<N, E>* DirGraph<N, E>::addNd() {
18
+  return addNd(new DirNode<N, E>());
19
+}
20
+
21
+// _____________________________________________________________________________
22
+template <typename N, typename E>
23
+Node<N, E>* DirGraph<N, E>::addNd(DirNode<N, E>* n) {
24
+  auto ins = Graph<N, E>::getNds()->insert(n);
25
+  return *ins.first;
26
+}
27
+
28
+// _____________________________________________________________________________
29
+template <typename N, typename E>
30
+Edge<N, E>* DirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to,
31
+                                    const E& p) {
32
+  Edge<N, E>* e = Graph<N, E>::getEdg(from, to);
33
+  if (!e) {
34
+    e = new Edge<N, E>(from, to, p);
35
+    from->addEdge(e);
36
+    to->addEdge(e);
37
+  }
38
+  return e;
39
+}
40
+
41
+// _____________________________________________________________________________
42
+template <typename N, typename E>
43
+Node<N, E>* DirGraph<N, E>::mergeNds(Node<N, E>* a, Node<N, E>* b) {
44
+  for (auto e : a->getAdjListOut()) {
45
+    if (e->getTo() != b) {
46
+      addEdg(b, e->getTo(), e->pl());
47
+    }
48
+  }
49
+
50
+  for (auto e : a->getAdjListIn()) {
51
+    if (e->getFrom() != b) {
52
+      addEdg(e->getFrom(), b, e->pl());
53
+    }
54
+  }
55
+
56
+  DirGraph<N, E>::delNd(a);
57
+
58
+  return b;
59
+}

+ 58 - 0
src/util/graph/DirNode.h

@@ -0,0 +1,58 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_DIRNODE_H_
6
+#define UTIL_GRAPH_DIRNODE_H_
7
+
8
+#include <vector>
9
+#include <algorithm>
10
+#include "util/graph/Node.h"
11
+
12
+namespace util {
13
+namespace graph {
14
+
15
+// forward declaration of Edge
16
+
17
+template <typename N, typename E>
18
+class DirNode : public Node<N, E> {
19
+ public:
20
+  DirNode();
21
+  DirNode(const N& pl);
22
+  ~DirNode();
23
+
24
+  const std::vector<Edge<N, E>*>& getAdjList() const;
25
+  const std::vector<Edge<N, E>*>& getAdjListIn() const;
26
+  const std::vector<Edge<N, E>*>& getAdjListOut() const;
27
+
28
+  size_t getDeg() const;
29
+  size_t getInDeg() const;
30
+  size_t getOutDeg() const;
31
+
32
+  bool hasEdgeIn(const Edge<N, E>* e) const;
33
+  bool hasEdgeOut(const Edge<N, E>* e) const;
34
+  bool hasEdge(const Edge<N, E>* e) const;
35
+
36
+  // add edge to this node's adjacency lists
37
+  void addEdge(Edge<N, E>* e);
38
+
39
+  // remove edge from this node's adjacency lists
40
+  void removeEdge(Edge<N, E>* e);
41
+
42
+  N& pl();
43
+  const N& pl() const;
44
+
45
+ private:
46
+  std::vector<Edge<N, E>*> _adjListIn;
47
+  std::vector<Edge<N, E>*> _adjListOut;
48
+  N _pl;
49
+
50
+  bool adjInContains(const Edge<N, E>* e) const;
51
+  bool adjOutContains(const Edge<N, E>* e) const;
52
+};
53
+
54
+#include "util/graph/DirNode.tpp"
55
+
56
+}}
57
+
58
+#endif  // UTIL_GRAPH_DIRNODE_H_

+ 153 - 0
src/util/graph/DirNode.tpp

@@ -0,0 +1,153 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+DirNode<N, E>::DirNode() : _pl() {}
8
+
9
+// _____________________________________________________________________________
10
+template <typename N, typename E>
11
+DirNode<N, E>::DirNode(const N& pl) : _pl(pl) {}
12
+
13
+// _____________________________________________________________________________
14
+template <typename N, typename E>
15
+DirNode<N, E>::~DirNode() {
16
+  // delete self edges
17
+  for (auto e = _adjListOut.begin(); e != _adjListOut.end();) {
18
+    Edge<N, E>* eP = *e;
19
+    if (eP->getTo() == this) {
20
+      _adjListIn.erase(std::find(_adjListIn.begin(), _adjListIn.end(), eP));
21
+      e = _adjListOut.erase(e);
22
+      delete eP;
23
+    } else {
24
+      e++;
25
+    }
26
+  }
27
+
28
+  for (auto e = _adjListOut.begin(); e != _adjListOut.end(); e++) {
29
+    Edge<N, E>* eP = *e;
30
+
31
+    if (eP->getTo() != this) {
32
+      eP->getTo()->removeEdge(eP);
33
+      delete eP;
34
+    }
35
+  }
36
+
37
+  for (auto e = _adjListIn.begin(); e != _adjListIn.end(); e++) {
38
+    Edge<N, E>* eP = *e;
39
+
40
+    if (eP->getFrom() != this) {
41
+      eP->getFrom()->removeEdge(eP);
42
+      delete eP;
43
+    }
44
+  }
45
+}
46
+
47
+// _____________________________________________________________________________
48
+template <typename N, typename E>
49
+void DirNode<N, E>::addEdge(Edge<N, E>* e) {
50
+  if (e->getFrom() == this && !adjOutContains(e)) {
51
+    _adjListOut.reserve(_adjListOut.size() + 1);
52
+    _adjListOut.push_back(e);
53
+  }
54
+  if (e->getTo() == this && !adjInContains(e)) {
55
+    _adjListIn.reserve(_adjListIn.size() + 1);
56
+    _adjListIn.push_back(e);
57
+  }
58
+}
59
+
60
+// _____________________________________________________________________________
61
+template <typename N, typename E>
62
+void DirNode<N, E>::removeEdge(Edge<N, E>* e) {
63
+  if (e->getFrom() == this) {
64
+    auto p = std::find(_adjListOut.begin(), _adjListOut.end(), e);
65
+    if (p != _adjListOut.end()) _adjListOut.erase(p);
66
+  }
67
+  if (e->getTo() == this) {
68
+    auto p = std::find(_adjListIn.begin(), _adjListIn.end(), e);
69
+    if (p != _adjListIn.end()) _adjListIn.erase(p);
70
+  }
71
+}
72
+//
73
+// _____________________________________________________________________________
74
+template <typename N, typename E>
75
+bool DirNode<N, E>::hasEdgeIn(const Edge<N, E>* e) const {
76
+  return e->getTo() == this;
77
+}
78
+
79
+// _____________________________________________________________________________
80
+template <typename N, typename E>
81
+bool DirNode<N, E>::hasEdgeOut(const Edge<N, E>* e) const {
82
+  return e->getFrom() == this;
83
+}
84
+
85
+// _____________________________________________________________________________
86
+template <typename N, typename E>
87
+bool DirNode<N, E>::hasEdge(const Edge<N, E>* e) const {
88
+  return hasEdgeOut(e) || hasEdgeIn(e);
89
+}
90
+
91
+// _____________________________________________________________________________
92
+template <typename N, typename E>
93
+const std::vector<Edge<N, E>*>& DirNode<N, E>::getAdjList() const {
94
+  return _adjListOut;
95
+}
96
+
97
+// _____________________________________________________________________________
98
+template <typename N, typename E>
99
+const std::vector<Edge<N, E>*>& DirNode<N, E>::getAdjListOut() const {
100
+  return _adjListOut;
101
+}
102
+
103
+// _____________________________________________________________________________
104
+template <typename N, typename E>
105
+const std::vector<Edge<N, E>*>& DirNode<N, E>::getAdjListIn() const {
106
+  return _adjListIn;
107
+}
108
+
109
+// _____________________________________________________________________________
110
+template <typename N, typename E>
111
+size_t DirNode<N, E>::getDeg() const {
112
+  return _adjListOut.size();
113
+}
114
+
115
+// _____________________________________________________________________________
116
+template <typename N, typename E>
117
+size_t DirNode<N, E>::getInDeg() const {
118
+  return _adjListIn.size();
119
+}
120
+
121
+// _____________________________________________________________________________
122
+template <typename N, typename E>
123
+size_t DirNode<N, E>::getOutDeg() const {
124
+  return _adjListOut.size();
125
+}
126
+
127
+// _____________________________________________________________________________
128
+template <typename N, typename E>
129
+N& DirNode<N, E>::pl() {
130
+  return _pl;
131
+}
132
+
133
+// _____________________________________________________________________________
134
+template <typename N, typename E>
135
+const N& DirNode<N, E>::pl() const {
136
+  return _pl;
137
+}
138
+
139
+// _____________________________________________________________________________
140
+template <typename N, typename E>
141
+bool DirNode<N, E>::adjInContains(const Edge<N, E>* e) const {
142
+  for (size_t i = 0; i < _adjListIn.size(); i++)
143
+    if (_adjListIn[i] == e) return true;
144
+  return false;
145
+}
146
+
147
+// _____________________________________________________________________________
148
+template <typename N, typename E>
149
+bool DirNode<N, E>::adjOutContains(const Edge<N, E>* e) const {
150
+  for (size_t i = 0; i < _adjListOut.size(); i++)
151
+    if (_adjListOut[i] == e) return true;
152
+  return false;
153
+}

+ 7 - 0
src/util/graph/EDijkstra.cpp

@@ -0,0 +1,7 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include "util/graph/EDijkstra.h"
6
+
7
+size_t util::graph::EDijkstra::ITERS = 0;

+ 139 - 0
src/util/graph/EDijkstra.h

@@ -0,0 +1,139 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_EDIJKSTRA_H_
6
+#define UTIL_GRAPH_EDIJKSTRA_H_
7
+
8
+#include <limits>
9
+#include <list>
10
+#include <queue>
11
+#include <set>
12
+#include <unordered_map>
13
+#include "util/graph/Edge.h"
14
+#include "util/graph/Graph.h"
15
+#include "util/graph/Node.h"
16
+#include "util/graph/ShortestPath.h"
17
+
18
+namespace util {
19
+namespace graph {
20
+
21
+using util::graph::Graph;
22
+using util::graph::Node;
23
+using util::graph::Edge;
24
+
25
+// edge-based dijkstra - settles edges instead of nodes
26
+class EDijkstra : public ShortestPath<EDijkstra> {
27
+ public:
28
+  template <typename N, typename E, typename C>
29
+  struct RouteEdge {
30
+    RouteEdge() : e(0), parent(0), d(), h(), n(0) {}
31
+    RouteEdge(Edge<N, E>* e) : e(e), parent(0), d(), h(), n(0) {}
32
+    RouteEdge(Edge<N, E>* e, Edge<N, E>* parent, Node<N, E>* n, C d)
33
+        : e(e), parent(parent), d(d), h(), n(n) {}
34
+    RouteEdge(Edge<N, E>* e, Edge<N, E>* parent, Node<N, E>* n, C d, C h)
35
+        : e(e), parent(parent), d(d), h(h), n(n) {}
36
+
37
+    Edge<N, E>* e;
38
+    Edge<N, E>* parent;
39
+
40
+    C d;
41
+    C h;
42
+
43
+    Node<N, E>* n;
44
+
45
+    bool operator<(const RouteEdge<N, E, C>& p) const {
46
+      return h > p.h || (h == p.h && d > p.d);
47
+    }
48
+  };
49
+
50
+  template <typename N, typename E, typename C>
51
+  struct CostFunc : public ShortestPath::CostFunc<N, E, C> {
52
+    C operator()(const Node<N, E>* from, const Edge<N, E>* e,
53
+                 const Node<N, E>* to) const {
54
+      UNUSED(from);
55
+      UNUSED(e);
56
+      UNUSED(to);
57
+      return C();
58
+    };
59
+  };
60
+
61
+  template <typename N, typename E, typename C>
62
+  struct HeurFunc : public ShortestPath::HeurFunc<N, E, C> {
63
+    C operator()(const Node<N, E>* from,
64
+                 const std::set<Node<N, E>*>& to) const {
65
+      UNUSED(from);
66
+      UNUSED(to);
67
+      return C();
68
+    };
69
+  };
70
+
71
+  template <typename N, typename E, typename C>
72
+  using Settled = std::unordered_map<Edge<N, E>*, RouteEdge<N, E, C> >;
73
+
74
+  template <typename N, typename E, typename C>
75
+  using PQ = std::priority_queue<RouteEdge<N, E, C> >;
76
+
77
+  template <typename N, typename E, typename C>
78
+  static C shortestPathImpl(const std::set<Edge<N, E>*> from,
79
+                            const std::set<Edge<N, E>*>& to,
80
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
81
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
82
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
83
+
84
+  template <typename N, typename E, typename C>
85
+  static C shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
86
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
87
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
88
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
89
+
90
+  template <typename N, typename E, typename C>
91
+  static C shortestPathImpl(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
92
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
93
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
94
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
95
+
96
+  template <typename N, typename E, typename C>
97
+  static C shortestPathImpl(const std::set<Edge<N, E>*>& from,
98
+                            const std::set<Node<N, E>*>& to,
99
+                            const ShortestPath::CostFunc<N, E, C>& costFunc,
100
+                            const ShortestPath::HeurFunc<N, E, C>& heurFunc,
101
+                            EList<N, E>* resEdges, NList<N, E>* resNodes);
102
+
103
+  template <typename N, typename E, typename C>
104
+  static std::unordered_map<Edge<N, E>*, C> shortestPathImpl(
105
+      const std::set<Edge<N, E>*>& from,
106
+      const ShortestPath::CostFunc<N, E, C>& costFunc, bool rev);
107
+
108
+  template <typename N, typename E, typename C>
109
+  static std::unordered_map<Edge<N, E>*, C> shortestPathImpl(
110
+      Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
111
+      const ShortestPath::CostFunc<N, E, C>& costFunc,
112
+      const ShortestPath::HeurFunc<N, E, C>& heurFunc,
113
+      std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
114
+      std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes);
115
+
116
+  template <typename N, typename E, typename C>
117
+  static void buildPath(Edge<N, E>* curE, const Settled<N, E, C>& settled,
118
+                        NList<N, E>* resNodes, EList<N, E>* resEdges);
119
+
120
+  template <typename N, typename E, typename C>
121
+  static inline void relax(RouteEdge<N, E, C>& cur,
122
+                           const std::set<Edge<N, E>*>& to,
123
+                           const ShortestPath::CostFunc<N, E, C>& costFunc,
124
+                           const ShortestPath::HeurFunc<N, E, C>& heurFunc,
125
+                           PQ<N, E, C>& pq);
126
+
127
+  template <typename N, typename E, typename C>
128
+  static void relaxInv(RouteEdge<N, E, C>& cur,
129
+                      const ShortestPath::CostFunc<N, E, C>& costFunc,
130
+                      PQ<N, E, C>& pq);
131
+
132
+  static size_t ITERS;
133
+};
134
+
135
+#include "util/graph/EDijkstra.tpp"
136
+}
137
+}
138
+
139
+#endif  // UTIL_GRAPH_DIJKSTRA_H_

+ 258 - 0
src/util/graph/EDijkstra.tpp

@@ -0,0 +1,258 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E, typename C>
7
+C EDijkstra::shortestPathImpl(Node<N, E>* from, const std::set<Node<N, E>*>& to,
8
+                              const ShortestPath::CostFunc<N, E, C>& costFunc,
9
+                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
10
+                              EList<N, E>* resEdges, NList<N, E>* resNodes) {
11
+  std::set<Edge<N, E>*> frEs;
12
+  std::set<Edge<N, E>*> toEs;
13
+
14
+  frEs.insert(from->getAdjListOut().begin(), from->getAdjListOut().end());
15
+
16
+  for (auto n : to) {
17
+    toEs.insert(n->getAdjListIn().begin(), n->getAdjListIn().end());
18
+  }
19
+
20
+  C cost = shortestPathImpl(frEs, toEs, costFunc, heurFunc, resEdges, resNodes);
21
+
22
+  // the beginning node is not included in our edge based dijkstra
23
+  if (resNodes) resNodes->push_back(from);
24
+
25
+  return cost;
26
+}
27
+
28
+// _____________________________________________________________________________
29
+template <typename N, typename E, typename C>
30
+C EDijkstra::shortestPathImpl(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
31
+                              const ShortestPath::CostFunc<N, E, C>& costFunc,
32
+                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
33
+                              EList<N, E>* resEdges, NList<N, E>* resNodes) {
34
+  std::set<Edge<N, E>*> frEs;
35
+  std::set<Edge<N, E>*> toEs;
36
+
37
+  frEs.insert(from);
38
+
39
+  for (auto n : to) {
40
+    toEs.insert(n->getAdjListIn().begin(), n->getAdjListIn().end());
41
+  }
42
+
43
+  C cost = shortestPathImpl(frEs, toEs, costFunc, heurFunc, resEdges, resNodes);
44
+
45
+  return cost;
46
+}
47
+
48
+// _____________________________________________________________________________
49
+template <typename N, typename E, typename C>
50
+C EDijkstra::shortestPathImpl(const std::set<Edge<N, E>*> from,
51
+                              const std::set<Edge<N, E>*>& to,
52
+                              const ShortestPath::CostFunc<N, E, C>& costFunc,
53
+                              const ShortestPath::HeurFunc<N, E, C>& heurFunc,
54
+                              EList<N, E>* resEdges, NList<N, E>* resNodes) {
55
+  if (from.size() == 0 || to.size() == 0) return costFunc.inf();
56
+
57
+  Settled<N, E, C> settled;
58
+  PQ<N, E, C> pq;
59
+  bool found = false;
60
+
61
+  // at the beginning, put all edges on the priority queue,
62
+  // init them with their own cost
63
+  for (auto e : from) {
64
+    C c = costFunc(0, 0, e);
65
+    C h = heurFunc(e, to);
66
+    pq.emplace(e, (Edge<N, E>*)0, (Node<N, E>*)0, c, c + h);
67
+  }
68
+
69
+  RouteEdge<N, E, C> cur;
70
+
71
+  while (!pq.empty()) {
72
+    EDijkstra::ITERS++;
73
+
74
+    if (settled.find(pq.top().e) != settled.end()) {
75
+      pq.pop();
76
+      continue;
77
+    }
78
+
79
+    cur = pq.top();
80
+    pq.pop();
81
+
82
+    settled[cur.e] = cur;
83
+
84
+    if (to.find(cur.e) != to.end()) {
85
+      found = true;
86
+      break;
87
+    }
88
+
89
+    relax(cur, to, costFunc, heurFunc, pq);
90
+  }
91
+
92
+  if (!found) return costFunc.inf();
93
+
94
+  buildPath(cur.e, settled, resNodes, resEdges);
95
+
96
+  return cur.d;
97
+}
98
+
99
+// _____________________________________________________________________________
100
+template <typename N, typename E, typename C>
101
+std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
102
+    const std::set<Edge<N, E>*>& from, const ShortestPath::CostFunc<N, E, C>& costFunc,
103
+    bool rev) {
104
+  std::unordered_map<Edge<N, E>*, C> costs;
105
+
106
+  Settled<N, E, C> settled;
107
+  PQ<N, E, C> pq;
108
+
109
+  std::set<Edge<N, E>*> to;
110
+
111
+  for (auto e : from) {
112
+    pq.emplace(e, (Edge<N, E>*)0, (Node<N, E>*)0, costFunc(0, 0, e), C());
113
+  }
114
+
115
+  RouteEdge<N, E, C> cur;
116
+
117
+  while (!pq.empty()) {
118
+    EDijkstra::ITERS++;
119
+
120
+    if (settled.find(pq.top().e) != settled.end()) {
121
+      pq.pop();
122
+      continue;
123
+    }
124
+
125
+    cur = pq.top();
126
+    pq.pop();
127
+
128
+    settled[cur.e] = cur;
129
+
130
+    costs[cur.e] = cur.d;
131
+    buildPath(cur.e, settled, (NList<N, E>*)0, (EList<N, E>*)0);
132
+
133
+    if (rev)
134
+      relaxInv(cur, costFunc, pq);
135
+    else
136
+      relax(cur, to, costFunc, ZeroHeurFunc<N, E, C>(), pq);
137
+  }
138
+
139
+  return costs;
140
+}
141
+
142
+// _____________________________________________________________________________
143
+template <typename N, typename E, typename C>
144
+std::unordered_map<Edge<N, E>*, C> EDijkstra::shortestPathImpl(
145
+    Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
146
+    const ShortestPath::CostFunc<N, E, C>& costFunc,
147
+    const ShortestPath::HeurFunc<N, E, C>& heurFunc,
148
+    std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
149
+    std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes) {
150
+  std::unordered_map<Edge<N, E>*, C> costs;
151
+  if (to.size() == 0) return costs;
152
+
153
+  // init costs with inf
154
+  for (auto e : to) costs[e] = costFunc.inf();
155
+
156
+  Settled<N, E, C> settled;
157
+  PQ<N, E, C> pq;
158
+
159
+  size_t found = 0;
160
+
161
+  C c = costFunc(0, 0, from);
162
+  C h = heurFunc(from, to);
163
+  pq.emplace(from, (Edge<N, E>*)0, (Node<N, E>*)0, c, c + h);
164
+
165
+  RouteEdge<N, E, C> cur;
166
+
167
+  while (!pq.empty()) {
168
+    EDijkstra::ITERS++;
169
+
170
+    if (settled.find(pq.top().e) != settled.end()) {
171
+      pq.pop();
172
+      continue;
173
+    }
174
+
175
+    cur = pq.top();
176
+    pq.pop();
177
+
178
+    settled[cur.e] = cur;
179
+
180
+    if (to.find(cur.e) != to.end()) {
181
+      found++;
182
+      costs[cur.e] = cur.d;
183
+      buildPath(cur.e, settled, resNodes[cur.e], resEdges[cur.e]);
184
+    }
185
+
186
+    if (found == to.size()) return costs;
187
+
188
+    relax(cur, to, costFunc, heurFunc, pq);
189
+  }
190
+
191
+  return costs;
192
+}
193
+
194
+// _____________________________________________________________________________
195
+template <typename N, typename E, typename C>
196
+void EDijkstra::relaxInv(RouteEdge<N, E, C>& cur,
197
+                         const ShortestPath::CostFunc<N, E, C>& costFunc,
198
+                         PQ<N, E, C>& pq) {
199
+
200
+  // handling undirected graph makes no sense here
201
+
202
+  for (const auto edge : cur.e->getFrom()->getAdjListIn()) {
203
+    if (edge == cur.e) continue;
204
+    C newC = costFunc(edge, cur.e->getFrom(), cur.e);
205
+    newC = cur.d + newC;
206
+    if (costFunc.inf() <= newC) continue;
207
+
208
+    pq.emplace(edge, cur.e, cur.e->getFrom(), newC, C());
209
+  }
210
+}
211
+
212
+// _____________________________________________________________________________
213
+template <typename N, typename E, typename C>
214
+void EDijkstra::relax(RouteEdge<N, E, C>& cur, const std::set<Edge<N, E>*>& to,
215
+                      const ShortestPath::CostFunc<N, E, C>& costFunc,
216
+                      const ShortestPath::HeurFunc<N, E, C>& heurFunc,
217
+                      PQ<N, E, C>& pq) {
218
+  if (cur.e->getFrom()->hasEdgeIn(cur.e)) {
219
+    // for undirected graphs
220
+    for (const auto edge : cur.e->getFrom()->getAdjListOut()) {
221
+      if (edge == cur.e) continue;
222
+      C newC = costFunc(cur.e, cur.e->getFrom(), edge);
223
+      newC = cur.d + newC;
224
+      if (costFunc.inf() <= newC) continue;
225
+
226
+      const C& h = heurFunc(edge, to);
227
+      const C& newH = newC + h;
228
+
229
+      pq.emplace(edge, cur.e, cur.e->getFrom(), newC, newH);
230
+    }
231
+  }
232
+
233
+  for (const auto edge : cur.e->getTo()->getAdjListOut()) {
234
+    if (edge == cur.e) continue;
235
+    C newC = costFunc(cur.e, cur.e->getTo(), edge);
236
+    newC = cur.d + newC;
237
+    if (costFunc.inf() <= newC) continue;
238
+
239
+    const C& h = heurFunc(edge, to);
240
+    const C& newH = newC + h;
241
+
242
+    pq.emplace(edge, cur.e, cur.e->getTo(), newC, newH);
243
+  }
244
+}
245
+
246
+// _____________________________________________________________________________
247
+template <typename N, typename E, typename C>
248
+void EDijkstra::buildPath(Edge<N, E>* curE, const Settled<N, E, C>& settled,
249
+                          NList<N, E>* resNodes, EList<N, E>* resEdges) {
250
+  const RouteEdge<N, E, C>* curEdge = &settled.find(curE)->second;
251
+  if (resNodes) resNodes->push_back(curEdge->e->getOtherNd(curEdge->n));
252
+  while (true) {
253
+    if (resNodes && curEdge->n) resNodes->push_back(curEdge->n);
254
+    if (resEdges) resEdges->push_back(curEdge->e);
255
+    if (!curEdge->parent) break;
256
+    curEdge = &settled.find(curEdge->parent)->second;
257
+  }
258
+}

+ 41 - 0
src/util/graph/Edge.h

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_EDGE_H_
6
+#define UTIL_GRAPH_EDGE_H_
7
+
8
+#include <vector>
9
+#include "util/graph/Node.h"
10
+
11
+namespace util {
12
+namespace graph {
13
+
14
+template <typename N, typename E>
15
+class Edge {
16
+ public:
17
+  Edge(Node<N, E>* from, Node<N, E>* to, const E& pl);
18
+
19
+  Node<N, E>* getFrom() const;
20
+  Node<N, E>* getTo() const;
21
+
22
+  Node<N, E>* getOtherNd(const Node<N, E>* notNode) const;
23
+
24
+  void setFrom(Node<N, E>* from);
25
+  void setTo(Node<N, E>* to);
26
+
27
+  E& pl();
28
+  const E& pl() const;
29
+
30
+ private:
31
+  Node<N, E>* _from;
32
+  Node<N, E>* _to;
33
+  E _pl;
34
+};
35
+
36
+#include "util/graph/Edge.tpp"
37
+
38
+}}
39
+
40
+#endif  // UTIL_GRAPH_EDGE_H_
41
+

+ 41 - 0
src/util/graph/Edge.tpp

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+Edge<N, E>::Edge(Node<N, E>* from, Node<N, E>* to, const E& pl)
8
+ : _from(from), _to(to), _pl(pl) {
9
+
10
+}
11
+
12
+// _____________________________________________________________________________
13
+template <typename N, typename E>
14
+Node<N, E>* Edge<N, E>::getFrom() const {
15
+  return _from;
16
+}
17
+
18
+// _____________________________________________________________________________
19
+template <typename N, typename E>
20
+Node<N, E>* Edge<N, E>::getTo() const {
21
+  return _to;
22
+}
23
+
24
+// _____________________________________________________________________________
25
+template <typename N, typename E>
26
+Node<N, E>* Edge<N, E>::getOtherNd(const Node<N, E>* notNode) const {
27
+  if (_to == notNode) return _from;
28
+  return _to;
29
+}
30
+
31
+// _____________________________________________________________________________
32
+template <typename N, typename E>
33
+E& Edge<N, E>::pl() {
34
+  return _pl;
35
+}
36
+
37
+// _____________________________________________________________________________
38
+template <typename N, typename E>
39
+const E& Edge<N, E>::pl() const {
40
+  return _pl;
41
+}

+ 48 - 0
src/util/graph/Graph.h

@@ -0,0 +1,48 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_GRAPH_H_
6
+#define UTIL_GRAPH_GRAPH_H_
7
+
8
+#include <set>
9
+#include <string>
10
+#include <iostream>
11
+#include <cassert>
12
+
13
+#include "util/graph/Edge.h"
14
+#include "util/graph/Node.h"
15
+
16
+namespace util {
17
+namespace graph {
18
+
19
+template <typename N, typename E>
20
+class Graph {
21
+ public:
22
+  virtual ~Graph();
23
+  virtual Node<N, E>* addNd() = 0;
24
+  virtual Node<N, E>* addNd(const N& pl) = 0;
25
+  Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to);
26
+  virtual Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p) = 0;
27
+  Edge<N, E>* getEdg(Node<N, E>* from, Node<N, E>* to);
28
+  const Edge<N, E>* getEdg(Node<N, E>* from, Node<N, E>* to) const;
29
+
30
+  virtual Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b) = 0;
31
+
32
+  const std::set<Node<N, E>*>& getNds() const;
33
+  std::set<Node<N, E>*>* getNds();
34
+
35
+  typename std::set<Node<N, E>*>::iterator delNd(Node<N, E>* n);
36
+  typename std::set<Node<N, E>*>::iterator delNd(
37
+      typename std::set<Node<N, E>*>::iterator i);
38
+  void delEdg(Node<N, E>* from, Node<N, E>* to);
39
+
40
+ private:
41
+  std::set<Node<N, E>*> _nodes;
42
+};
43
+
44
+#include "util/graph/Graph.tpp"
45
+}
46
+}
47
+
48
+#endif  // UTIL_GRAPH_GRAPH_H_

+ 76 - 0
src/util/graph/Graph.tpp

@@ -0,0 +1,76 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+Graph<N, E>::~Graph() {
8
+  for (auto n : _nodes) delete n;
9
+}
10
+
11
+// _____________________________________________________________________________
12
+template <typename N, typename E>
13
+Edge<N, E>* Graph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to) {
14
+  return addEdg(from, to, E());
15
+}
16
+
17
+// _____________________________________________________________________________
18
+template <typename N, typename E>
19
+const std::set<Node<N, E>*>& Graph<N, E>::getNds() const {
20
+  return _nodes;
21
+}
22
+
23
+// _____________________________________________________________________________
24
+template <typename N, typename E>
25
+std::set<Node<N, E>*>* Graph<N, E>::getNds() {
26
+  return &_nodes;
27
+}
28
+
29
+// _____________________________________________________________________________
30
+template <typename N, typename E>
31
+typename std::set<Node<N, E>*>::iterator Graph<N, E>::delNd(
32
+    Node<N, E>* n) {
33
+  return delNd(_nodes.find(n));
34
+}
35
+
36
+// _____________________________________________________________________________
37
+template <typename N, typename E>
38
+typename std::set<Node<N, E>*>::iterator Graph<N, E>::delNd(
39
+    typename std::set<Node<N, E>*>::iterator i) {
40
+  delete *i;
41
+  return _nodes.erase(i);
42
+}
43
+
44
+// _____________________________________________________________________________
45
+template <typename N, typename E>
46
+void Graph<N, E>::delEdg(Node<N, E>* from, Node<N, E>* to) {
47
+  Edge<N, E>* toDel = getEdg(from, to);
48
+  if (!toDel) return;
49
+
50
+  from->removeEdge(toDel);
51
+  to->removeEdge(toDel);
52
+
53
+  assert(!getEdg(from, to));
54
+
55
+  delete toDel;
56
+}
57
+
58
+// _____________________________________________________________________________
59
+template <typename N, typename E>
60
+Edge<N, E>* Graph<N, E>::getEdg(Node<N, E>* from, Node<N, E>* to) {
61
+  for (auto e : from->getAdjList()) {
62
+    if (e->getOtherNd(from) == to) return e;
63
+  }
64
+
65
+  return 0;
66
+}
67
+
68
+// _____________________________________________________________________________
69
+template <typename N, typename E>
70
+const Edge<N, E>* Graph<N, E>::getEdg(Node<N, E>* from, Node<N, E>* to) const {
71
+  for (auto e : from->getAdjList()) {
72
+    if (e->getOtherNd(from) == to) return e;
73
+  }
74
+
75
+  return 0;
76
+}

+ 47 - 0
src/util/graph/Node.h

@@ -0,0 +1,47 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_NODE_H_
6
+#define UTIL_GRAPH_NODE_H_
7
+
8
+#include <vector>
9
+
10
+namespace util {
11
+namespace graph {
12
+
13
+// forward declaration of Edge
14
+template <typename N, typename E>
15
+class Edge;
16
+
17
+template <typename N, typename E>
18
+class Node {
19
+ public:
20
+  virtual const std::vector<Edge<N, E>*>& getAdjList() const = 0;
21
+  virtual const std::vector<Edge<N, E>*>& getAdjListOut() const = 0;
22
+  virtual const std::vector<Edge<N, E>*>& getAdjListIn() const = 0;
23
+
24
+  virtual size_t getDeg() const = 0;
25
+  virtual size_t getInDeg() const = 0;
26
+  virtual size_t getOutDeg() const = 0;
27
+
28
+  virtual bool hasEdgeIn(const Edge<N, E>* e) const = 0;
29
+  virtual bool hasEdgeOut(const Edge<N, E>* e) const = 0;
30
+  virtual bool hasEdge(const Edge<N, E>* e) const = 0;
31
+
32
+  // add edge to this node's adjacency lists
33
+  virtual void addEdge(Edge<N, E>* e) = 0;
34
+  virtual void removeEdge(Edge<N, E>* e) = 0;
35
+
36
+  virtual ~Node() = 0;
37
+
38
+  virtual N& pl() = 0;
39
+  virtual const N& pl() const = 0;
40
+};
41
+
42
+template <typename N, typename E>
43
+inline Node<N, E>::~Node() {}
44
+
45
+}}
46
+
47
+#endif  // UTIL_GRAPH_NODE_H_

+ 401 - 0
src/util/graph/ShortestPath.h

@@ -0,0 +1,401 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_SHORTESTPATH_H_
6
+#define UTIL_GRAPH_SHORTESTPATH_H_
7
+
8
+#include <exception>
9
+#include <iostream>
10
+#include <limits>
11
+#include <list>
12
+#include <queue>
13
+#include <set>
14
+#include <unordered_map>
15
+#include "util/graph/Edge.h"
16
+#include "util/graph/Graph.h"
17
+#include "util/graph/Node.h"
18
+
19
+namespace util {
20
+namespace graph {
21
+
22
+using util::graph::Graph;
23
+using util::graph::Node;
24
+using util::graph::Edge;
25
+
26
+// shortest path base class
27
+template <class D>
28
+class ShortestPath {
29
+ public:
30
+  template <typename N, typename E>
31
+  using EList = std::vector<Edge<N, E>*>;
32
+
33
+  template <typename N, typename E>
34
+  using NList = std::vector<Node<N, E>*>;
35
+
36
+  template <typename N, typename E, typename C>
37
+  struct CostFunc {
38
+    virtual C operator()(const Node<N, E>* from, const Edge<N, E>* e,
39
+                         const Node<N, E>* to) const = 0;
40
+    virtual C operator()(const Edge<N, E>* from, const Node<N, E>* n,
41
+                         const Edge<N, E>* to) const = 0;
42
+    virtual C inf() const = 0;
43
+  };
44
+
45
+  template <typename N, typename E, typename C>
46
+  struct HeurFunc {
47
+    virtual C operator()(const Node<N, E>* a,
48
+                         const std::set<Node<N, E>*>& b) const = 0;
49
+    virtual C operator()(const Edge<N, E>* a,
50
+                         const std::set<Edge<N, E>*>& b) const = 0;
51
+  };
52
+
53
+  template <typename N, typename E, typename C>
54
+  struct ZeroHeurFunc : public HeurFunc<N, E, C> {
55
+    C operator()(const Node<N, E>* a, const std::set<Node<N, E>*>& b) const {
56
+      UNUSED(a);
57
+      UNUSED(b);
58
+      return C();
59
+    }
60
+    C operator()(const Edge<N, E>* a, const std::set<Edge<N, E>*>& b) const {
61
+      UNUSED(a);
62
+      UNUSED(b);
63
+      return C();
64
+    }
65
+  };
66
+
67
+  template <typename N, typename E, typename C>
68
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
69
+                        const CostFunc<N, E, C>& costFunc,
70
+                        const HeurFunc<N, E, C>& heurFunc,
71
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
72
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
73
+                               resNodes);
74
+  }
75
+
76
+  template <typename N, typename E, typename C>
77
+  static C shortestPath(const std::set<Node<N, E>*> from, const std::set<Node<N, E>*>& to,
78
+                        const CostFunc<N, E, C>& costFunc,
79
+                        const HeurFunc<N, E, C>& heurFunc,
80
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
81
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
82
+                               resNodes);
83
+  }
84
+
85
+  template <typename N, typename E, typename C>
86
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
87
+                        const CostFunc<N, E, C>& costFunc,
88
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
89
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(),
90
+                               resEdges, resNodes);
91
+  }
92
+
93
+  template <typename N, typename E, typename C>
94
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
95
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
96
+      const CostFunc<N, E, C>& costFunc, const HeurFunc<N, E, C>& heurFunc,
97
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
98
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
99
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
100
+                               resNodes);
101
+  }
102
+
103
+  template <typename N, typename E, typename C>
104
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
105
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
106
+      const CostFunc<N, E, C>& costFunc,
107
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges,
108
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
109
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(),
110
+                               resEdges, resNodes);
111
+  }
112
+
113
+  template <typename N, typename E, typename C>
114
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
115
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
116
+      const CostFunc<N, E, C>& costFunc, const HeurFunc<N, E, C>& heurFunc,
117
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges) {
118
+    std::unordered_map<Node<N, E>*, NList<N, E>*> dummyRet;
119
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
120
+                               dummyRet);
121
+  }
122
+
123
+  template <typename N, typename E, typename C>
124
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
125
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
126
+      const CostFunc<N, E, C>& costFunc,
127
+      std::unordered_map<Node<N, E>*, EList<N, E>*> resEdges) {
128
+    std::unordered_map<Node<N, E>*, NList<N, E>*> dummyRet;
129
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(),
130
+                               resEdges, dummyRet);
131
+  }
132
+
133
+  template <typename N, typename E, typename C>
134
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
135
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
136
+      const CostFunc<N, E, C>& costFunc,
137
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
138
+    std::unordered_map<Node<N, E>*, EList<N, E>*> dummyRet;
139
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(),
140
+                               dummyRet, resNodes);
141
+  }
142
+
143
+  template <typename N, typename E, typename C>
144
+  static std::unordered_map<Node<N, E>*, C> shortestPath(
145
+      Node<N, E>* from, const std::set<Node<N, E>*>& to,
146
+      const CostFunc<N, E, C>& costFunc, const HeurFunc<N, E, C>& heurFunc,
147
+      std::unordered_map<Node<N, E>*, NList<N, E>*> resNodes) {
148
+    std::unordered_map<Node<N, E>*, EList<N, E>*> dummyRet;
149
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, dummyRet,
150
+                               resNodes);
151
+  }
152
+
153
+  template <typename N, typename E, typename C>
154
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
155
+                        const CostFunc<N, E, C>& costFunc,
156
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
157
+    if (to->getInDeg() == 0) return costFunc.inf();
158
+    std::set<Node<N, E>*> tos;
159
+    tos.insert(to);
160
+    return shortestPath(from, tos, costFunc, resEdges, resNodes);
161
+  }
162
+
163
+  template <typename N, typename E, typename C>
164
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
165
+                        const CostFunc<N, E, C>& costFunc) {
166
+    if (to->getInDeg() == 0) return costFunc.inf();
167
+    std::set<Node<N, E>*> tos;
168
+    tos.insert(to);
169
+    EList<N, E>* el = 0;
170
+    NList<N, E>* nl = 0;
171
+    return shortestPath(from, tos, costFunc, el, nl);
172
+  }
173
+
174
+  template <typename N, typename E, typename C>
175
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
176
+                        const CostFunc<N, E, C>& costFunc,
177
+                        NList<N, E>* resNodes) {
178
+    if (to->getInDeg() == 0) return costFunc.inf();
179
+    std::set<Node<N, E>*> tos;
180
+    tos.insert(to);
181
+    EList<N, E>* el = 0;
182
+    return shortestPath(from, tos, costFunc, el, resNodes);
183
+  }
184
+
185
+  template <typename N, typename E, typename C>
186
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
187
+                        const CostFunc<N, E, C>& costFunc,
188
+                        EList<N, E>* resEdges) {
189
+    if (to->getInDeg() == 0) return costFunc.inf();
190
+    std::set<Node<N, E>*> tos;
191
+    tos.insert(to);
192
+    NList<N, E>* nl = 0;
193
+    return shortestPath(from, tos, costFunc, resEdges, nl);
194
+  }
195
+
196
+  template <typename N, typename E, typename C>
197
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
198
+                        const CostFunc<N, E, C>& costFunc,
199
+                        NList<N, E>* resNodes) {
200
+    EList<N, E>* el = 0;
201
+    return shortestPath(from, to, costFunc, el, resNodes);
202
+  }
203
+
204
+  template <typename N, typename E, typename C>
205
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
206
+                        const CostFunc<N, E, C>& costFunc,
207
+                        EList<N, E>* resEdges) {
208
+    NList<N, E>* nl = 0;
209
+    return shortestPath(from, to, costFunc, resEdges, nl);
210
+  }
211
+
212
+  template <typename N, typename E, typename C>
213
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
214
+                        const CostFunc<N, E, C>& costFunc,
215
+                        const HeurFunc<N, E, C>& heurFunc,
216
+                        EList<N, E>* resEdges, NList<N, E>* resNodes) {
217
+    if (to->getInDeg() == 0) return costFunc.inf();
218
+    std::set<Node<N, E>*> tos;
219
+    tos.insert(to);
220
+    return D::shortestPathImpl(from, tos, costFunc, heurFunc, resEdges,
221
+                               resNodes);
222
+  }
223
+
224
+  template <typename N, typename E, typename C>
225
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
226
+                        const CostFunc<N, E, C>& costFunc,
227
+                        const HeurFunc<N, E, C>& heurFunc,
228
+                        NList<N, E>* resNodes) {
229
+    if (to->getInDeg() == 0) return costFunc.inf();
230
+    std::set<Node<N, E>*> tos;
231
+    tos.insert(to);
232
+    EList<N, E>* el = 0;
233
+    return D::shortestPathImpl(from, tos, costFunc, heurFunc, el, resNodes);
234
+  }
235
+
236
+  template <typename N, typename E, typename C>
237
+  static C shortestPath(Node<N, E>* from, Node<N, E>* to,
238
+                        const CostFunc<N, E, C>& costFunc,
239
+                        const HeurFunc<N, E, C>& heurFunc,
240
+                        EList<N, E>* resEdges) {
241
+    if (to->getInDeg() == 0) return costFunc.inf();
242
+    std::set<Node<N, E>*> tos;
243
+    tos.insert(to);
244
+    NList<N, E>* nl = 0;
245
+    return D::shortestPathImpl(from, tos, costFunc, heurFunc, resEdges, nl);
246
+  }
247
+
248
+  template <typename N, typename E, typename C>
249
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
250
+                        const CostFunc<N, E, C>& costFunc,
251
+                        const HeurFunc<N, E, C>& heurFunc,
252
+                        NList<N, E>* resNodes) {
253
+    EList<N, E>* el = 0;
254
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, resNodes);
255
+  }
256
+
257
+  template <typename N, typename E, typename C>
258
+  static C shortestPath(Node<N, E>* from, const std::set<Node<N, E>*>& to,
259
+                        const CostFunc<N, E, C>& costFunc,
260
+                        const HeurFunc<N, E, C>& heurFunc,
261
+                        EList<N, E>* resEdges) {
262
+    NList<N, E>* nl = 0;
263
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges, nl);
264
+  }
265
+
266
+  template <typename N, typename E, typename C>
267
+  static std::unordered_map<Edge<N, E>*, C> shortestPath(
268
+      Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
269
+      const ShortestPath::CostFunc<N, E, C>& costFunc,
270
+      const HeurFunc<N, E, C>& heurFunc,
271
+      std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges,
272
+      std::unordered_map<Edge<N, E>*, NList<N, E>*> resNodes) {
273
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
274
+                               resNodes);
275
+  }
276
+
277
+  template <typename N, typename E, typename C>
278
+  static std::unordered_map<Edge<N, E>*, C> shortestPath(
279
+      Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
280
+      const ShortestPath::CostFunc<N, E, C>& costFunc,
281
+      const HeurFunc<N, E, C>& heurFunc,
282
+      std::unordered_map<Edge<N, E>*, EList<N, E>*> resEdges) {
283
+    std::unordered_map<Edge<N, E>*, NList<N, E>*> dummyRet;
284
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, resEdges,
285
+                               dummyRet);
286
+  }
287
+
288
+  template <typename N, typename E, typename C>
289
+  static std::unordered_map<Edge<N, E>*, C> shortestPath(
290
+      Edge<N, E>* from, const std::set<Edge<N, E>*>& to,
291
+      const ShortestPath::CostFunc<N, E, C>& costFunc,
292
+      const HeurFunc<N, E, C>& heurFunc) {
293
+    std::unordered_map<Edge<N, E>*, NList<N, E>*> dummyRet;
294
+    std::unordered_map<Edge<N, E>*, EList<N, E>*> dummyRetE;
295
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, dummyRetE,
296
+                               dummyRet);
297
+  }
298
+
299
+  template <typename N, typename E, typename C>
300
+  static C shortestPath(const std::set<Edge<N, E>*>& from,
301
+                        const std::set<Edge<N, E>*>& to,
302
+                        const CostFunc<N, E, C>& costFunc,
303
+                        const HeurFunc<N, E, C>& heurFunc) {
304
+    NList<N, E>* nl = 0;
305
+    EList<N, E>* el = 0;
306
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, nl);
307
+  }
308
+
309
+  template <typename N, typename E, typename C>
310
+  static C shortestPath(Edge<N, E>* from,
311
+                        Edge<N, E>* to,
312
+                        const CostFunc<N, E, C>& costFunc ) {
313
+    NList<N, E>* nl = 0;
314
+    EList<N, E>* el = 0;
315
+    std::set<Edge<N, E>*> tos{to};
316
+    std::set<Edge<N, E>*> froms{from};
317
+    return D::shortestPathImpl(froms, tos, costFunc, ZeroHeurFunc<N, E, C>(), el, nl);
318
+  }
319
+
320
+  template <typename N, typename E, typename C>
321
+  static C shortestPath(const std::set<Edge<N, E>*>& from,
322
+                        const std::set<Edge<N, E>*>& to,
323
+                        const CostFunc<N, E, C>& costFunc,
324
+                        const HeurFunc<N, E, C>& heurFunc, EList<N, E>* el) {
325
+    NList<N, E>* nl = 0;
326
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, nl);
327
+  }
328
+
329
+  template <typename N, typename E, typename C>
330
+  static C shortestPath(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
331
+                        const CostFunc<N, E, C>& costFunc,
332
+                        const HeurFunc<N, E, C>& heurFunc, EList<N, E>* el,
333
+                        NList<N, E>* nl) {
334
+    return D::shortestPathImpl(from, to, costFunc, heurFunc, el, nl);
335
+  }
336
+
337
+  template <typename N, typename E, typename C>
338
+  static C shortestPath(Edge<N, E>* from, const std::set<Node<N, E>*>& to,
339
+                        const CostFunc<N, E, C>& costFunc,
340
+                        EList<N, E>* el,
341
+                        NList<N, E>* nl) {
342
+    return D::shortestPathImpl(from, to, costFunc, ZeroHeurFunc<N, E, C>(), el,
343
+                               nl);
344
+  }
345
+
346
+  template <typename N, typename E, typename C>
347
+  static C shortestPath(Edge<N, E>* from, Node<N, E>* to,
348
+                        const CostFunc<N, E, C>& costFunc,
349
+                        const HeurFunc<N, E, C>& heurFunc, EList<N, E>* el,
350
+                        NList<N, E>* nl) {
351
+    std::set<Node<N, E>*> tos{to};
352
+    return D::shortestPathImpl(from, tos, costFunc, heurFunc, el, nl);
353
+  }
354
+
355
+  template <typename N, typename E, typename C>
356
+  static C shortestPath(Edge<N, E>* from, Node<N, E>* to,
357
+                        const CostFunc<N, E, C>& costFunc, EList<N, E>* el,
358
+                        NList<N, E>* nl) {
359
+    std::set<Node<N, E>*> tos{to};
360
+    return D::shortestPathImpl(from, tos, costFunc, ZeroHeurFunc<N, E, C>(), el,
361
+                               nl);
362
+  }
363
+
364
+  template <typename N, typename E, typename C>
365
+  static std::unordered_map<Edge<N, E>*, C> shortestPath(
366
+      Edge<N, E>* from,
367
+      const ShortestPath::CostFunc<N, E, C>& costFunc) {
368
+    std::set<Edge<N, E>*> froms { from };
369
+    return D::shortestPathImpl(froms, costFunc, false);
370
+  }
371
+
372
+  template <typename N, typename E, typename C>
373
+  static std::unordered_map<Edge<N, E>*, C> shortestPathRev(
374
+      Edge<N, E>* from,
375
+      const ShortestPath::CostFunc<N, E, C>& costFunc) {
376
+    std::set<Edge<N, E>*> froms { from };
377
+    return D::shortestPathImpl(froms, costFunc, true);
378
+  }
379
+
380
+  template <typename N, typename E, typename C>
381
+  static std::unordered_map<Edge<N, E>*, C> shortestPath(
382
+      Node<N, E>* from,
383
+      const ShortestPath::CostFunc<N, E, C>& costFunc) {
384
+    std::set<Edge<N, E>*> froms;
385
+    froms.insert(from->getAdjListOut().begin(), from->getAdjListOut().end());
386
+    return D::shortestPathImpl(froms, costFunc, false);
387
+  }
388
+
389
+  template <typename N, typename E, typename C>
390
+  static std::unordered_map<Edge<N, E>*, C> shortestPathRev(
391
+      Node<N, E>* from,
392
+      const ShortestPath::CostFunc<N, E, C>& costFunc) {
393
+    std::set<Edge<N, E>*> froms;
394
+    froms.insert(from->getAdjListOut().begin(), from->getAdjListOut().end());
395
+    return D::shortestPathImpl(froms, costFunc, true);
396
+  }
397
+};
398
+}
399
+}
400
+
401
+#endif  // UTIL_GRAPH_SHORTESTPATH_H_

+ 1 - 0
src/util/graph/ShortestPath.tpp

@@ -0,0 +1 @@
1
+

+ 41 - 0
src/util/graph/UndirGraph.h

@@ -0,0 +1,41 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_UNDIRGRAPH_H_
6
+#define UTIL_GRAPH_UNDIRGRAPH_H_
7
+
8
+#include <set>
9
+#include <string>
10
+
11
+#include "util/graph/Graph.h"
12
+#include "util/graph/Edge.h"
13
+#include "util/graph/UndirNode.h"
14
+
15
+namespace util {
16
+namespace graph {
17
+
18
+template <typename N, typename E>
19
+using UndirEdge = Edge<N, E>;
20
+
21
+template <typename N, typename E>
22
+class UndirGraph : public Graph<N, E> {
23
+ public:
24
+  explicit UndirGraph();
25
+
26
+  using Graph<N, E>::addEdg;
27
+
28
+  Node<N, E>* addNd();
29
+  Node<N, E>* addNd(UndirNode<N, E>* n);
30
+  Node<N, E>* addNd(const N& pl);
31
+  Edge<N, E>* addEdg(Node<N, E>* from, Node<N, E>* to, const E& p);
32
+
33
+  Node<N, E>* mergeNds(Node<N, E>* a, Node<N, E>* b);
34
+
35
+};
36
+
37
+#include "util/graph/UndirGraph.tpp"
38
+}
39
+}
40
+
41
+#endif  // UTIL_GRAPH_UNDIRGRAPH_H_

+ 59 - 0
src/util/graph/UndirGraph.tpp

@@ -0,0 +1,59 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+UndirGraph<N, E>::UndirGraph() {}
8
+
9
+// _____________________________________________________________________________
10
+template <typename N, typename E>
11
+Node<N, E>* UndirGraph<N, E>::addNd(const N& pl) {
12
+  return addNd(new UndirNode<N, E>(pl));
13
+}
14
+
15
+// _____________________________________________________________________________
16
+template <typename N, typename E>
17
+Node<N, E>* UndirGraph<N, E>::addNd() {
18
+  return addNd(new UndirNode<N, E>());
19
+}
20
+
21
+// _____________________________________________________________________________
22
+template <typename N, typename E>
23
+Node<N, E>* UndirGraph<N, E>::addNd(UndirNode<N, E>* n) {
24
+  auto ins = Graph<N, E>::getNds()->insert(n);
25
+  return *ins.first;
26
+}
27
+
28
+// _____________________________________________________________________________
29
+template <typename N, typename E>
30
+Edge<N, E>* UndirGraph<N, E>::addEdg(Node<N, E>* from, Node<N, E>* to,
31
+                                     const E& p) {
32
+  Edge<N, E>* e = Graph<N, E>::getEdg(from, to);
33
+  if (!e) {
34
+    e = new Edge<N, E>(from, to, p);
35
+    from->addEdge(e);
36
+    to->addEdge(e);
37
+  }
38
+  return e;
39
+}
40
+
41
+// _____________________________________________________________________________
42
+template <typename N, typename E>
43
+Node<N, E>* UndirGraph<N, E>::mergeNds(Node<N, E>* a, Node<N, E>* b) {
44
+  for (auto e : a->getAdjListOut()) {
45
+    if (e->getTo() != b) {
46
+      addEdg(b, e->getTo(), e->pl());
47
+    }
48
+  }
49
+
50
+  for (auto e : a->getAdjListIn()) {
51
+    if (e->getFrom() != b) {
52
+      addEdg(e->getFrom(), b, e->pl());
53
+    }
54
+  }
55
+
56
+  UndirGraph<N, E>::delNd(a);
57
+
58
+  return b;
59
+}

+ 54 - 0
src/util/graph/UndirNode.h

@@ -0,0 +1,54 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_GRAPH_UNDIRNODE_H_
6
+#define UTIL_GRAPH_UNDIRNODE_H_
7
+
8
+#include <vector>
9
+#include <algorithm>
10
+#include "util/graph/Node.h"
11
+
12
+namespace util {
13
+namespace graph {
14
+
15
+template <typename N, typename E>
16
+class UndirNode : public Node<N, E> {
17
+ public:
18
+  UndirNode();
19
+  UndirNode(const N& pl);
20
+  ~UndirNode();
21
+
22
+  const std::vector<Edge<N, E>*>& getAdjList() const;
23
+  const std::vector<Edge<N, E>*>& getAdjListIn() const;
24
+  const std::vector<Edge<N, E>*>& getAdjListOut() const;
25
+
26
+  size_t getDeg() const;
27
+  size_t getInDeg() const;
28
+  size_t getOutDeg() const;
29
+
30
+  bool hasEdgeIn(const Edge<N, E>* e) const;
31
+  bool hasEdgeOut(const Edge<N, E>* e) const;
32
+  bool hasEdge(const Edge<N, E>* e) const;
33
+
34
+  // add edge to this node's adjacency lists
35
+  void addEdge(Edge<N, E>* e);
36
+
37
+  // remove edge from this node's adjacency lists
38
+  void removeEdge(Edge<N, E>* e);
39
+
40
+  N& pl();
41
+  const N& pl() const;
42
+
43
+ private:
44
+  std::vector<Edge<N, E>*> _adjList;
45
+  N _pl;
46
+
47
+  bool adjContains(const Edge<N, E>* e) const;
48
+};
49
+
50
+#include "util/graph/UndirNode.tpp"
51
+
52
+}}
53
+
54
+#endif  // UTIL_GRAPH_UNDIRNODE_H_

+ 130 - 0
src/util/graph/UndirNode.tpp

@@ -0,0 +1,130 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+// _____________________________________________________________________________
6
+template <typename N, typename E>
7
+UndirNode<N, E>::UndirNode() : _pl() {
8
+}
9
+
10
+// _____________________________________________________________________________
11
+template <typename N, typename E>
12
+UndirNode<N, E>::UndirNode(const N& pl) : _pl(pl) {
13
+}
14
+
15
+// _____________________________________________________________________________
16
+template <typename N, typename E>
17
+UndirNode<N, E>::~UndirNode() {
18
+  // delete self edges
19
+  for (auto e = _adjList.begin(); e != _adjList.end();) {
20
+    Edge<N, E>* eP = *e;
21
+    if (eP->getTo() == this && eP->getFrom() == this) {
22
+      e = _adjList.erase(e);
23
+      delete eP;
24
+    } else {
25
+      e++;
26
+    }
27
+  }
28
+
29
+  for (auto e = _adjList.begin(); e != _adjList.end(); e++) {
30
+    Edge<N, E>* eP = *e;
31
+
32
+    if (eP->getTo() != this) {
33
+      eP->getTo()->removeEdge(eP);
34
+    }
35
+
36
+    if (eP->getFrom() != this) {
37
+      eP->getFrom()->removeEdge(eP);
38
+    }
39
+
40
+    delete eP;
41
+  }
42
+}
43
+
44
+// _____________________________________________________________________________
45
+template <typename N, typename E>
46
+bool UndirNode<N, E>::hasEdgeIn(const Edge<N, E>* e) const {
47
+  return hasEdge(e);
48
+}
49
+
50
+// _____________________________________________________________________________
51
+template <typename N, typename E>
52
+bool UndirNode<N, E>::hasEdgeOut(const Edge<N, E>* e) const {
53
+  return hasEdge(e);
54
+}
55
+
56
+// _____________________________________________________________________________
57
+template <typename N, typename E>
58
+bool UndirNode<N, E>::hasEdge(const Edge<N, E>* e) const {
59
+  return e->getFrom() == this || e->getTo() == this;
60
+}
61
+
62
+// _____________________________________________________________________________
63
+template <typename N, typename E>
64
+bool UndirNode<N, E>::adjContains(const Edge<N, E>* e) const {
65
+  for (size_t i = 0; i < _adjList.size(); i++) if (_adjList[i] == e) return true;
66
+  return false;
67
+}
68
+
69
+// _____________________________________________________________________________
70
+template <typename N, typename E>
71
+void UndirNode<N, E>::addEdge(Edge<N, E>* e) {
72
+  if (adjContains(e)) return;
73
+  _adjList.reserve(_adjList.size() + 1);
74
+  _adjList.push_back(e);
75
+}
76
+
77
+// _____________________________________________________________________________
78
+template <typename N, typename E>
79
+void UndirNode<N, E>::removeEdge(Edge<N, E>* e) {
80
+  auto p = std::find(_adjList.begin(), _adjList.end(), e);
81
+  if (p != _adjList.end()) _adjList.erase(p);
82
+}
83
+
84
+// _____________________________________________________________________________
85
+template <typename N, typename E>
86
+const std::vector<Edge<N, E>*>& UndirNode<N, E>::getAdjList() const {
87
+  return _adjList;
88
+}
89
+
90
+// _____________________________________________________________________________
91
+template <typename N, typename E>
92
+const std::vector<Edge<N, E>*>& UndirNode<N, E>::getAdjListOut() const {
93
+  return _adjList;
94
+}
95
+
96
+// _____________________________________________________________________________
97
+template <typename N, typename E>
98
+const std::vector<Edge<N, E>*>& UndirNode<N, E>::getAdjListIn() const {
99
+  return _adjList;
100
+}
101
+
102
+// _____________________________________________________________________________
103
+template <typename N, typename E>
104
+size_t UndirNode<N, E>::getDeg() const {
105
+  return _adjList.size();
106
+}
107
+
108
+// _____________________________________________________________________________
109
+template <typename N, typename E>
110
+size_t UndirNode<N, E>::getInDeg() const {
111
+  return getDeg();
112
+}
113
+
114
+// _____________________________________________________________________________
115
+template <typename N, typename E>
116
+size_t UndirNode<N, E>::getOutDeg() const {
117
+  return getDeg();
118
+}
119
+
120
+// _____________________________________________________________________________
121
+template <typename N, typename E>
122
+N& UndirNode<N, E>::pl() {
123
+  return _pl;
124
+}
125
+
126
+// _____________________________________________________________________________
127
+template <typename N, typename E>
128
+const N& UndirNode<N, E>::pl() const {
129
+  return _pl;
130
+}

+ 343 - 0
src/util/http/Server.cpp

@@ -0,0 +1,343 @@
1
+// Copyright 2018, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef ZLIB_CONST
6
+#define ZLIB_CONST
7
+#endif
8
+
9
+#include <fcntl.h>
10
+#include <netdb.h>
11
+#include <netinet/in.h>
12
+#include <netinet/tcp.h>
13
+#include <algorithm>
14
+#include <memory>
15
+#include <sstream>
16
+#include <stdexcept>
17
+#include <thread>
18
+#include <unordered_map>
19
+#ifdef ZLIB_FOUND
20
+#include <zlib.h>
21
+#endif
22
+#include <vector>
23
+#include "Server.h"
24
+#include "util/String.h"
25
+
26
+using util::http::Socket;
27
+using util::http::Queue;
28
+using util::http::Req;
29
+using util::http::HttpErr;
30
+using util::http::HttpServer;
31
+using util::http::HeaderState;
32
+
33
+// _____________________________________________________________________________
34
+Socket::Socket(int port) {
35
+  int y = 1;
36
+  _sock = socket(PF_INET, SOCK_STREAM, 0);
37
+  if (_sock < 0)
38
+    throw std::runtime_error(std::string("Could not create socket (") +
39
+                             std::strerror(errno) + ")");
40
+
41
+  struct sockaddr_in addr;
42
+
43
+  addr.sin_family = AF_INET;
44
+  addr.sin_port = htons(port);
45
+  addr.sin_addr.s_addr = INADDR_ANY;
46
+  memset(&(addr.sin_zero), '\0', 8);
47
+
48
+  setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y));
49
+
50
+  if (bind(_sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
51
+    throw std::runtime_error(std::string("Could not bind to port ") +
52
+                             std::to_string(port) + " (" +
53
+                             std::strerror(errno) + ")");
54
+  }
55
+}
56
+
57
+// _____________________________________________________________________________
58
+Socket::~Socket() { close(_sock); }
59
+
60
+// _____________________________________________________________________________
61
+int Socket::wait() {
62
+  if (listen(_sock, BLOG) < 0)
63
+    throw std::runtime_error(std::string("Cannot listen to socket (") +
64
+                             std::strerror(errno) + ")");
65
+  sockaddr_in cli_addr;
66
+  socklen_t clilen = sizeof(cli_addr);
67
+  int sock = accept(_sock, reinterpret_cast<sockaddr*>(&cli_addr), &clilen);
68
+  return sock;
69
+}
70
+
71
+// _____________________________________________________________________________
72
+void HttpServer::send(int sock, Answer* aw) {
73
+  std::string enc = "identity";
74
+  if (aw->gzip) aw->pl = compress(aw->pl, &enc);
75
+
76
+  aw->params["Content-Encoding"] = enc;
77
+  aw->params["Content-Length"] = std::to_string(aw->pl.size());
78
+
79
+  std::stringstream ss;
80
+  ss << "HTTP/1.1 " << aw->status << "\r\n";
81
+  for (const auto& kv : aw->params)
82
+    ss << kv.first << ": " << kv.second << "\r\n";
83
+  ss << "\r\n" << aw->pl;
84
+  std::string buff = ss.str();
85
+
86
+  size_t writes = 0;
87
+
88
+  while (writes != buff.size()) {
89
+    int64_t out = write(sock, buff.c_str() + writes, buff.size() - writes);
90
+    if (out < 0) {
91
+      if (errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR) continue;
92
+      throw std::runtime_error("Failed to write to socket");
93
+    }
94
+    writes += out;
95
+  }
96
+}
97
+
98
+// _____________________________________________________________________________
99
+void HttpServer::handle() {
100
+  int connection = -1;
101
+  while ((connection = _jobs.get()) != -1) {
102
+    Answer answ;
103
+
104
+    try {
105
+      Req req = getReq(connection);
106
+      answ = _handler->handle(req, connection);
107
+      answ.gzip = gzipSupport(req);
108
+    } catch (const HttpErr& err) {
109
+      answ = Answer(err.what(), err.what());
110
+    } catch (...) {
111
+      // catch everything to make sure the server continues running
112
+      answ = Answer("500 Internal Server Error", "500 Internal Server Error");
113
+    }
114
+
115
+    send(connection, &answ);
116
+    close(connection);
117
+  }
118
+}
119
+
120
+// _____________________________________________________________________________
121
+bool HttpServer::gzipSupport(const Req& req) {
122
+  bool accepts = false;
123
+  // decide according to
124
+  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
125
+  for (const auto& kv : req.params) {
126
+    if (kv.first == "Accept-Encoding") {
127
+      for (const auto& encoding : split(kv.second, ',')) {
128
+        std::vector<std::string> parts = split(encoding, ';');
129
+        for (size_t i = 0; i < parts.size(); i++) {
130
+          parts[i] = trim(parts[i]);
131
+        }
132
+        if (parts[0] == "*" && ((parts.size() == 1) || parts[1] != "q=0"))
133
+          accepts = true;
134
+        if (parts[0] == "gzip") accepts = true;
135
+        if (parts.size() > 1 && parts[1] == "q=0") accepts = false;
136
+      }
137
+    }
138
+  }
139
+  return accepts;
140
+}
141
+
142
+// _____________________________________________________________________________
143
+Req HttpServer::getReq(int connection) {
144
+  char buf[BSIZE + 1];
145
+  size_t rcvd = 0;
146
+  int64_t curRcvd = 0;
147
+  HeaderState state = NONE;
148
+  Req ret;
149
+  char* tmp = 0;
150
+  char* tmp2 = 0;
151
+  char* brk = 0;
152
+
153
+  while ((curRcvd = read(connection, buf + rcvd, BSIZE - rcvd))) {
154
+    if (curRcvd < 0) {
155
+      if (errno == EAGAIN || errno == EINTR) continue;
156
+      throw HttpErr("500 Internal Server Error");
157
+    }
158
+
159
+    // parse request
160
+    for (int i = 0; i < curRcvd; i++) {
161
+      if (brk) break;
162
+      char* c = buf + rcvd + i;
163
+      switch (state) {
164
+        case NONE:
165
+          state = I_COM;
166
+          tmp = c;
167
+          continue;
168
+        case I_VER:
169
+          if (*c == '\n') {
170
+            *c = 0;
171
+            ret.ver = trim(tmp);
172
+            state = A_KEY;
173
+          }
174
+          continue;
175
+        case I_URL:
176
+          if (*c == ' ') {
177
+            *c = 0, ret.url = trim(tmp);
178
+            tmp = c + 1;
179
+            state = I_VER;
180
+          } else if (*c == '\n') {
181
+            *c = 0, ret.url = trim(tmp);
182
+            state = A_KEY;
183
+          }
184
+          continue;
185
+        case I_COM:
186
+          if (*c == ' ') {
187
+            *c = 0, ret.cmd = trim(tmp);
188
+            tmp = c + 1;
189
+            state = I_URL;
190
+          } else if (*c == '\n') {
191
+            *c = 0, ret.cmd = trim(tmp);
192
+            state = A_KEY;
193
+          }
194
+          continue;
195
+        case A_KEY:
196
+          if (*c == '\r') *c = ' ';
197
+          if (*c == '\n')
198
+            brk = c + 1;
199
+          else if (*c != ' ') {
200
+            state = I_KEY;
201
+            tmp = c;
202
+          }
203
+          continue;
204
+        case I_KEY:
205
+          if (*c == ':') {
206
+            *c = 0;
207
+            state = A_VAL;
208
+          }
209
+          continue;
210
+        case A_VAL:
211
+          if (*c != ' ') {
212
+            state = I_VAL;
213
+            tmp2 = c;
214
+          }
215
+          continue;
216
+        case I_VAL:
217
+          if (*c == '\r') *c = ' ';
218
+          if (*c == '\n') {
219
+            *c = 0;
220
+            ret.params[tmp] = trim(tmp2);
221
+            state = A_KEY;
222
+          }
223
+          continue;
224
+      }
225
+    }
226
+
227
+    rcvd += curRcvd;
228
+
229
+    // buffer is full
230
+    if (rcvd == BSIZE) throw HttpErr("431 Request Header Fields Too Large");
231
+    if (brk) break;
232
+  }
233
+
234
+  // POST payload
235
+  if (ret.cmd == "POST") {
236
+    size_t size = 0;
237
+    if (ret.params.count("Content-Length"))
238
+      size = atoi(ret.params["Content-Length"].c_str());
239
+    if (size) {
240
+      char* postBuf = new char[size + 1];
241
+      postBuf[size] = 0;
242
+      size_t rem = 0;
243
+
244
+      // copy existing to new buffer
245
+      if ((int)rcvd > brk - buf) {
246
+        rem = std::min(size, rcvd - (brk - buf));
247
+        memcpy(postBuf, brk, rem);
248
+      }
249
+
250
+      rcvd = 0;
251
+
252
+      if (rem < size) {
253
+        while ((curRcvd = read(connection, postBuf + rcvd + rem, size - rem))) {
254
+          if (curRcvd == -1 && (errno == EAGAIN || errno == EINTR)) continue;
255
+          if (curRcvd == -1) {
256
+            postBuf[rcvd + 1] = 0;
257
+            break;
258
+          }
259
+          rcvd += curRcvd;
260
+          if (rcvd == size - rem) break;
261
+        }
262
+      }
263
+
264
+      ret.payload = postBuf;
265
+      delete[] postBuf;
266
+    }
267
+  }
268
+
269
+  return ret;
270
+}
271
+
272
+// _____________________________________________________________________________
273
+std::string HttpServer::compress(const std::string& str, std::string* enc) {
274
+#ifdef ZLIB_FOUND
275
+  // do not compress small payloads
276
+  if (str.size() < 500) return str;
277
+
278
+  std::string ret;
279
+
280
+  // based on http://www.zlib.net/zlib_how.html
281
+  z_stream defStr;
282
+  defStr.zalloc = Z_NULL;
283
+  defStr.zfree = Z_NULL;
284
+  defStr.opaque = Z_NULL;
285
+  defStr.avail_in = 0;
286
+  defStr.next_in = Z_NULL;
287
+
288
+  // fail silently with no compression at all
289
+  if (deflateInit2(&defStr, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8,
290
+                   Z_DEFAULT_STRATEGY) != Z_OK)
291
+    return str;
292
+
293
+  defStr.next_in = reinterpret_cast<z_const Bytef*>(str.c_str());
294
+  defStr.avail_in = static_cast<unsigned int>(str.size());
295
+
296
+  size_t cSize = 0;
297
+  do {
298
+    if (ret.size() < (cSize + BSIZE_C)) ret.resize(cSize + BSIZE_C);
299
+    defStr.avail_out = BSIZE_C;
300
+    defStr.next_out = reinterpret_cast<Bytef*>(&ret[0] + cSize);
301
+    deflate(&defStr, Z_FINISH);
302
+    cSize += BSIZE_C - defStr.avail_out;
303
+  } while (defStr.avail_out == 0);
304
+
305
+  deflateEnd(&defStr);
306
+  ret.resize(cSize);
307
+
308
+  if (ret.size() > str.size()) return str;
309
+  *enc = "gzip";
310
+  return ret;
311
+#else
312
+  return str;
313
+#endif
314
+}
315
+
316
+// _____________________________________________________________________________
317
+void HttpServer::run() {
318
+  Socket socket(_port);
319
+
320
+  std::vector<std::thread> thrds(_threads);
321
+  for (auto& thr : thrds) thr = std::thread(&HttpServer::handle, this);
322
+
323
+  while (1) _jobs.add(socket.wait());
324
+}
325
+
326
+// _____________________________________________________________________________
327
+void Queue::add(int c) {
328
+  if (c < 0) return;
329
+  {
330
+    std::unique_lock<std::mutex> lock(_mut);
331
+    _jobs.push(c);
332
+  }
333
+  _hasNew.notify_one();
334
+}
335
+
336
+// _____________________________________________________________________________
337
+int Queue::get() {
338
+  std::unique_lock<std::mutex> lock(_mut);
339
+  while (_jobs.empty()) _hasNew.wait(lock);
340
+  int next = _jobs.front();
341
+  _jobs.pop();
342
+  return next;
343
+}

+ 139 - 0
src/util/http/Server.h

@@ -0,0 +1,139 @@
1
+// Copyright 2018, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include <condition_variable>
6
+#include <fstream>
7
+#include <iostream>
8
+#include <map>
9
+#include <mutex>
10
+#include <queue>
11
+#include <stdexcept>
12
+#include <string>
13
+#include <thread>
14
+#include <unordered_map>
15
+#include <vector>
16
+
17
+#include <unistd.h>
18
+#include <cerrno>
19
+#include <cstdio>
20
+#include <cstdlib>
21
+#include <cstring>
22
+
23
+#ifndef UTIL_HTTP_SERVER_H_
24
+#define UTIL_HTTP_SERVER_H_
25
+
26
+namespace util {
27
+namespace http {
28
+
29
+// socket backlog size
30
+const static size_t BLOG = 128;
31
+// socket read buffer size
32
+const static size_t BSIZE = 4 * 1024;
33
+// zlib compression buffer size
34
+const size_t BSIZE_C = 128 * 1024;
35
+
36
+// states for HTTP header parser
37
+enum HeaderState { NONE, I_COM, I_URL, I_VER, A_KEY, I_KEY, A_VAL, I_VAL };
38
+
39
+/*
40
+ * HTTP Error
41
+ */
42
+class HttpErr : public std::exception {
43
+ public:
44
+  HttpErr(std::string msg) : _msg(msg) {}
45
+  ~HttpErr() throw() {}
46
+
47
+  virtual const char* what() const throw() { return _msg.c_str(); }
48
+
49
+ private:
50
+  std::string _msg;
51
+};
52
+
53
+/*
54
+ * HTTP Request
55
+ */
56
+struct Req {
57
+  std::string cmd, url, ver, payload;
58
+  std::unordered_map<std::string, std::string> params;
59
+};
60
+
61
+/*
62
+ * HTTP Answer
63
+ */
64
+struct Answer {
65
+  Answer() : status(""), pl(""), gzip(false) {}
66
+  Answer(const std::string& status, const std::string& pl)
67
+      : status(status), pl(pl), gzip(false) {}
68
+  Answer(const std::string& status, const std::string& pl, bool gz)
69
+      : status(status), pl(pl), gzip(gz) {}
70
+  std::string status, pl;
71
+  bool gzip;
72
+  std::unordered_map<std::string, std::string> params;
73
+};
74
+
75
+/*
76
+ * Virtual handler provider class
77
+ */
78
+class Handler {
79
+ public:
80
+  virtual Answer handle(const Req& request, int connection) const = 0;
81
+};
82
+
83
+/*
84
+ * Queue of connections to handle
85
+ */
86
+class Queue {
87
+ public:
88
+  void add(int c);
89
+  int get();
90
+
91
+ private:
92
+  std::mutex _mut;
93
+  std::queue<int> _jobs;
94
+  std::condition_variable _hasNew;
95
+};
96
+
97
+/*
98
+ * Socket wrapper
99
+ */
100
+class Socket {
101
+ public:
102
+  Socket(int port);
103
+  ~Socket();
104
+  int wait();
105
+
106
+ private:
107
+  int _sock;
108
+};
109
+
110
+/*
111
+ * Simple HTTP server, must provide a pointer to a class instance implementing
112
+ * virtual class Handler.
113
+ */
114
+class HttpServer {
115
+ public:
116
+  HttpServer(int port, const Handler* h) : HttpServer(port, h, 0) {}
117
+  HttpServer(int port, const Handler* h, size_t threads)
118
+      : _port(port), _handler(h), _threads(threads) {
119
+    if (!_threads) _threads = 8 * std::thread::hardware_concurrency();
120
+  }
121
+  void run();
122
+
123
+ private:
124
+  int _port;
125
+  Queue _jobs;
126
+  const Handler* _handler;
127
+  size_t _threads;
128
+
129
+  void handle();
130
+
131
+  static void send(int sock, Answer* aw);
132
+  static Req getReq(int connection);
133
+  static std::string compress(const std::string& str, std::string* enc);
134
+  static bool gzipSupport(const Req& req);
135
+};
136
+}  // http
137
+}  // util
138
+
139
+#endif  // UTIL_HTTP_SERVER_H_

+ 173 - 0
src/util/json/Writer.cpp

@@ -0,0 +1,173 @@
1
+// Copyright 2018, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include <iomanip>
6
+#include "Writer.h"
7
+#include "util/String.h"
8
+using namespace util;
9
+using namespace json;
10
+
11
+using std::ostream;
12
+using std::string;
13
+using std::map;
14
+
15
+// _____________________________________________________________________________
16
+Writer::Writer(std::ostream* out)
17
+    : _out(out), _pretty(false), _indent(2), _floatPrec(10) {}
18
+
19
+// _____________________________________________________________________________
20
+Writer::Writer(std::ostream* out, size_t prec)
21
+    : _out(out), _pretty(false), _indent(2), _floatPrec(prec) {}
22
+
23
+// _____________________________________________________________________________
24
+Writer::Writer(std::ostream* out, size_t prec, bool pret)
25
+    : _out(out), _pretty(pret), _indent(2), _floatPrec(prec) {}
26
+
27
+// _____________________________________________________________________________
28
+Writer::Writer(std::ostream* out, size_t prec, bool pret, size_t indent)
29
+    : _out(out), _pretty(pret), _indent(indent), _floatPrec(prec) {}
30
+
31
+// _____________________________________________________________________________
32
+void Writer::obj() {
33
+  if (!_stack.empty() && _stack.top().type == OBJ)
34
+    throw WriterException("Object not allowed as key");
35
+  if (!_stack.empty() && _stack.top().type == KEY) _stack.pop();
36
+  if (!_stack.empty() && _stack.top().type == ARR) valCheck();
37
+  if (_stack.size() && _stack.top().type == ARR) prettor();
38
+  *_out << "{";
39
+  _stack.push({OBJ, 1});
40
+}
41
+
42
+// _____________________________________________________________________________
43
+void Writer::key(const std::string& k) {
44
+  if (_stack.empty() || _stack.top().type != OBJ)
45
+    throw WriterException("Keys only allowed in objects.");
46
+  if (!_stack.top().empty) (*_out) << "," << (_pretty ? " " : "");
47
+  _stack.top().empty = 0;
48
+  prettor();
49
+  *_out << "\"" << k << "\""
50
+        << ":" << (_pretty ? " " : "");
51
+  _stack.push({KEY, 1});
52
+}
53
+
54
+// _____________________________________________________________________________
55
+void Writer::valCheck() {
56
+  if (_stack.empty() || (_stack.top().type != KEY && _stack.top().type != ARR))
57
+    throw WriterException("Value not allowed here.");
58
+  if (!_stack.empty() && _stack.top().type == KEY) _stack.pop();
59
+  if (!_stack.empty() && _stack.top().type == ARR) {
60
+    if (!_stack.top().empty) (*_out) << "," << (_pretty ? " " : "");
61
+    _stack.top().empty = 0;
62
+  }
63
+}
64
+
65
+// _____________________________________________________________________________
66
+void Writer::val(const std::string& v) {
67
+  valCheck();
68
+  *_out << "\"" << util::jsonStringEscape(v) << "\"";
69
+}
70
+
71
+// _____________________________________________________________________________
72
+void Writer::val(const char* v) {
73
+  valCheck();
74
+  *_out << "\"" << util::jsonStringEscape(v) << "\"";
75
+}
76
+
77
+// _____________________________________________________________________________
78
+void Writer::val(bool v) {
79
+  valCheck();
80
+  *_out << (v ? "true" : "false");
81
+}
82
+
83
+// _____________________________________________________________________________
84
+void Writer::val(int v) {
85
+  valCheck();
86
+  *_out << v;
87
+}
88
+
89
+// _____________________________________________________________________________
90
+void Writer::val(double v) {
91
+  valCheck();
92
+  *_out << std::fixed << std::setprecision(_floatPrec) << v;
93
+}
94
+
95
+// _____________________________________________________________________________
96
+void Writer::val(Null) {
97
+  valCheck();
98
+  *_out << "null";
99
+}
100
+
101
+// _____________________________________________________________________________
102
+void Writer::val(const Val& v) {
103
+  switch (v.type) {
104
+    case Val::JSNULL:
105
+      val(Null());
106
+      return;
107
+    case Val::INT:
108
+      val(v.i);
109
+      return;
110
+    case Val::FLOAT:
111
+      val(v.f);
112
+      return;
113
+    case Val::BOOL:
114
+      val((bool)v.i);
115
+      return;
116
+    case Val::STRING:
117
+      val(v.str);
118
+      return;
119
+    case Val::ARRAY:
120
+      arr();
121
+      for (const Val& varr : v.arr) val(varr);
122
+      close();
123
+      return;
124
+    case Val::DICT:
125
+      obj();
126
+      for (const auto& vdic : v.dict) {
127
+        keyVal(vdic.first, vdic.second);
128
+      };
129
+      close();
130
+      return;
131
+  }
132
+}
133
+
134
+// _____________________________________________________________________________
135
+void Writer::arr() {
136
+  if (!_stack.empty() && _stack.top().type == OBJ)
137
+    throw WriterException("Array not allowed as key");
138
+  if (!_stack.empty() && _stack.top().type == KEY) _stack.pop();
139
+  if (!_stack.empty() && _stack.top().type == ARR) valCheck();
140
+  *_out << "[";
141
+  _stack.push({ARR, 1});
142
+}
143
+
144
+// _____________________________________________________________________________
145
+void Writer::prettor() {
146
+  if (_pretty) {
147
+    *_out << "\n";
148
+    for (size_t i = 0; i < _indent * _stack.size(); i++) (*_out) << " ";
149
+  }
150
+}
151
+
152
+// _____________________________________________________________________________
153
+void Writer::closeAll() {
154
+  while (!_stack.empty()) close();
155
+}
156
+
157
+// _____________________________________________________________________________
158
+void Writer::close() {
159
+  if (_stack.empty()) return;
160
+  switch (_stack.top().type) {
161
+    case OBJ:
162
+      _stack.pop();
163
+      prettor();
164
+      (*_out) << "}";
165
+      break;
166
+    case ARR:
167
+      _stack.pop();
168
+      (*_out) << "]";
169
+      break;
170
+    case KEY:
171
+      throw WriterException("Missing value.");
172
+  }
173
+}

+ 108 - 0
src/util/json/Writer.h

@@ -0,0 +1,108 @@
1
+// Copyright 2018, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_JSON_WRITER_H_
6
+#define UTIL_JSON_WRITER_H_
7
+
8
+#include <map>
9
+#include <ostream>
10
+#include <stack>
11
+#include <string>
12
+#include <vector>
13
+
14
+namespace util {
15
+namespace json {
16
+
17
+class WriterException : public std::exception {
18
+ public:
19
+  WriterException(std::string msg) : _msg(msg) {}
20
+  ~WriterException() throw() {}
21
+
22
+  virtual const char* what() const throw() { return _msg.c_str(); };
23
+
24
+ private:
25
+  std::string _msg;
26
+};
27
+
28
+struct Null {};
29
+
30
+struct Val {
31
+  enum VAL_T { INT, FLOAT, STRING, ARRAY, DICT, BOOL, JSNULL };
32
+  VAL_T type;
33
+  int i;
34
+  double f;
35
+  std::string str;
36
+  std::vector<Val> arr;
37
+  std::map<std::string, Val> dict;
38
+
39
+  Val() { type = DICT; }
40
+  Val(Null) { type = JSNULL; }
41
+  Val(const std::vector<Val>& arrC) { arr = arrC, type = ARRAY; }
42
+  Val(const std::map<std::string, Val>& dC) { dict = dC, type = DICT; }
43
+  Val(const std::string& strC) { str = strC, type = STRING; }
44
+  Val(const char* strC) { str = strC, type = STRING; }
45
+  Val(double fC) { f = fC, type = FLOAT; }
46
+  Val(int iC) { i = iC, type = INT; }
47
+  Val(bool fC) { i = fC, type = BOOL; }
48
+};
49
+
50
+typedef int Int;
51
+typedef double Float;
52
+typedef bool Bool;
53
+typedef std::string String;
54
+typedef std::vector<Val> Array;
55
+typedef std::map<std::string, Val> Dict;
56
+
57
+// simple JSON writer class without much overhead
58
+class Writer {
59
+ public:
60
+  explicit Writer(std::ostream* out);
61
+  Writer(std::ostream* out, size_t prec);
62
+  Writer(std::ostream* out, size_t prec, bool pretty);
63
+  Writer(std::ostream* out, size_t prec, bool pretty, size_t indent);
64
+  ~Writer(){};
65
+
66
+  void obj();
67
+  void arr();
68
+  void key(const std::string& k);
69
+  void val(const std::string& v);
70
+  void val(const char* v);
71
+  void val(double v);
72
+  void val(int v);
73
+  void val(bool v);
74
+  void val(Null);
75
+  void val(const Val& v);
76
+  template <typename V>
77
+  void keyVal(const std::string& k, const V& v) {
78
+    key(k);
79
+    val(v);
80
+  }
81
+
82
+  void close();
83
+  void closeAll();
84
+
85
+ private:
86
+  std::ostream* _out;
87
+
88
+  enum NODE_T { OBJ, ARR, KEY };
89
+
90
+  struct Node {
91
+    NODE_T type;
92
+    bool empty;
93
+  };
94
+
95
+  std::stack<Node> _stack;
96
+
97
+  bool _pretty;
98
+  size_t _indent;
99
+  size_t _floatPrec;
100
+
101
+  void valCheck();
102
+  void prettor();
103
+};
104
+
105
+}  // namespace json
106
+}  // namespace util
107
+
108
+#endif  // UTIL_JSON_WRITER_H_

+ 54 - 0
src/util/log/Log.h

@@ -0,0 +1,54 @@
1
+// Copyright 2017, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_LOG_LOG_H_
6
+#define UTIL_LOG_LOG_H_
7
+
8
+#include <chrono>
9
+#include <iomanip>
10
+#include <iostream>
11
+
12
+#define VDEBUG 4
13
+#define DEBUG 3
14
+#define INFO 2
15
+#define WARN 1
16
+#define ERROR 0
17
+
18
+#ifndef LOGLEVEL
19
+#define LOGLEVEL 2
20
+#endif
21
+
22
+// compiler will optimize statement away if x > LOGLEVEL
23
+#define LOG(x) if (x <= LOGLEVEL) util::Log<x>().log()
24
+
25
+using std::setfill;
26
+using std::setw;
27
+using namespace std::chrono;
28
+
29
+namespace util {
30
+
31
+static const char* LOGS[] = {"ERROR", "WARN ", "INFO ", "DEBUG", "DEBUG"};
32
+
33
+template <char LVL>
34
+class Log {
35
+ public:
36
+  Log() { if (LVL == ERROR) os = &std::cerr; else os = &std::cout; }
37
+  ~Log() { (*os) << std::endl; }
38
+  std::ostream& log() { return ts() << LOGS[(size_t)LVL] << ": "; }
39
+
40
+ private:
41
+  std::ostream* os;
42
+  std::ostream& ts() {
43
+    char tl[20];
44
+    auto n = system_clock::now();
45
+    time_t tt = system_clock::to_time_t(n);
46
+    int m = duration_cast<milliseconds>(n-time_point_cast<seconds>(n)).count();
47
+    struct tm t = *localtime(&tt);
48
+    strftime(tl, 20, "%Y-%m-%d %H:%M:%S", &t);
49
+    return (*os) << "[" << tl << "." << setfill('0') << setw(3) << m << "] ";
50
+  }
51
+};
52
+}
53
+
54
+#endif  // UTIL_LOG_LOG_H_

+ 6 - 0
src/util/tests/CMakeLists.txt

@@ -0,0 +1,6 @@
1
+include_directories(
2
+	${TRANSITMAP_INCLUDE_DIR}
3
+)
4
+
5
+add_executable(utilTest TestMain.cpp)
6
+target_link_libraries(utilTest util)

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1456 - 0
src/util/tests/TestMain.cpp


Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 1446 - 0
src/util/tests/lest.h


+ 182 - 0
src/util/xml/XmlWriter.cpp

@@ -0,0 +1,182 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#include <algorithm>
6
+#include <map>
7
+#include <ostream>
8
+#include <stack>
9
+#include <string>
10
+#include "XmlWriter.h"
11
+
12
+using namespace util;
13
+using namespace xml;
14
+
15
+using std::ostream;
16
+using std::string;
17
+using std::map;
18
+
19
+// _____________________________________________________________________________
20
+XmlWriter::XmlWriter(std::ostream* out)
21
+    : _out(out), _pretty(false), _indent(4) {}
22
+
23
+// _____________________________________________________________________________
24
+XmlWriter::XmlWriter(std::ostream* out, bool pret)
25
+    : _out(out), _pretty(pret), _indent(4) {}
26
+
27
+// _____________________________________________________________________________
28
+XmlWriter::XmlWriter(std::ostream* out, bool pret, size_t indent)
29
+    : _out(out), _pretty(pret), _indent(indent) {}
30
+
31
+// _____________________________________________________________________________
32
+void XmlWriter::openTag(const string& tag, const map<string, string>& attrs) {
33
+  if (!_nstack.empty() && _nstack.top().t == COMMENT) {
34
+    throw XmlWriterException("Opening tags not allowed while inside comment.");
35
+  }
36
+
37
+  checkTagName(tag);
38
+  closeHanging();
39
+  doIndent();
40
+
41
+  *_out << "<" << tag;
42
+
43
+  for (auto kv : attrs) {
44
+    *_out << " ";
45
+    putEsced(_out, kv.first, '"');
46
+    *_out << "=\"";
47
+    putEsced(_out, kv.second, '"');
48
+    *_out << "\"";
49
+  }
50
+
51
+  _nstack.push(XmlNode(TAG, tag, true));
52
+}
53
+
54
+// _____________________________________________________________________________
55
+void XmlWriter::openTag(const string& tag) {
56
+  openTag(tag, map<string, string>());
57
+}
58
+
59
+// _____________________________________________________________________________
60
+void XmlWriter::openTag(const string& tag, const string& k, const string& v) {
61
+  map<string, string> kv;
62
+  kv[k] = v;
63
+  openTag(tag, kv);
64
+}
65
+
66
+// _____________________________________________________________________________
67
+void XmlWriter::openComment() {
68
+  // don't allow nested comments
69
+  if (!_nstack.empty() && _nstack.top().t == COMMENT) return;
70
+
71
+  closeHanging();
72
+  doIndent();
73
+
74
+  *_out << "<!-- ";
75
+
76
+  _nstack.push(XmlNode(COMMENT, "", false));
77
+}
78
+
79
+// _____________________________________________________________________________
80
+void XmlWriter::writeText(const string& text) {
81
+  if (_nstack.empty()) {
82
+    throw XmlWriterException("Text content not allowed in prolog / trailing.");
83
+  }
84
+  closeHanging();
85
+  doIndent();
86
+  putEsced(_out, text, ' ');
87
+}
88
+
89
+// _____________________________________________________________________________
90
+void XmlWriter::closeTag() {
91
+  while (!_nstack.empty() && _nstack.top().t == TEXT) _nstack.pop();
92
+
93
+  if (_nstack.empty()) return;
94
+
95
+  if (_nstack.top().t == COMMENT) {
96
+    _nstack.pop();
97
+    doIndent();
98
+    *_out << " -->";
99
+  } else if (_nstack.top().t == TAG) {
100
+    if (_nstack.top().hanging) {
101
+      *_out << " />";
102
+      _nstack.pop();
103
+    } else {
104
+      string tag = _nstack.top().pload;
105
+      _nstack.pop();
106
+      doIndent();
107
+      *_out << "</" << tag << ">";
108
+    }
109
+  }
110
+}
111
+
112
+// _____________________________________________________________________________
113
+void XmlWriter::closeTags() {
114
+  while (!_nstack.empty()) closeTag();
115
+}
116
+
117
+// _____________________________________________________________________________
118
+void XmlWriter::doIndent() {
119
+  if (_pretty) {
120
+    *_out << std::endl;
121
+    for (size_t i = 0; i < _nstack.size() * _indent; i++) *_out << " ";
122
+  }
123
+}
124
+
125
+// _____________________________________________________________________________
126
+void XmlWriter::closeHanging() {
127
+  if (_nstack.empty()) return;
128
+
129
+  if (_nstack.top().hanging) {
130
+    *_out << ">";
131
+    _nstack.top().hanging = false;
132
+  } else if (_nstack.top().t == TEXT) {
133
+    _nstack.pop();
134
+  }
135
+}
136
+
137
+// _____________________________________________________________________________
138
+void XmlWriter::putEsced(ostream* out, const string& str, char quot) {
139
+  if (!_nstack.empty() && _nstack.top().t == COMMENT) {
140
+    *out << str;
141
+    return;
142
+  }
143
+
144
+  for (const char& c : str) {
145
+    if (quot == '"' && c == '"')
146
+      *out << "&quot;";
147
+    else if (quot == '\'' && c == '\'')
148
+      *out << "&apos;";
149
+    else if (c == '<')
150
+      *out << "&lt;";
151
+    else if (c == '>')
152
+      *out << "&gt;";
153
+    else if (c == '&')
154
+      *out << "&amp;";
155
+    else
156
+      *out << c;
157
+  }
158
+}
159
+
160
+// _____________________________________________________________________________
161
+void XmlWriter::checkTagName(const string& str) const {
162
+  if (!isalpha(str[0]) && str[0] != '_')
163
+    throw XmlWriterException(
164
+        "XML elements must start with either a letter "
165
+        "or an underscore");
166
+
167
+  string begin = str.substr(0, 3);
168
+  std::transform(begin.begin(), begin.end(), begin.begin(), ::tolower);
169
+  if (begin == "xml")
170
+    throw XmlWriterException(
171
+        "XML elements cannot start with"
172
+        " XML, xml, Xml etc.");
173
+
174
+  for (const char& c : str) {
175
+    // we allow colons in tag names for primitive namespace support
176
+    if (!isalpha(c) && !isdigit(c) && c != '-' && c != '_' && c != '.' &&
177
+        c != ':')
178
+      throw XmlWriterException(
179
+          "XML elements can only contain letters, "
180
+          "digits, hyphens, underscores and periods.");
181
+  }
182
+}

+ 91 - 0
src/util/xml/XmlWriter.h

@@ -0,0 +1,91 @@
1
+// Copyright 2016, University of Freiburg,
2
+// Chair of Algorithms and Data Structures.
3
+// Authors: Patrick Brosi <brosi@informatik.uni-freiburg.de>
4
+
5
+#ifndef UTIL_XML_XMLWRITER_H_
6
+#define UTIL_XML_XMLWRITER_H_
7
+
8
+#include <map>
9
+#include <ostream>
10
+#include <stack>
11
+#include <string>
12
+
13
+namespace util {
14
+namespace xml {
15
+
16
+class XmlWriterException : public std::exception {
17
+ public:
18
+  XmlWriterException(std::string msg) : _msg(msg) {}
19
+  ~XmlWriterException() throw() {}
20
+
21
+  virtual const char* what() const throw() { return _msg.c_str(); };
22
+
23
+ private:
24
+  std::string _msg;
25
+};
26
+
27
+// simple XML writer class without much overhead
28
+class XmlWriter {
29
+ public:
30
+  explicit XmlWriter(std::ostream* out);
31
+  XmlWriter(std::ostream* out, bool pretty);
32
+  XmlWriter(std::ostream* out, bool pretty, size_t indent);
33
+  ~XmlWriter(){};
34
+
35
+  // open tag without attributes
36
+  void openTag(const std::string& tag);
37
+
38
+  // open tag with single attribute (for convenience...)
39
+  void openTag(const std::string& tag, const std::string& key,
40
+               const std::string& val);
41
+
42
+  // open tag with attribute list
43
+  void openTag(const std::string& tag,
44
+               const std::map<std::string, std::string>& attrs);
45
+
46
+  // open comment
47
+  void openComment();
48
+
49
+  // write text
50
+  void writeText(const std::string& text);
51
+
52
+  // close tag
53
+  void closeTag();
54
+
55
+  // close all open tags, essentially closing the document
56
+  void closeTags();
57
+
58
+ private:
59
+  enum XML_NODE_T { TAG, TEXT, COMMENT };
60
+
61
+  struct XmlNode {
62
+    XmlNode(XML_NODE_T t, const std::string& pload, bool hanging)
63
+        : t(t), pload(pload), hanging(hanging) {}
64
+    XML_NODE_T t;
65
+    std::string pload;
66
+    bool hanging;
67
+  };
68
+
69
+  std::ostream* _out;
70
+  std::stack<XmlNode> _nstack;
71
+
72
+  bool _pretty;
73
+  size_t _indent;
74
+
75
+  // handles indentation
76
+  void doIndent();
77
+
78
+  // close "hanging" tags
79
+  void closeHanging();
80
+
81
+  // pushes XML escaped text to stream
82
+  void putEsced(std::ostream* out, const std::string& str, char quot);
83
+
84
+  // checks tag names for validiy
85
+  void checkTagName(const std::string& str) const;
86
+};
87
+
88
+}  // namespace xml
89
+}  // namespace util
90
+
91
+#endif  // UTIL_XML_XMLWRITER_H_