Compare commits
No commits in common. "ca820ff1086a55da2c025b7b168d20a8a98ccedf" and "63be32de7cedabd15fd10dfb5419283c5d0884ea" have entirely different histories.
ca820ff108
...
63be32de7c
|
|
@ -0,0 +1,23 @@
|
||||||
|
FROM alpine:3.21.3
|
||||||
|
|
||||||
|
# Install tools required for building.
|
||||||
|
RUN apk update && \
|
||||||
|
apk add --no-cache \
|
||||||
|
autoconf \
|
||||||
|
bash \
|
||||||
|
build-base \
|
||||||
|
cmake \
|
||||||
|
clang \
|
||||||
|
clang-extra-tools \
|
||||||
|
gdb \
|
||||||
|
git \
|
||||||
|
libstdc++ \
|
||||||
|
libtool \
|
||||||
|
linux-headers \
|
||||||
|
ninja \
|
||||||
|
m4 \
|
||||||
|
perl \
|
||||||
|
python3 \
|
||||||
|
py3-pip && \
|
||||||
|
pip install --break-system-packages conan && \
|
||||||
|
conan profile detect
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "C++",
|
"name": "C++",
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "../devcontainer.Dockerfile"
|
"dockerfile": "Dockerfile"
|
||||||
},
|
},
|
||||||
// Configure tool-specific properties.
|
// Configure tool-specific properties.
|
||||||
"customizations": {
|
"customizations": {
|
||||||
"vscode": {
|
"vscode": {
|
||||||
"settings": {
|
"settings": {},
|
||||||
"conan-extension.installArgs": [
|
|
||||||
"-of build",
|
|
||||||
"-s build_type=Debug"
|
|
||||||
],
|
|
||||||
},
|
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"ms-vscode.cpptools",
|
"ms-vscode.cpptools",
|
||||||
"twxs.cmake",
|
"twxs.cmake",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
find_package(Boost 1.89.0 REQUIRED COMPONENTS headers CONFIG)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
find_package(Boost 1.84.0 REQUIRED COMPONENTS headers CONFIG)
|
||||||
find_package(JPEG REQUIRED)
|
find_package(JPEG REQUIRED)
|
||||||
|
|
||||||
project(http-mandelbrot)
|
project(http-mandelbrot)
|
||||||
|
|
@ -6,7 +7,6 @@ project(http-mandelbrot)
|
||||||
add_executable(
|
add_executable(
|
||||||
${PROJECT_NAME}
|
${PROJECT_NAME}
|
||||||
./src/main.cpp
|
./src/main.cpp
|
||||||
./src/mandelbrot.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(
|
set_property(
|
||||||
|
|
|
||||||
|
|
@ -24,22 +24,19 @@
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div id="map" style="width: 100%; height: 100%;">
|
|
||||||
<div class="leaflet-bottom leaflet-left">
|
|
||||||
<input type="button" id="Btn1" value="Btn1" onclick="" class="btnStyle span3" />
|
<div id="map" style="width: 100%; height: 100%;"></div>
|
||||||
<input type="button" id="Btn2" value="Btn2" onclick="SaveRoutes()" class="btnStyle span3 leaflet-control" />
|
|
||||||
<input type="button" id="Btn3" value="Btn3" onclick="editRoutes()" class="btnStyle span3 leaflet-control" />
|
|
||||||
<span id="studentsCount" class="lblStyle span3 leaflet-control"> Ikke rutesat: </span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
const map = L.map('map', {crs: L.CRS.Simple, zoomSnap: 0}).setView([0.0, 0.0], 1);
|
const map = L.map('map', {crs: L.CRS.Simple}).setView([0.0, 0.0], 1);
|
||||||
|
|
||||||
const tiles = L.tileLayer('/render_z{z}x{x}y{y}w256h256ar8.0ai0.0maxiter200.jpg', {
|
const tiles = L.tileLayer('http://localhost:9800/render_{x}_{y}_{z}', {
|
||||||
maxZoom: 1000
|
maxZoom: 1000
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@
|
||||||
#include <bmrshared/request_handler_interface.hpp>
|
#include <bmrshared/request_handler_interface.hpp>
|
||||||
#include <bmrshared/directory_request_handler.hpp>
|
#include <bmrshared/directory_request_handler.hpp>
|
||||||
#include <bmrshared/request_response.hpp>
|
#include <bmrshared/request_response.hpp>
|
||||||
#include <bmrshared/color.hpp>
|
|
||||||
#include <boost/asio/signal_set.hpp>
|
#include <boost/asio/signal_set.hpp>
|
||||||
#include <boost/gil/image.hpp>
|
#include <boost/gil/image.hpp>
|
||||||
#include <boost/gil/image_view.hpp>
|
#include <boost/gil/image_view.hpp>
|
||||||
|
|
@ -21,10 +20,90 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include "mandelbrot.hpp"
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
const std::regex regex_renderpath(R"REGEX(\/render_z(\d+)x(-?\d+)y(-?\d+)w(\d+)h(\d+)ar(-?\d+\.\d+)ai(-?\d+\.\d+)maxiter(\d+).jpg)REGEX");
|
const std::regex regex_renderpath(R"REGEX(\/render_(-?\d+)_(-?\d+)_(\d+))REGEX");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class window
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
window(T x_min, T x_max, T y_min, T y_max)
|
||||||
|
: m_x_min(x_min), m_x_max(x_max), m_y_min(y_min), m_y_max(y_max)
|
||||||
|
{}
|
||||||
|
|
||||||
|
T size() const {
|
||||||
|
return width() * height();
|
||||||
|
}
|
||||||
|
|
||||||
|
T width() const {
|
||||||
|
return m_x_max - m_x_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
T height() const {
|
||||||
|
return m_y_max - m_y_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
T x_min() const {return m_x_min;}
|
||||||
|
T x_max() const {return m_x_max;}
|
||||||
|
T y_min() const {return m_y_min;}
|
||||||
|
T y_max() const {return m_y_max;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T m_x_min;
|
||||||
|
T m_x_max;
|
||||||
|
T m_y_min;
|
||||||
|
T m_y_max;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert a pixel coordinate to the complex domain
|
||||||
|
std::complex<double> scale(const window<int>& scr, const window<double>& fr, const std::complex<double>& c)
|
||||||
|
{
|
||||||
|
return std::complex<double>(c.real() / (double)scr.width() * fr.width() + fr.x_min(),
|
||||||
|
c.imag() / (double)scr.height() * fr.height() + fr.y_min());
|
||||||
|
}
|
||||||
|
|
||||||
|
int escape(const std::complex<double>& c,
|
||||||
|
int iter_max,
|
||||||
|
const std::function<std::complex<double>(std::complex<double>, std::complex<double>)>& func)
|
||||||
|
{
|
||||||
|
std::complex<double> z(0);
|
||||||
|
int iter = 0;
|
||||||
|
|
||||||
|
while (abs(z) < 2.0 && iter < iter_max) {
|
||||||
|
z = func(z, c);
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
return iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fractal(
|
||||||
|
const window<int>& scr,
|
||||||
|
const window<double>&fract,
|
||||||
|
int max_iterations,
|
||||||
|
const std::function<std::complex<double>(std::complex<double>, std::complex<double>)>& fractal_fn,
|
||||||
|
const std::function<void(int x, int y, int num_iter)>& painter)
|
||||||
|
{
|
||||||
|
for(int y = scr.y_min(); y < scr.y_max(); ++y)
|
||||||
|
{
|
||||||
|
for(int x = scr.x_min(); x < scr.x_max(); ++x)
|
||||||
|
{
|
||||||
|
auto num_iter = escape(
|
||||||
|
scale(scr,
|
||||||
|
fract,
|
||||||
|
std::complex<double>{double(y), double(x)}
|
||||||
|
),
|
||||||
|
max_iterations,
|
||||||
|
fractal_fn);
|
||||||
|
|
||||||
|
painter(x,y,num_iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
constexpr unsigned int config_max_simultanious_requests = 10;
|
constexpr unsigned int config_max_simultanious_requests = 10;
|
||||||
constexpr uint64_t config_request_body_limit = (10 * 1024);
|
constexpr uint64_t config_request_body_limit = (10 * 1024);
|
||||||
|
|
@ -61,61 +140,51 @@ namespace
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "GET: " << target << std::endl;
|
|
||||||
std::smatch base_match;
|
std::smatch base_match;
|
||||||
std::string tmp(target);
|
std::string tmp(target);
|
||||||
if (std::regex_match(tmp, base_match, regex_renderpath) && base_match.size() == 9)
|
if (std::regex_match(tmp, base_match, regex_renderpath) && base_match.size() == 4)
|
||||||
{
|
{
|
||||||
int z = std::stoi(base_match[1]);
|
double offset_y = std::stoi(base_match[1]);
|
||||||
int offset_y = std::stoi(base_match[2]);
|
double offset_x = std::stoi(base_match[2]);
|
||||||
int offset_x = std::stoi(base_match[3]);
|
double z = std::stoi(base_match[3]);
|
||||||
int width = std::stoi(base_match[4]);
|
|
||||||
int height = std::stoi(base_match[5]);
|
|
||||||
double a_real = std::stof(base_match[6]);
|
|
||||||
double a_img = std::stof(base_match[7]);
|
|
||||||
int max_iter = std::stoi(base_match[8]);
|
|
||||||
std::complex<float> factor_a(a_real, a_img);
|
|
||||||
|
|
||||||
auto renderfn = [offset_y, offset_x, z, width, height, factor_a, max_iter, req, target, rs, tmp]() mutable
|
auto renderfn = [offset_y, offset_x, z, req, target, rs, tmp]() mutable
|
||||||
{
|
{
|
||||||
int pixel_width = width;
|
constexpr int pixel_width = 256;
|
||||||
int pixel_height = height;
|
constexpr int pixel_height = 256;
|
||||||
int max_iterations = max_iter;
|
constexpr int max_iterations = 255;
|
||||||
|
|
||||||
|
|
||||||
boost::gil::rgb8_image_t image(pixel_width,pixel_height);
|
boost::gil::gray8_image_t image(pixel_width,pixel_height);
|
||||||
auto view = boost::gil::view(image);
|
auto view = boost::gil::view(image);
|
||||||
boost::gil::fill_pixels(view, boost::gil::rgb8_pixel_t(0));
|
boost::gil::fill_pixels(view, boost::gil::gray8_pixel_t(0));
|
||||||
|
|
||||||
auto painter = [&](int x, int y, int num_iter) -> void
|
auto painter = [&](int x, int y, int num_iter) -> void
|
||||||
{
|
{
|
||||||
if(x >= 0 && y >= 0 && x < pixel_width && y < pixel_height)
|
if(x >= 0 && y >= 0 && x < pixel_width && y < pixel_height)
|
||||||
{
|
{
|
||||||
bmrshared::color c({.h=(num_iter*2)%360,.s=1.0, .v=1.0});
|
|
||||||
auto crgb = c.rgb();
|
|
||||||
uint8_t r = crgb.r * 255;
|
|
||||||
uint8_t g = crgb.g * 255;
|
|
||||||
uint8_t b = crgb.b * 255;
|
|
||||||
|
|
||||||
|
|
||||||
const auto iter = view.at({x, y});
|
const auto iter = view.at({x, y});
|
||||||
boost::gil::color_convert(boost::gil::rgb8_pixel_t(r,g,b), *iter);
|
boost::gil::color_convert(boost::gil::gray8_pixel_t(num_iter), *iter);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto fract_fn = [](std::complex <double> z, std::complex<double> c) -> std::complex<double>
|
||||||
|
{
|
||||||
|
return z * z + c;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto zoomfactor = 1.0/std::pow(2, z);
|
||||||
|
|
||||||
const auto zoomfactor = 1.0/std::pow(2, z);
|
fractal(window<int>{0,pixel_width, 0,pixel_height},
|
||||||
window<float> src_window{offset_x * zoomfactor, (offset_x + 1)*zoomfactor, offset_y * zoomfactor ,(offset_y + 1)*zoomfactor};
|
window<double>{offset_x * zoomfactor, (offset_x + 1)*zoomfactor, offset_y * zoomfactor ,(offset_y + 1)*zoomfactor},
|
||||||
window<float> dst_window{0,pixel_width, 0,pixel_height};
|
max_iterations,
|
||||||
|
fract_fn,
|
||||||
mandelbrot<float> fractal(src_window, dst_window, max_iterations, factor_a);
|
painter);
|
||||||
fractal.apply(painter);
|
|
||||||
|
|
||||||
std::stringstream out_buffer( std::ios_base::out | std::ios_base::binary );
|
std::stringstream out_buffer( std::ios_base::out | std::ios_base::binary );
|
||||||
boost::gil::write_view(out_buffer,
|
boost::gil::write_view(out_buffer,
|
||||||
boost::gil::view(image),
|
boost::gil::view(image),
|
||||||
boost::gil::image_write_info<boost::gil::jpeg_tag>(90));
|
boost::gil::image_write_info<boost::gil::jpeg_tag>(70));
|
||||||
|
|
||||||
auto& ok = rs.create_response<boost::beast::http::response<boost::beast::http::string_body>>(boost::beast::http::status::ok, req.version());
|
auto& ok = rs.create_response<boost::beast::http::response<boost::beast::http::string_body>>(boost::beast::http::status::ok, req.version());
|
||||||
ok.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
|
ok.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
|
||||||
|
|
@ -176,7 +245,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::jthread> threads;
|
std::vector<std::jthread> threads;
|
||||||
while(threads.size() < 4)
|
while(threads.size() < 16)
|
||||||
{
|
{
|
||||||
threads.emplace_back([&ioc]{ioc.run();});
|
threads.emplace_back([&ioc]{ioc.run();});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
// GNU Lesser General Public License v3.0
|
|
||||||
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
|
||||||
// the Free Software Foundation.
|
|
||||||
//
|
|
||||||
#include "mandelbrot.hpp"
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
// GNU Lesser General Public License v3.0
|
|
||||||
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
|
||||||
// the Free Software Foundation.
|
|
||||||
//
|
|
||||||
#include <complex>
|
|
||||||
#include <functional>
|
|
||||||
#include "window.hpp"
|
|
||||||
|
|
||||||
template<typename TFloat>
|
|
||||||
class mandelbrot
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using painter_fn = std::function<void(int x, int y, int iterations)>;
|
|
||||||
using escape_fn = std::function<std::complex<TFloat>(std::complex<TFloat>, std::complex<TFloat>)>;
|
|
||||||
|
|
||||||
mandelbrot(
|
|
||||||
window<TFloat> source_window,
|
|
||||||
window<TFloat> destination_window,
|
|
||||||
int max_iterations,
|
|
||||||
std::complex<TFloat> factor_a)
|
|
||||||
: m_source_window(source_window)
|
|
||||||
, m_destination_window(destination_window)
|
|
||||||
, m_max_iterations(max_iterations)
|
|
||||||
, m_factor_a(factor_a)
|
|
||||||
{}
|
|
||||||
|
|
||||||
void apply(const painter_fn& painter) const
|
|
||||||
{
|
|
||||||
auto fract_fn = [factor = m_factor_a](std::complex <TFloat> z, std::complex<TFloat> c) -> std::complex<TFloat>
|
|
||||||
{
|
|
||||||
return std::pow<TFloat>(z, factor) + c;
|
|
||||||
};
|
|
||||||
|
|
||||||
const TFloat dst_factor_x = 1.0 / m_destination_window.width() * m_source_window.width();
|
|
||||||
const TFloat dst_factor_y = 1.0 / m_destination_window.height() * m_source_window.height();
|
|
||||||
|
|
||||||
for (int x = 0; x < m_destination_window.width(); ++x)
|
|
||||||
{
|
|
||||||
for (int y = 0; y < m_destination_window.height(); ++y)
|
|
||||||
{
|
|
||||||
const auto _x = x * dst_factor_x + m_source_window.x_min();
|
|
||||||
const auto _y = y * dst_factor_y + m_source_window.y_min();
|
|
||||||
const int iterations = escape(std::complex<TFloat>(_y, _x), fract_fn);
|
|
||||||
|
|
||||||
painter(y,x,iterations);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int escape(const std::complex<TFloat>& c,
|
|
||||||
const escape_fn& func) const
|
|
||||||
{
|
|
||||||
std::complex<TFloat> z(0);
|
|
||||||
int iter = 0;
|
|
||||||
|
|
||||||
while (abs(z) < 2.0 && iter < m_max_iterations) {
|
|
||||||
z = func(z, c);
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
return iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
window<TFloat> m_source_window;
|
|
||||||
window<TFloat> m_destination_window;
|
|
||||||
int m_max_iterations;
|
|
||||||
std::complex<TFloat> m_factor_a;
|
|
||||||
};
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
// GNU Lesser General Public License v3.0
|
|
||||||
// Copyright (c) 2025 Bart Beumer <bart@4beumer.nl>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
|
||||||
// the Free Software Foundation.
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class window
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
window(T x_min, T x_max, T y_min, T y_max)
|
|
||||||
: m_x_min(x_min), m_x_max(x_max), m_y_min(y_min), m_y_max(y_max)
|
|
||||||
{}
|
|
||||||
|
|
||||||
T size() const {
|
|
||||||
return width() * height();
|
|
||||||
}
|
|
||||||
|
|
||||||
T width() const {
|
|
||||||
return m_x_max - m_x_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
T height() const {
|
|
||||||
return m_y_max - m_y_min;
|
|
||||||
}
|
|
||||||
|
|
||||||
T x_min() const {return m_x_min;}
|
|
||||||
T x_max() const {return m_x_max;}
|
|
||||||
T y_min() const {return m_y_min;}
|
|
||||||
T y_max() const {return m_y_max;}
|
|
||||||
|
|
||||||
private:
|
|
||||||
T m_x_min;
|
|
||||||
T m_x_max;
|
|
||||||
T m_y_min;
|
|
||||||
T m_y_max;
|
|
||||||
};
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
find_package(Boost 1.89.0 REQUIRED COMPONENTS program_options headers CONFIG)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
find_package(Boost 1.84.0 REQUIRED COMPONENTS program_options headers CONFIG)
|
||||||
find_package(JPEG REQUIRED)
|
find_package(JPEG REQUIRED)
|
||||||
|
|
||||||
project(text2image)
|
project(text2image)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(freetype REQUIRED)
|
find_package(freetype REQUIRED)
|
||||||
find_package(Boost 1.89.0 REQUIRED COMPONENTS headers CONFIG)
|
find_package(Boost 1.84.0 REQUIRED COMPONENTS headers CONFIG)
|
||||||
|
|
||||||
project(bmrshared-freetype)
|
project(bmrshared-freetype)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(libmagic 5.45 REQUIRED)
|
find_package(libmagic 5.45 REQUIRED)
|
||||||
|
|
||||||
project(bmrshared-magic)
|
project(bmrshared-magic)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
find_package(GTest REQUIRED)
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
find_package(Boost 1.89.0 REQUIRED COMPONENTS headers CONFIG)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
find_package(Boost 1.84.0 REQUIRED COMPONENTS headers CONFIG)
|
||||||
project(bmrshared-web)
|
project(bmrshared-web)
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
|
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
// GNU Lesser General Public License v3.0
|
|
||||||
// Copyright (c) 2023 Bart Beumer <bart@4beumer.nl>
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or modify it
|
|
||||||
// under the terms of the GNU Lesser General Public License v3.0 as published by
|
|
||||||
// the Free Software Foundation.
|
|
||||||
//
|
|
||||||
#pragma once
|
|
||||||
#include <cmath>
|
|
||||||
#include <optional>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
|
||||||
namespace bmrshared
|
|
||||||
{
|
|
||||||
class color
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct color_hsv
|
|
||||||
{
|
|
||||||
double h;
|
|
||||||
double s;
|
|
||||||
double v;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct color_rgb
|
|
||||||
{
|
|
||||||
double r;
|
|
||||||
double g;
|
|
||||||
double b;
|
|
||||||
};
|
|
||||||
|
|
||||||
color() = delete;
|
|
||||||
~color() = default;
|
|
||||||
constexpr color(const color&) = default;
|
|
||||||
constexpr color(color&&) = default;
|
|
||||||
constexpr color& operator=(const color&) = default;
|
|
||||||
constexpr color& operator=(color&&) = default;
|
|
||||||
|
|
||||||
constexpr color(const color_hsv& c)
|
|
||||||
: m_rgb()
|
|
||||||
, m_hsv(c)
|
|
||||||
{}
|
|
||||||
|
|
||||||
constexpr color(const color_rgb& c)
|
|
||||||
: m_rgb(c)
|
|
||||||
, m_hsv()
|
|
||||||
{}
|
|
||||||
|
|
||||||
constexpr const color_rgb& rgb() const
|
|
||||||
{
|
|
||||||
if (!m_rgb)
|
|
||||||
{
|
|
||||||
m_rgb = calculate_rgb(*m_hsv);
|
|
||||||
}
|
|
||||||
return *m_rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const color_hsv& hsv() const
|
|
||||||
{
|
|
||||||
if (!m_hsv)
|
|
||||||
{
|
|
||||||
m_hsv = calculate_hsv(*m_rgb);
|
|
||||||
}
|
|
||||||
return *m_hsv;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static constexpr color_hsv calculate_hsv(const color_rgb& c)
|
|
||||||
{
|
|
||||||
color_hsv r{.h = 0.0, .s = 0.0, .v = 0.0};
|
|
||||||
double min = std::min(c.r, std::min(c.g,c.b));
|
|
||||||
r.v = std::max(c.r, std::max(c.g,c.b));
|
|
||||||
double delta = r.v - min;
|
|
||||||
r.s = (r.v <= 0.0) ? 0.0 : (delta / r.v);
|
|
||||||
if (r.s <= 0.0)
|
|
||||||
{
|
|
||||||
r.h = 0.0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (c.r == r.v)
|
|
||||||
{
|
|
||||||
r.h = (c.g - c.b) / delta;
|
|
||||||
}
|
|
||||||
else if (c.g == r.v)
|
|
||||||
{
|
|
||||||
r.h = 2.0 + (c.b - c.r) / delta;
|
|
||||||
}
|
|
||||||
else if (c.b == r.v)
|
|
||||||
{
|
|
||||||
r.h = 4.0 + (c.r - c.g) / delta;
|
|
||||||
}
|
|
||||||
r.h*=60.0;
|
|
||||||
if (r.h < 0.0)
|
|
||||||
{
|
|
||||||
r.h +=360.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr color_rgb calculate_rgb(const color_hsv& in)
|
|
||||||
{
|
|
||||||
double C = in.s * in.v;
|
|
||||||
double X = C*(1-std::fabs(std::fmod(in.h/60.0, 2)-1));
|
|
||||||
double m = in.v-C;
|
|
||||||
|
|
||||||
color_rgb result{.r = 0.0, .g = 0.0, .b = 0.0};
|
|
||||||
if(in.h >= 0.0 && in.h < 60.0){
|
|
||||||
result = {.r = C, .g = X, .b = 0.0};
|
|
||||||
}
|
|
||||||
else if(in.h >= 60.0 && in.h < 120.0){
|
|
||||||
result = {.r = X, .g = C, . b = 0.0};
|
|
||||||
}
|
|
||||||
else if(in.h >= 120.0 && in.h < 180.0){
|
|
||||||
result = {.r = 0.0, .g = C, .b = X};
|
|
||||||
}
|
|
||||||
else if(in.h >= 180.0 && in.h < 240.0){
|
|
||||||
result = {.r = 0.0, .g = X, .b = C};
|
|
||||||
}
|
|
||||||
else if(in.h >= 240.0 && in.h < 300.0){
|
|
||||||
result = {.r = X, .g = 0.0, .b = C};
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
result = {.r = C, .g = 0.0, .b = X};
|
|
||||||
}
|
|
||||||
result.r+=m;
|
|
||||||
result.g+=m;
|
|
||||||
result.b+=m;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutable std::optional<color_rgb> m_rgb;
|
|
||||||
mutable std::optional<color_hsv> m_hsv;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
project(bmrshared)
|
project(bmrshared)
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
find_package(GTest REQUIRED)
|
find_package(GTest REQUIRED)
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
|
||||||
|
|
||||||
class HelloConan(ConanFile):
|
class HelloConan(ConanFile):
|
||||||
settings = "os", "compiler", "build_type", "arch"
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
requires = "boost/1.89.0", "gtest/1.14.0", "libmagic/5.45", "freetype/2.14.1", "libjpeg/9f"
|
requires = "boost/1.89.0", "gtest/1.14.0", "libmagic/5.45", "freetype/2.13.3", "libjpeg/9f"
|
||||||
generators = "CMakeDeps"
|
generators = "CMakeDeps"
|
||||||
build_policy = "*"
|
build_policy = "*"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
FROM alpine:3.21.3 AS build
|
|
||||||
|
|
||||||
RUN apk update && \
|
|
||||||
apk add --no-cache \
|
|
||||||
libstdc++
|
|
||||||
|
|
||||||
# Install tools required for building.
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
autoconf \
|
|
||||||
bash \
|
|
||||||
build-base \
|
|
||||||
cmake \
|
|
||||||
clang \
|
|
||||||
clang-extra-tools \
|
|
||||||
gdb \
|
|
||||||
git \
|
|
||||||
libtool \
|
|
||||||
linux-headers \
|
|
||||||
ninja \
|
|
||||||
m4 \
|
|
||||||
perl \
|
|
||||||
python3 \
|
|
||||||
py3-pip && \
|
|
||||||
pip install --break-system-packages conan && \
|
|
||||||
conan profile detect
|
|
||||||
|
|
||||||
# Pre-build some conan packages we require and take a lot of time to build. This to
|
|
||||||
# avoid expensive rebuilding everytime we need a fresh dev container..
|
|
||||||
RUN mkdir -p /workspaces/tmp
|
|
||||||
WORKDIR /workspaces/tmp
|
|
||||||
RUN conan install -s build_type=Debug -b=* --requires=boost/1.89.0
|
|
||||||
RUN conan install -s build_type=Debug -b=* --requires=libmagic/5.45
|
|
||||||
RUN conan install -s build_type=Debug -b=* --requires=freetype/2.14.1
|
|
||||||
RUN conan install -s build_type=Debug -b=missing --requires=gtest/1.14.0
|
|
||||||
RUN conan install -s build_type=Debug -b=missing --requires=libjpeg/9f
|
|
||||||
|
|
||||||
# Remove the temporary workspace, build results for the conan packages remain cached.
|
|
||||||
WORKDIR /workspaces
|
|
||||||
RUN rm -rf tmp && \
|
|
||||||
mkdir network-experiment && \
|
|
||||||
mkdir build && \
|
|
||||||
mkdir install
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
FROM alpine:3.21.3 AS build
|
|
||||||
|
|
||||||
RUN apk update && \
|
|
||||||
apk add --no-cache \
|
|
||||||
libstdc++
|
|
||||||
|
|
||||||
# Install tools required for building.
|
|
||||||
RUN apk add --no-cache \
|
|
||||||
autoconf \
|
|
||||||
bash \
|
|
||||||
build-base \
|
|
||||||
cmake \
|
|
||||||
clang \
|
|
||||||
clang-extra-tools \
|
|
||||||
gdb \
|
|
||||||
git \
|
|
||||||
libtool \
|
|
||||||
linux-headers \
|
|
||||||
ninja \
|
|
||||||
m4 \
|
|
||||||
perl \
|
|
||||||
python3 \
|
|
||||||
py3-pip && \
|
|
||||||
pip install --break-system-packages conan && \
|
|
||||||
conan profile detect
|
|
||||||
|
|
||||||
# Pre-build some conan packages we require and take a lot of time to build. This to
|
|
||||||
# avoid expensive rebuilding everytime we need a fresh dev container..
|
|
||||||
RUN mkdir -p /workspaces/tmp
|
|
||||||
WORKDIR /workspaces/tmp
|
|
||||||
RUN conan install -s build_type=Release -b=* --requires=boost/1.89.0
|
|
||||||
RUN conan install -s build_type=Release -b=* --requires=libmagic/5.45
|
|
||||||
RUN conan install -s build_type=Release -b=* --requires=freetype/2.14.1
|
|
||||||
RUN conan install -s build_type=Release -b=missing --requires=gtest/1.14.0
|
|
||||||
RUN conan install -s build_type=Release -b=missing --requires=libjpeg/9f
|
|
||||||
|
|
||||||
# Remove the temporary workspace, build results for the conan packages remain cached.
|
|
||||||
WORKDIR /workspaces
|
|
||||||
RUN rm -rf tmp && \
|
|
||||||
mkdir network-experiment && \
|
|
||||||
mkdir build && \
|
|
||||||
mkdir install
|
|
||||||
|
|
||||||
|
|
||||||
# Build and install
|
|
||||||
WORKDIR /workspaces/network-experiment
|
|
||||||
ADD . .
|
|
||||||
RUN conan install /workspaces/network-experiment -of /workspaces/build -s build_type=Release
|
|
||||||
RUN cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -S . -B /workspaces/build --install-prefix=/workspaces/install
|
|
||||||
RUN cmake --build /workspaces/build --parallel
|
|
||||||
RUN cmake --install /workspaces/build
|
|
||||||
|
|
||||||
|
|
||||||
FROM alpine:3.21.3
|
|
||||||
|
|
||||||
RUN apk update && \
|
|
||||||
apk add --no-cache \
|
|
||||||
libstdc++
|
|
||||||
|
|
||||||
RUN mkdir -p /workspaces/network-experiment/applications/http-mandelbrot/html
|
|
||||||
|
|
||||||
COPY --from=build /workspaces/install/bin/http-mandelbrot /bin
|
|
||||||
COPY --from=build /workspaces/install/bin/magic.mgc /bin
|
|
||||||
COPY --from=build /workspaces/network-experiment/applications/http-mandelbrot/html /workspaces/network-experiment/applications/http-mandelbrot/html
|
|
||||||
|
|
||||||
WORKDIR /bin
|
|
||||||
ENTRYPOINT ["http-mandelbrot"]
|
|
||||||
EXPOSE 9800/tcp
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue