diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile
index 6d6a4e895..53d336f81 100644
--- a/.gitpod.dockerfile
+++ b/.gitpod.dockerfile
@@ -1,9 +1,9 @@
-FROM gitpod/workspace-full
+FROM gitpod/workspace-full-vnc
RUN sudo apt-get update \
- && sudo apt-get install -y \
- doxygen \
- graphviz \
- ninja-build \
- && pip install cpplint \
- && sudo rm -rf /var/lib/apt/lists/*
+ && sudo apt-get install -y \
+ doxygen \
+ graphviz \
+ ninja-build \
+ && pip install cpplint \
+ && sudo rm -rf /var/lib/apt/lists/*
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 712c3db42..d7fa88559 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -17,7 +17,28 @@ if(MSVC)
endif(MSVC)
option(USE_OPENMP "flag to use OpenMP for multithreading" ON)
-
+if(USE_OPENMP)
+ find_package(OpenMP)
+ if (OpenMP_CXX_FOUND)
+ message(STATUS "Building with OpenMP Multithreading.")
+ else()
+ message(STATUS "No OpenMP found, no multithreading.")
+ endif()
+endif()
+
+add_subdirectory(math)
+add_subdirectory(others)
+add_subdirectory(search)
+add_subdirectory(ciphers)
+add_subdirectory(strings)
+add_subdirectory(sorting)
+add_subdirectory(geometry)
+add_subdirectory(graphics)
+add_subdirectory(probability)
+add_subdirectory(data_structures)
+add_subdirectory(machine_learning)
+add_subdirectory(numerical_methods)
+
cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0057 NEW)
find_package(Doxygen OPTIONAL_COMPONENTS dot dia)
@@ -34,6 +55,7 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_STRIP_CODE_COMMENTS NO)
set(DOXYGEN_EXT_LINKS_IN_WINDOW YES)
set(DOXYGEN_BUILTIN_STL_SUPPORT YES)
+ set(DOXYGEN_ENABLE_PREPROCESSING YES)
set(DOXYGEN_CLANG_ASSISTED_PARSING YES)
set(DOXYGEN_FILE_PATTERNS *.cpp *.h *.hpp *.md)
set(DOXYGEN_MATHJAX_EXTENSIONS TeX/AMSmath TeX/AMSsymbols)
@@ -48,6 +70,12 @@ if(DOXYGEN_FOUND)
set(DOXYGEN_INTERACTIVE_SVG YES)
set(DOXYGEN_DOT_IMAGE_FORMAT "svg")
endif()
+ if(OPENMP_FOUND)
+ set(DOXYGEN_PREDEFINED "_OPENMP=1")
+ endif()
+ if(GLUT_FOUND)
+ set(DOXYGEN_PREDEFINED ${DOXYGEN_PREDEFINED} "GLUT_FOUND=1")
+ endif()
doxygen_add_docs(
doc
@@ -56,27 +84,6 @@ if(DOXYGEN_FOUND)
)
endif()
-if(USE_OPENMP)
- find_package(OpenMP)
- if (OpenMP_CXX_FOUND)
- message(STATUS "Building with OpenMP Multithreading.")
- else()
- message(STATUS "No OpenMP found, no multithreading.")
- endif()
-endif()
-
-add_subdirectory(math)
-add_subdirectory(others)
-add_subdirectory(search)
-add_subdirectory(ciphers)
-add_subdirectory(strings)
-add_subdirectory(sorting)
-add_subdirectory(geometry)
-add_subdirectory(probability)
-add_subdirectory(data_structures)
-add_subdirectory(machine_learning)
-add_subdirectory(numerical_methods)
-
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
diff --git a/DIRECTORY.md b/DIRECTORY.md
index f53d2f7ab..0f7e9a053 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -84,6 +84,9 @@
* [Topological Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/topological_sort.cpp)
* [Topological Sort By Kahns Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graph/topological_sort_by_kahns_algo.cpp)
+## Graphics
+ * [Spirograph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/graphics/spirograph.cpp)
+
## Greedy Algorithms
* [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/greedy_algorithms/dijkstra.cpp)
* [Huffman](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/greedy_algorithms/huffman.cpp)
diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt
new file mode 100644
index 000000000..2ea6ca230
--- /dev/null
+++ b/graphics/CMakeLists.txt
@@ -0,0 +1,83 @@
+find_package(OpenGL)
+if(OpenGL_FOUND)
+ find_package(GLUT)
+ if(NOT GLUT_FOUND)
+ message("FreeGLUT library will be downloaded and built.")
+ include(ExternalProject)
+ ExternalProject_Add (
+ FREEGLUT-PRJ
+ URL https://sourceforge.net/projects/freeglut/files/freeglut/3.2.1/freeglut-3.2.1.tar.gz
+ URL_MD5 cd5c670c1086358598a6d4a9d166949d
+ CMAKE_GENERATOR ${CMAKE_GENERATOR}
+ CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET}
+ CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM}
+ CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release
+ -DFREEGLUT_BUILD_SHARED_LIBS=OFF
+ -DFREEGLUT_BUILD_STATIC_LIBS=ON
+ -DFREEGLUT_BUILD_DEMOS=OFF
+ PREFIX ${CMAKE_CURRENT_BINARY_DIR}/freeglut
+ # BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/freeglut-build
+ # BUILD_IN_SOURCE ON
+ # UPDATE_COMMAND ""
+ INSTALL_COMMAND ""
+ # CONFIGURE_COMMAND ""
+ # BUILD_COMMAND ""
+ )
+ ExternalProject_Get_Property(FREEGLUT-PRJ SOURCE_DIR)
+ ExternalProject_Get_Property(FREEGLUT-PRJ BINARY_DIR)
+ set(FREEGLUT_BIN_DIR ${BINARY_DIR})
+ set(FREEGLUT_SRC_DIR ${SOURCE_DIR})
+ # add_library(libfreeglut STATIC IMPORTED)
+ # set_target_properties(libfreeglut PROPERTIES IMPORTED_LOCATION ${FREEGLUT_BIN_DIR})
+
+ # set(FREEGLUT_BUILD_DEMOS OFF CACHE BOOL "")
+ # set(FREEGLUT_BUILD_SHARED_LIBS OFF CACHE BOOL "")
+ # set(FREEGLUT_BUILD_STATIC_LIBS ON CACHE BOOL "")
+ # add_subdirectory(${FREEGLUT_SRC_DIR} ${FREEGLUT_BIN_DIR} EXCLUDE_FROM_ALL)
+ # add_subdirectory(${BINARY_DIR})
+ # find_package(FreeGLUT)
+ endif(NOT GLUT_FOUND)
+else(OpenGL_FOUND)
+ message(WARNING "OPENGL not found. Will not build graphical outputs.")
+endif(OpenGL_FOUND)
+
+# If necessary, use the RELATIVE flag, otherwise each source file may be listed
+# with full pathname. RELATIVE may makes it easier to extract an executable name
+# automatically.
+file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
+# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
+# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
+foreach( testsourcefile ${APP_SOURCES} )
+ # I used a simple string replace, to cut off .cpp.
+ string( REPLACE ".cpp" "" testname ${testsourcefile} )
+ add_executable( ${testname} ${testsourcefile} )
+
+ set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
+ if(OpenMP_CXX_FOUND)
+ target_link_libraries(${testname} PRIVATE OpenMP::OpenMP_CXX)
+ endif()
+
+ if(OpenGL_FOUND)
+ if(NOT GLUT_FOUND)
+ add_dependencies(${testname} FREEGLUT-PRJ)
+ target_compile_definitions(${testname} PRIVATE FREEGLUT_STATIC)
+ target_include_directories(${testname} PRIVATE ${FREEGLUT_SRC_DIR}/include)
+ target_link_directories(${testname} PRIVATE ${FREEGLUT_BIN_DIR}/lib)
+ target_link_libraries(${testname} PRIVATE OpenGL::GL)
+ target_link_libraries(${testname} INTERFACE FREEGLUT-PRJ)
+ # target_include_directories(${testname} PRIVATE ${FREEGLUT_INCLUDE_DIRS})
+ # target_link_libraries(${testname} INTERFACE freeglut_static)
+ else()
+ target_include_directories(${testname} PRIVATE ${GLUT_INCLUDE_DIRS})
+ target_link_libraries(${testname} PRIVATE OpenGL::GL ${GLUT_LIBRARIES})
+ endif()
+ target_compile_definitions(${testname} PRIVATE USE_GLUT)
+ endif(OpenGL_FOUND)
+
+ if(APPLE)
+ target_compile_options(${testname} PRIVATE -Wno-deprecated)
+ endif(APPLE)
+
+ install(TARGETS ${testname} DESTINATION "bin/graphics")
+
+endforeach( testsourcefile ${APP_SOURCES} )
diff --git a/graphics/spirograph.cpp b/graphics/spirograph.cpp
new file mode 100644
index 000000000..84c17c4db
--- /dev/null
+++ b/graphics/spirograph.cpp
@@ -0,0 +1,284 @@
+/**
+ * @file
+ * @author [Krishna Vedala](https://github.com/kvedala)
+ * @brief Implementation of
+ * [Spirograph](https://en.wikipedia.org/wiki/Spirograph)
+ *
+ * @details
+ * Implementation of the program is based on the geometry shown in the figure
+ * below:
+ *
+ *
+ */
+#ifdef USE_GLUT
+#ifdef __APPLE__
+#include // include path on Macs is different
+#else
+#include
+#endif // __APPLE__
+#endif
+#define _USE_MATH_DEFINES /**< required for MSVC compiler */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef _OPENMP
+#include
+#endif
+
+/**
+ * @namespace spirograph Functions related to spirograph.cpp
+ */
+namespace spirograph {
+/** Generate spirograph curve into arrays `x` and `y` such that the i^th point
+ * in 2D is represented by `(x[i],y[i])`. The generating function is given by:
+ * \f{eqnarray*}{
+ * x &=& R\left[ (1-k) \cos (t) + l\cdot k\cdot\cos \left(\frac{1-k}{k}t\right)
+ * \right]\\
+ * y &=& R\left[ (1-k) \sin (t) - l\cdot k\cdot\sin \left(\frac{1-k}{k}t\right)
+ * \right] \f}
+ * where
+ * * \f$R\f$ is the scaling parameter that we will consider \f$=1\f$
+ * * \f$l=\frac{\rho}{r}\f$ is the relative distance of marker from the centre
+ * of inner circle and \f$0\le l\le1\f$
+ * * \f$\rho\f$ is physical distance of marker from centre of inner circle
+ * * \f$r\f$ is the radius of inner circle
+ * * \f$k=\frac{r}{R}\f$ is the ratio of radius of inner circle to outer circle
+ * and \f$0
+void spirograph(std::array, N> *points, double l,
+ double k, double rot) {
+ double dt = rot * 2.f * M_PI / N;
+ double R = 1.f;
+ const double k1 = 1.f - k;
+ int32_t step = 0;
+
+#ifdef _OPENMP
+#pragma omp for
+#endif
+ for (step = 0; step < N; step++) {
+ double t = dt * step;
+ double first = R * (k1 * std::cos(t) + l * k * std::cos(k1 * t / k));
+ double second = R * (k1 * std::sin(t) - l * k * std::sin(k1 * t / k));
+ points[0][step].first = first;
+ points[0][step].second = second;
+ }
+}
+
+/**
+ * @brief Test function to save resulting points to a CSV file.
+ *
+ */
+void test() {
+ const size_t N = 500;
+ double l = 0.3, k = 0.75, rot = 10.;
+ std::stringstream fname;
+ fname << std::setw(3) << "spirograph_" << l << "_" << k << "_" << rot
+ << ".csv";
+ std::ofstream fp(fname.str());
+ if (!fp.is_open()) {
+ perror(fname.str().c_str());
+ exit(EXIT_FAILURE);
+ }
+
+ std::array, N> points;
+
+ spirograph(&points, l, k, rot);
+
+ for (size_t i = 0; i < N; i++) {
+ fp << points[i].first << "," << points[i].first;
+ if (i < N - 1) {
+ fp << '\n';
+ }
+ }
+
+ fp.close();
+}
+
+#ifdef USE_GLUT
+static bool paused = 0; /**< flag to set pause/unpause animation */
+static const int animation_speed = 25; /**< animation delate in ms */
+
+static const double step = 0.01; /**< animation step size */
+static double l_ratio = step * 10; /**< the l-ratio defined in docs */
+static double k_ratio = step; /**< the k-ratio defined in docs */
+static const double num_rot = 20.; /**< number of rotations to simulate */
+
+/** A wrapper that is not available in all GLUT implementations.
+ */
+static inline void glutBitmapString(void *font, char *message) {
+ for (char *ch = message; *ch != '\0'; ch++) glutBitmapCharacter(font, *ch);
+}
+
+/**
+ * @brief Function to graph (x,y) points on the OpenGL graphics window.
+ *
+ * @tparam N number of points = size of array
+ * @param [in] points Array of 2D points represented as std::pair
+ * @param l the relative distance of marker from the centre of
+ * inner circle and \f$0\le l\le1\f$ to display info
+ * @param k the ratio of radius of inner circle to outer circle and \f$0
+void display_graph(const std::array, N> &points,
+ double l, double k) {
+ glClearColor(1.0f, 1.0f, 1.0f,
+ 0.0f); // Set background color to white and opaque
+ glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
+
+ glBegin(GL_LINES); // draw line segments
+ glColor3f(0.f, 0.f, 1.f); // blue
+ glPointSize(2.f); // point size in pixels
+
+ for (size_t i = 1; i < N; i++) {
+ glVertex2f(points[i - 1].first, points[i - 1].second); // line from
+ glVertex2f(points[i].first, points[i].second); // line to
+ }
+ glEnd();
+
+ glColor3f(0.f, 0.f, 0.f);
+ std::stringstream buffer;
+ buffer << std::setw(3) << "l = " << l;
+ glRasterPos2f(-.85, .85);
+ glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,
+ const_cast(buffer.str().c_str()));
+ buffer.str("");
+ buffer.clear();
+ buffer << std::setw(3) << "k = " << k;
+ glRasterPos2f(-.85, .70);
+ glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,
+ const_cast(buffer.str().c_str()));
+
+ glutSwapBuffers();
+}
+
+/**
+ * @brief Test function with animation
+ *
+ */
+void test2() {
+ const size_t N = 5000; // number of samples
+
+ static bool direction1 = true; // increment if true, otherwise decrement
+ static bool direction2 = true; // increment if true, otherwise decrement
+
+ std::array, N> points;
+
+ spirograph(&points, l_ratio, k_ratio, num_rot);
+ display_graph(points, l_ratio, k_ratio);
+
+ if (paused)
+ // if paused, do not update l_ratio and k_ratio
+ return;
+
+ if (direction1) { // increment k_ratio
+ if (k_ratio >= (1.f - step)) // maximum limit
+ direction1 = false; // reverse direction of k_ratio
+ else
+ k_ratio += step;
+ } else { // decrement k_ratio
+ if (k_ratio <= step) { // minimum limit
+ direction1 = true; // reverse direction of k_ratio
+
+ if (direction2) { // increment l_ratio
+ if (l_ratio >= (1.f - step)) // max limit of l_ratio
+ direction2 = false; // reverse direction of l_ratio
+ else
+ l_ratio += step;
+ } else { // decrement l_ratio
+ if (l_ratio <= step) // minimum limit of l_ratio
+ direction2 = true; // reverse direction of l_ratio
+ else
+ l_ratio -= step;
+ }
+ } else { // no min limit of k_ratio
+ k_ratio -= step;
+ }
+ }
+}
+
+/**
+ * @brief GLUT timer callback function to add animation delay.
+ */
+void timer_cb(int t) {
+ glutTimerFunc(animation_speed, timer_cb, 0);
+ glutPostRedisplay();
+}
+
+/**
+ * @brief Keypress event call back function.
+ *
+ * @param key ID of the key pressed
+ * @param x mouse pointer position at event
+ * @param y mouse pointer position at event
+ */
+void keyboard_cb(unsigned char key, int x, int y) {
+ switch (key) {
+ case ' ': // spacebar toggles pause
+ paused = !paused; // toggle
+ break;
+ case GLUT_KEY_UP:
+ case '+': // up arrow key
+ k_ratio += step;
+ break;
+ case GLUT_KEY_DOWN:
+ case '_': // down arrow key
+ k_ratio -= step;
+ break;
+ case GLUT_KEY_RIGHT:
+ case '=': // left arrow key
+ l_ratio += step;
+ break;
+ case GLUT_KEY_LEFT:
+ case '-': // right arrow key
+ l_ratio -= step;
+ break;
+ case 0x1B: // escape key exits
+ exit(EXIT_SUCCESS);
+ default:
+ return;
+ }
+}
+#endif
+} // namespace spirograph
+
+/** Main function */
+int main(int argc, char **argv) {
+ spirograph::test();
+
+#ifdef USE_GLUT
+ glutInit(&argc, argv);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
+ glutCreateWindow("Spirograph");
+ glutInitWindowSize(400, 400);
+ // glutIdleFunc(glutPostRedisplay);
+ glutTimerFunc(spirograph::animation_speed, spirograph::timer_cb, 0);
+ glutKeyboardFunc(spirograph::keyboard_cb);
+ glutDisplayFunc(spirograph::test2);
+ glutMainLoop();
+#endif
+
+ return 0;
+}