infrastructure
This commit is contained in:
parent
28a209cbd1
commit
b66adf7ab5
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Docker C++ Debug",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "/app/a.out",
|
||||
"args": [],
|
||||
"stopAtEntry": true,
|
||||
"cwd": "/app",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"pipeTransport": {
|
||||
"debuggerPath": "/usr/bin/gdb",
|
||||
"pipeProgram": "ssh",
|
||||
"pipeArgs": [
|
||||
"root@localhost",
|
||||
"-p", "2222",
|
||||
"-i", "${workspaceFolder}/key",
|
||||
"-o", "StrictHostKeychecking=no",
|
||||
"/usr/bin/gdb --interpreter=mi"
|
||||
]
|
||||
},
|
||||
"sourceFileMap": {
|
||||
"/app": "${workspaceFolder}"
|
||||
},
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "skip libpoly",
|
||||
"text": "skip -gfi libpoly.so",
|
||||
"ignoreFailures": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"condition_variable": "cpp",
|
||||
"thread": "cpp",
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"bit": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"mutex": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"map": "cpp"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"tasks": [
|
||||
{
|
||||
"type": "cppbuild",
|
||||
"label": "C/C++: g++ build active file",
|
||||
"command": "/usr/bin/g++-14",
|
||||
"args": [
|
||||
"-fdiagnostics-color=always",
|
||||
"-g",
|
||||
"${file}",
|
||||
"-o",
|
||||
"${fileDirname}/${fileBasenameNoExtension}",
|
||||
"-Wall",
|
||||
"-pedantic",
|
||||
"-pthread",
|
||||
"-std=c++20"
|
||||
],
|
||||
"options": {
|
||||
"cwd": "${fileDirname}"
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"detail": "Task generated by Debugger."
|
||||
}
|
||||
],
|
||||
"version": "2.0.0"
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
FROM gcc:latest
|
||||
|
||||
COPY ./ /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt update && apt install -y gdb gdbserver openssh-server && \
|
||||
apt clean
|
||||
|
||||
RUN make a.out && echo 'yeey'
|
||||
|
||||
RUN mv key.pub /root/.ssh/authorized_keys && \
|
||||
mkdir /var/run/sshd
|
||||
|
||||
EXPOSE 22
|
||||
|
||||
CMD ["/usr/sbin/sshd", "-D"]
|
||||
|
||||
|
||||
# CMD ["sleep", "infinity"]
|
||||
|
||||
# CMD ["/app/a.out"]
|
|
@ -0,0 +1,2 @@
|
|||
a.out: triangulation.cpp
|
||||
g++ -Wl,-rpath=. triangulation.cpp -g -Wall -pedantic -pthread -lpoly -L./ -std=c++20
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
if [ ! -f key ] || [ ! -f key.pub ]; then
|
||||
rm -f key key.pub && \
|
||||
ssh-keygen -t ed25519 -N "" -f key
|
||||
fi
|
||||
docker build -t cpp20 .
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker ps --filter name=triangulation --format "{{.ID}}"| xargs -L1 docker kill
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef libpoly092986127876186578684563243
|
||||
#define libpoly092986127876186578684563243
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
void test(); // prints to stdout to test linking
|
||||
|
||||
struct LP_Point {
|
||||
double x, y;
|
||||
auto operator<=>(const LP_Point&) const = default;
|
||||
};
|
||||
|
||||
struct LP_Polygon {
|
||||
std::vector< LP_Point > points;
|
||||
LP_Polygon(std::vector< LP_Point >&& p) : points(p) {}
|
||||
LP_Polygon() {}
|
||||
};
|
||||
|
||||
class LP_Task : public std::enable_shared_from_this< LP_Task > {
|
||||
struct Private{ explicit Private() = default; };
|
||||
|
||||
public:
|
||||
LP_Task(Private) {}
|
||||
static std::shared_ptr<LP_Task> create() {
|
||||
return std::make_shared<LP_Task>(Private());
|
||||
}
|
||||
|
||||
std::shared_ptr<LP_Task> getptr() {
|
||||
return shared_from_this();
|
||||
}
|
||||
LP_Task(LP_Polygon&& _p): p(_p), minimal_triangulation(MAXFLOAT){};
|
||||
|
||||
LP_Polygon p;
|
||||
double minimal_triangulation;
|
||||
};
|
||||
|
||||
using LP_Task_p = std::shared_ptr< LP_Task >;
|
||||
|
||||
LP_Task_p pickup_task();
|
||||
bool submit_task(LP_Task_p&&);
|
||||
|
||||
#endif // libpoly092986127876186578684563243
|
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
docker run --rm -d --name triangulation -p 2222:22 -p 7777:7777 cpp20
|
|
@ -21,21 +21,19 @@ std::condition_variable can_push;
|
|||
|
||||
std::atomic_uint32_t active_producents;
|
||||
std::atomic_uint32_t active_consuments;
|
||||
std::atomic_bool tasks_incoming;
|
||||
std::ostream& os = std::cout;
|
||||
std::mutex os_l;
|
||||
|
||||
//############################# MODIFY HERE
|
||||
|
||||
constexpr unsigned NUM_PRODUCENTS = 1;
|
||||
constexpr unsigned NUM_WORKERS = 3;
|
||||
constexpr unsigned NUM_PRODUCENTS = 2;
|
||||
constexpr unsigned NUM_WORKERS = 5;
|
||||
|
||||
//############################################################ COMMON STRUCTURES
|
||||
|
||||
struct Temp_Task: public std::enable_shared_from_this< Temp_Task > {
|
||||
LP_Polygon p;
|
||||
double minimal_triangulation;
|
||||
|
||||
Temp_Task(LP_Polygon&& _p): p(_p){}
|
||||
};
|
||||
|
||||
|
@ -45,9 +43,10 @@ class Task {
|
|||
private:
|
||||
Temp_Task_p task;
|
||||
|
||||
double triangulate(LP_Polygon* p);
|
||||
double triangulate_basic(LP_Polygon* p);
|
||||
double triangulate();
|
||||
double triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m);
|
||||
std::vector<bool> create_key(std::vector<int>* indices);
|
||||
|
||||
public:
|
||||
Task(): task(nullptr){};
|
||||
|
@ -56,13 +55,20 @@ public:
|
|||
t.task.reset();
|
||||
}
|
||||
Task(Temp_Task_p&& tp): task(tp){}
|
||||
void solve_stupid(){
|
||||
task->minimal_triangulation = triangulate(&(task->p));
|
||||
|
||||
double solution() const { return task->minimal_triangulation; }
|
||||
bool is_empty() const {
|
||||
return task.get() == nullptr;
|
||||
}
|
||||
|
||||
void solve_stupid(){
|
||||
task->minimal_triangulation = triangulate_basic(&(task->p));
|
||||
}
|
||||
void solve_less_stupid(){ task->minimal_triangulation = triangulate(); }
|
||||
|
||||
Temp_Task_p unwrap(){ // TODO: vymyslet jinak, zaručit po tomto kroku selfdestruct
|
||||
return std::move(task);
|
||||
}
|
||||
double const solution(){ return task->minimal_triangulation; }
|
||||
};
|
||||
|
||||
class Queue{
|
||||
|
@ -100,7 +106,7 @@ public:
|
|||
using task_queue_ptr = std::shared_ptr<Queue>;
|
||||
|
||||
//############################################################ PRODUCE THREAD
|
||||
|
||||
/*
|
||||
class Producent{
|
||||
private:
|
||||
task_queue_ptr task_queue;
|
||||
|
@ -111,30 +117,41 @@ public:
|
|||
|
||||
Task get_task(){
|
||||
//LP_Task_p tp = pickup_task();
|
||||
os_l.lock();
|
||||
os << "picked up" << std::endl;
|
||||
os_l.unlock();
|
||||
|
||||
//#########################3TEMP_PART:
|
||||
std::vector< LP_Point > points;
|
||||
srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
|
||||
int num_of_points = (rand()%10) + 1;
|
||||
for(int i = 0; i < num_of_points; i++){
|
||||
LP_Point p;
|
||||
// std::vector< LP_Point > points;
|
||||
// srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
|
||||
// int num_of_points = (rand()%10) + 1;
|
||||
// for(int i = 0; i < num_of_points; i++){
|
||||
// LP_Point p;
|
||||
|
||||
p.x = rand()%199 +1;
|
||||
p.y = rand()%199 +1;
|
||||
points.push_back(p);
|
||||
}
|
||||
LP_Polygon p(std::move(points));
|
||||
Temp_Task_p tp = std::make_shared<Temp_Task>(std::move( p ));
|
||||
// p.x = rand()%199 +1;
|
||||
// p.y = rand()%199 +1;
|
||||
// points.push_back(p);
|
||||
// }
|
||||
// LP_Polygon p(std::move(points));
|
||||
// Temp_Task_p tp = std::make_shared<Temp_Task>(std::move( p ));
|
||||
|
||||
return Task(std::move(tp));
|
||||
}
|
||||
|
||||
void fill_queue(){
|
||||
while(tasks_incoming){
|
||||
//Task t = get_task();
|
||||
|
||||
task_queue->push(get_task());
|
||||
while(1){
|
||||
Task t = get_task();
|
||||
if(t.is_empty()) break;
|
||||
else{
|
||||
task_queue->push(std::move(t));
|
||||
os_l.lock();
|
||||
os << "queued" << std::endl;
|
||||
os_l.unlock();
|
||||
}
|
||||
}
|
||||
os_l.lock();
|
||||
os << "p ready to join" << std::endl;
|
||||
os_l.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -154,6 +171,9 @@ public:
|
|||
~Consument() { active_consuments--; }
|
||||
|
||||
Task get_task(){ // might be redundant
|
||||
os_l.lock();
|
||||
os << "processing" << std::endl;
|
||||
os_l.unlock();
|
||||
return task_queue->pop();
|
||||
}
|
||||
|
||||
|
@ -161,11 +181,14 @@ public:
|
|||
while(active_producents || ! task_queue->is_empty()){
|
||||
Task t = get_task();
|
||||
t.solve_stupid();
|
||||
//submit_task(std::move(t.unwrap()));
|
||||
submit_task(std::move(t.unwrap()));
|
||||
os_l.lock();
|
||||
os << t.solution() << std::endl;
|
||||
os_l.unlock();
|
||||
}
|
||||
os_l.lock();
|
||||
os << "c ready to join" << std::endl;
|
||||
os_l.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -173,7 +196,7 @@ void consume_thread(task_queue_ptr task_queue){
|
|||
Consument c(task_queue);
|
||||
c.work();
|
||||
}
|
||||
|
||||
*/
|
||||
//############################################################ TRIANGULATION
|
||||
|
||||
struct Line{
|
||||
|
@ -191,12 +214,19 @@ struct Line{
|
|||
Line(Line& l): a(l.a), b(l.b), length(l.length){}
|
||||
};
|
||||
|
||||
double Task::triangulate(LP_Polygon* p){
|
||||
double Task::triangulate_basic(LP_Polygon* p){
|
||||
size_t poly_size = p->points.size();
|
||||
|
||||
if(poly_size == 3) return 0.;
|
||||
if(poly_size == 4){
|
||||
Line cut1(p->points.at( 0 ),
|
||||
p->points.at( 2 ));
|
||||
Line cut2(p->points.at( 1 ),
|
||||
p->points.at( 3 ));
|
||||
return std::min(cut1.length, cut2.length);
|
||||
}
|
||||
|
||||
double triangulation;
|
||||
double triangulation = INFINITY;
|
||||
double min_triangulation = INFINITY;
|
||||
|
||||
for (size_t point_idx = 0; point_idx < poly_size; point_idx++){
|
||||
|
@ -209,24 +239,31 @@ double Task::triangulate(LP_Polygon* p){
|
|||
}
|
||||
|
||||
LP_Polygon s_p(std::move(smaller_poly));
|
||||
triangulation = triangulate(&s_p) + cut.length;
|
||||
triangulation = triangulate_basic(&s_p) + cut.length;
|
||||
if(triangulation < min_triangulation) min_triangulation = triangulation;
|
||||
}
|
||||
|
||||
return min_triangulation;
|
||||
|
||||
}
|
||||
//############################### dynamic something
|
||||
|
||||
//########################### attempt of thought
|
||||
|
||||
// build a list (array?) of all cut lengths ... n
|
||||
// build a list of "quatrogones"-> pentagones -> hexagones -> ....; each of them carries its min_triangulation
|
||||
// end up with our polygone already w min triang.
|
||||
// not really better i guess...
|
||||
|
||||
//########################### dynamic something
|
||||
|
||||
//use std::map to store triangulations of polygons
|
||||
//KEY CREATION:
|
||||
// take relative positions of points in polygon, add them as vectors and do something with the amount of them
|
||||
// maybe num * vx + num^2 * vy
|
||||
|
||||
double Task::triangulate(){
|
||||
std::map<int, double> m;
|
||||
std::vector<bool> poly_key;
|
||||
return triangulate_subpolys(poly_key, &m);
|
||||
std::vector<bool> poly_key(task->p.points.size(), true);
|
||||
return triangulate_subpolys(poly_key, &m);
|
||||
//
|
||||
// return triangulate_subpolys_but_better();
|
||||
}
|
||||
|
||||
int vec_to_int(std::vector<bool>* vec){
|
||||
|
@ -237,46 +274,150 @@ int vec_to_int(std::vector<bool>* vec){
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<bool> Task::create_key(std::vector<int>* indices){
|
||||
|
||||
size_t key_length = task->p.points.size();
|
||||
std::vector<bool> key(key_length, false);
|
||||
|
||||
for(size_t i = 0; i < indices->size(); i++){
|
||||
key[indices->at(i)] = true;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
double Task::triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m){
|
||||
// convert p to int
|
||||
int key = vec_to_int(&poly_key);
|
||||
|
||||
// try to find in map
|
||||
// success -> return mapped value
|
||||
// failure -> compute triangulation
|
||||
// save value in map
|
||||
if (m->count(key)) return m->at(key); // ! contains() is c++20
|
||||
|
||||
// failure -> create poly from key
|
||||
std::vector<LP_Point> curr_points;
|
||||
std::vector<int> curr_indices;
|
||||
for(size_t i = 0; i < task->p.points.size(); i++){
|
||||
if(poly_key.at(i)){
|
||||
curr_points.push_back(task->p.points.at(i));
|
||||
curr_indices.push_back(i);
|
||||
}
|
||||
}
|
||||
LP_Polygon poly(std::move(curr_points));
|
||||
|
||||
// use stupid triangulation but create poly_key instead of small_poly
|
||||
// save value in map before any return
|
||||
|
||||
size_t poly_size = poly.points.size();
|
||||
if(poly_size == 3){
|
||||
(*m)[key] = 0.;
|
||||
return 0.;
|
||||
}
|
||||
|
||||
double triangulation;
|
||||
double min_triangulation = INFINITY;
|
||||
|
||||
for (size_t point_idx = 0; point_idx < poly_size; point_idx++){
|
||||
Line cut(poly.points.at( (point_idx - 1) % poly_size ),
|
||||
poly.points.at( (point_idx + 1) % poly_size ));
|
||||
|
||||
std::vector<int> sub_indices = curr_indices;
|
||||
sub_indices.erase(sub_indices.begin() + point_idx);
|
||||
|
||||
triangulation = triangulate_subpolys( create_key( &sub_indices ), m )
|
||||
+ cut.length;
|
||||
|
||||
if(triangulation < min_triangulation) min_triangulation = triangulation;
|
||||
}
|
||||
|
||||
(*m)[key] = min_triangulation;
|
||||
|
||||
// return found value
|
||||
// COMPUTE TRIANGULATION
|
||||
// create polygon poly from p
|
||||
// use stupid triangulation but create poly_key instead of small_poly
|
||||
|
||||
return 0.;
|
||||
|
||||
|
||||
return min_triangulation;
|
||||
}
|
||||
|
||||
//########################### dynamic something but better
|
||||
|
||||
|
||||
//############################################################ TRIANGULATION TEST
|
||||
|
||||
void task_test(){
|
||||
std::vector< LP_Point > v1 = {{0,0}, {1,1}, {3,1}, {2,0}};
|
||||
std::vector< LP_Point > v2 = {{0,0}, {0,1}, {1,2}, {2,1}, {2,0}};
|
||||
std::vector< LP_Point > v3 = {{0,0}, {1,1}, {2,2}, {3,1}, {2,0}, {1,-1}};
|
||||
|
||||
LP_Polygon p1(std::move(v1));
|
||||
LP_Polygon p2(std::move(v2));
|
||||
LP_Polygon p3(std::move(v3));
|
||||
|
||||
Temp_Task_p tp1 = std::make_shared<Temp_Task>(std::move(p1));
|
||||
Temp_Task_p tp2 = std::make_shared<Temp_Task>(std::move(p2));
|
||||
Temp_Task_p tp3 = std::make_shared<Temp_Task>(std::move(p3));
|
||||
|
||||
Task t1(std::move(tp1));
|
||||
Task t2(std::move(tp2));
|
||||
Task t3(std::move(tp3));
|
||||
|
||||
t1.solve_stupid();
|
||||
t2.solve_stupid();
|
||||
t3.solve_stupid();
|
||||
|
||||
std::cout << "4 vertices:\ncorrect: calculated:\n" << "1.414 " << t1.solution() << std::endl;
|
||||
std::cout << "5 vertices:\ncorrect: calculated:\n" << "4.236 " << t2.solution() << std::endl;
|
||||
std::cout << "6 vertices:\ncorrect: calculated:\n" << "5.414 " << t1.solution() << std::endl << std::endl;
|
||||
|
||||
t1.solve_less_stupid();
|
||||
t2.solve_less_stupid();
|
||||
t3.solve_less_stupid();
|
||||
|
||||
std::cout << "SECOND VERSION:\n\n";
|
||||
|
||||
std::cout << "4 vertices:\ncorrect: calculated:\n" << "1.414 " << t1.solution() << std::endl;
|
||||
std::cout << "5 vertices:\ncorrect: calculated:\n" << "4.236 " << t2.solution() << std::endl;
|
||||
std::cout << "6 vertices:\ncorrect: calculated:\n" << "5.414 " << t1.solution() << std::endl << std::endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//############################################################ MAIN
|
||||
|
||||
int main(){
|
||||
active_producents = active_consuments = 0;
|
||||
tasks_incoming = true;
|
||||
|
||||
task_queue_ptr queue_ptr = std::make_shared<Queue>();
|
||||
std::vector<std::thread> threads;
|
||||
//############################### MULTI THREAD
|
||||
|
||||
for(unsigned int i = 0; i < NUM_PRODUCENTS; i++){
|
||||
threads.emplace_back(produce_thread, queue_ptr);
|
||||
}
|
||||
// active_producents = active_consuments = 0;
|
||||
|
||||
for(unsigned int i = 0; i < NUM_WORKERS; i++){
|
||||
threads.emplace_back(consume_thread, queue_ptr);
|
||||
}
|
||||
// task_queue_ptr queue_ptr = std::make_shared<Queue>();
|
||||
// std::vector<std::thread> threads;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
tasks_incoming = false;
|
||||
for(auto& t : threads){
|
||||
t.join();
|
||||
os_l.lock();
|
||||
os << "joined" << std::endl;
|
||||
os_l.unlock();
|
||||
}
|
||||
//test();
|
||||
// for(unsigned int i = 0; i < NUM_PRODUCENTS; i++){
|
||||
// threads.emplace_back(produce_thread, queue_ptr);
|
||||
// }
|
||||
|
||||
// for(unsigned int i = 0; i < NUM_WORKERS; i++){
|
||||
// threads.emplace_back(consume_thread, queue_ptr);
|
||||
// }
|
||||
|
||||
// for(auto& t : threads){
|
||||
// t.join();
|
||||
// os_l.lock();
|
||||
// os << "joined" << std::endl;
|
||||
// os_l.unlock();
|
||||
// }
|
||||
|
||||
//############################### SINGLE THREAD
|
||||
|
||||
// while(1){
|
||||
// LP_Task_p tp = pickup_task();
|
||||
// if(!tp) break;
|
||||
// Task t(std::move(tp));
|
||||
// t.solve_stupid();
|
||||
// submit_task(std::move(t.unwrap()));
|
||||
// }
|
||||
|
||||
//############################### CONNECTION TEST
|
||||
|
||||
// test();
|
||||
|
||||
//############################### TRIANGULATION TEST
|
||||
task_test();
|
||||
}
|
Loading…
Reference in New Issue