contrek 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +4 -3
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +4 -4
- data/README.md +34 -30
- data/Rakefile +3 -0
- data/contrek.gemspec +7 -4
- data/ext/cpp_polygon_finder/PolygonFinder/Makefile +44 -0
- data/ext/cpp_polygon_finder/PolygonFinder/images/sample_10240x10240.png +0 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/Main.cpp +14 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +136 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +5 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/CpuTimer.h +44 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.cpp +8 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/Bitmap.h +3 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +63 -573
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.h +17 -18
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +22 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.c +6980 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/spng.h +537 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +101 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.h +16 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +0 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +4 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +13 -13
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +5 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +47 -41
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +15 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +181 -178
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +19 -20
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Polygon.h +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +52 -137
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +85 -16
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/RectBounds.h +39 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.cpp +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ClippedPolygonFinder.h +17 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +117 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +32 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +344 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +46 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.cpp +14 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +22 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.cpp +13 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/FakeCluster.h +17 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +138 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +70 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +47 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.cpp +24 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/PartPool.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +182 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +30 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +108 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.cpp +59 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Poolable.h +52 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +31 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +25 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queue.h +36 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +230 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +35 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +20 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +26 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +23 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +105 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +56 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.cpp +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/Matcher.h +5 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBMatcher.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/RGBNotMatcher.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/matchers/ValueNotMatcher.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +23 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +6 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +2 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +4 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +9 -12
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +3 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +26 -27
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +76 -87
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +64 -32
- data/ext/cpp_polygon_finder/extconf.rb +14 -0
- data/lib/contrek/bitmaps/sample_generator.rb +56 -0
- data/lib/contrek/cpp/cpp_concurrent_finder.rb +9 -0
- data/lib/contrek/finder/bounds.rb +17 -0
- data/lib/contrek/finder/concurrent/cluster.rb +2 -2
- data/lib/contrek/finder/concurrent/cursor.rb +8 -8
- data/lib/contrek/finder/concurrent/finder.rb +10 -9
- data/lib/contrek/finder/concurrent/part.rb +2 -2
- data/lib/contrek/finder/concurrent/partitionable.rb +1 -1
- data/lib/contrek/finder/concurrent/polyline.rb +17 -15
- data/lib/contrek/finder/concurrent/sequence.rb +11 -0
- data/lib/contrek/finder/concurrent/tile.rb +3 -3
- data/lib/contrek/finder/node_cluster.rb +16 -8
- data/lib/contrek/finder/polygon_finder.rb +1 -4
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +9 -1
- metadata +62 -15
- data/ext/cpp_polygon_finder/PolygonFinder/.cproject +0 -136
- data/ext/cpp_polygon_finder/PolygonFinder/.project +0 -27
- data/ext/cpp_polygon_finder/PolygonFinder/.settings/org.eclipse.ltk.core.refactoring.prefs +0 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.cpp +0 -48
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/PngBitmap.h +0 -32
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Hub.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include <deque>
|
|
12
|
+
#include "EndPoint.h"
|
|
13
|
+
|
|
14
|
+
class EndPoint;
|
|
15
|
+
class Hub {
|
|
16
|
+
public:
|
|
17
|
+
explicit Hub(int height, int width);
|
|
18
|
+
EndPoint* spawn_end_point();
|
|
19
|
+
const int width() const { return width_; }
|
|
20
|
+
inline EndPoint* get(int key) const {
|
|
21
|
+
if (!is_set(key)) return nullptr;
|
|
22
|
+
return payloads_[key];
|
|
23
|
+
}
|
|
24
|
+
inline void put(int key, EndPoint* payload) {
|
|
25
|
+
payloads_[key] = payload;
|
|
26
|
+
bitset_[key >> 6] |= (1ULL << (key & 63));
|
|
27
|
+
}
|
|
28
|
+
inline bool is_set(int key) const {
|
|
29
|
+
return (bitset_[key >> 6] & (1ULL << (key & 63)));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private:
|
|
33
|
+
int width_;
|
|
34
|
+
int height_;
|
|
35
|
+
std::vector<EndPoint*> payloads_;
|
|
36
|
+
std::deque<EndPoint> endpoint_pool_;
|
|
37
|
+
Hub(const Hub&) = delete;
|
|
38
|
+
Hub& operator=(const Hub&) = delete;
|
|
39
|
+
std::vector<uint64_t> bitset_;
|
|
40
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Part.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "Part.h"
|
|
10
|
+
#include <iostream>
|
|
11
|
+
#include "Polyline.h"
|
|
12
|
+
#include "Tile.h"
|
|
13
|
+
#include "Cluster.h"
|
|
14
|
+
|
|
15
|
+
Part::Part(Types type, Polyline* polyline)
|
|
16
|
+
: type(type),
|
|
17
|
+
polyline_(polyline) {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
bool Part::is(Types type)
|
|
21
|
+
{ return(this->type == type);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
Position* Part::next_position(Position* force_position) {
|
|
25
|
+
if (force_position != nullptr)
|
|
26
|
+
{ QNode<Point>* move_to_this = nullptr;
|
|
27
|
+
this->reverse_each([&](QNode<Point>* pos) -> bool {
|
|
28
|
+
if (*(pos->payload) == *(force_position->payload)) {
|
|
29
|
+
move_to_this = pos;
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
});
|
|
34
|
+
if (move_to_this) next_of(move_to_this);
|
|
35
|
+
return(force_position);
|
|
36
|
+
} else {
|
|
37
|
+
if (this->iterator() == nullptr) return(nullptr);
|
|
38
|
+
Position *position = static_cast<Position*>(this->iterator());
|
|
39
|
+
this->touched_ = true;
|
|
40
|
+
this->forward();
|
|
41
|
+
return(position);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void Part::add_position(Point* point) {
|
|
46
|
+
Cluster* c = this->polyline_->tile->cluster;
|
|
47
|
+
c->positions_pool.emplace_back(c->hub(), point);
|
|
48
|
+
this->add(&c->positions_pool.back());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
bool Part::innerable()
|
|
52
|
+
{ return(!this->touched_ && is(EXCLUSIVE));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void Part::touch()
|
|
56
|
+
{ this->touched_ = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
bool Part::intersect_part(Part* other_part)
|
|
60
|
+
{ bool intersect = false;
|
|
61
|
+
other_part->each([&](QNode<Point>* pos) -> bool {
|
|
62
|
+
Position *position = dynamic_cast<Position*>(pos);
|
|
63
|
+
if (position->end_point()->queues_include(this))
|
|
64
|
+
{ intersect = true;
|
|
65
|
+
return(false);
|
|
66
|
+
}
|
|
67
|
+
return(true);
|
|
68
|
+
});
|
|
69
|
+
return(intersect);
|
|
70
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Part.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <deque>
|
|
13
|
+
#include "Queueable.h"
|
|
14
|
+
#include "Position.h"
|
|
15
|
+
#include "../Node.h"
|
|
16
|
+
|
|
17
|
+
class Polyline;
|
|
18
|
+
class Position;
|
|
19
|
+
class Part : public Queueable<Point> {
|
|
20
|
+
public:
|
|
21
|
+
enum Types : uint32_t {
|
|
22
|
+
SEAM = 1,
|
|
23
|
+
EXCLUSIVE = 0,
|
|
24
|
+
ADDED = 2
|
|
25
|
+
};
|
|
26
|
+
explicit Part(Types type, Polyline* polyline);
|
|
27
|
+
bool is(Types type);
|
|
28
|
+
bool inverts = false;
|
|
29
|
+
bool trasmuted = false;
|
|
30
|
+
Part* next = nullptr;
|
|
31
|
+
Part* prev = nullptr;
|
|
32
|
+
Part* circular_next = nullptr;
|
|
33
|
+
std::string toString() const { return "Part type = " + std::to_string(static_cast<uint32_t>(type)); }
|
|
34
|
+
Polyline* polyline() { return polyline_; }
|
|
35
|
+
Position* next_position(Position* force_position);
|
|
36
|
+
void add_position(Point* point);
|
|
37
|
+
int passes = 0;
|
|
38
|
+
Types type;
|
|
39
|
+
bool innerable();
|
|
40
|
+
const bool touched() const { return touched_; }
|
|
41
|
+
void touch();
|
|
42
|
+
bool intersect_part(Part* other_part);
|
|
43
|
+
|
|
44
|
+
private:
|
|
45
|
+
bool touched_ = false;
|
|
46
|
+
Polyline* polyline_;
|
|
47
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PartPool.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include "PartPool.h"
|
|
10
|
+
#include "Part.h"
|
|
11
|
+
#include "Polyline.h"
|
|
12
|
+
|
|
13
|
+
Part* PartPool::acquire(uint32_t type, Polyline* poly) {
|
|
14
|
+
storage.emplace_back(static_cast<Part::Types>(type), poly);
|
|
15
|
+
|
|
16
|
+
Part* p = &storage.back();
|
|
17
|
+
p->next = nullptr;
|
|
18
|
+
p->prev = nullptr;
|
|
19
|
+
return p;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
void PartPool::clear() {
|
|
23
|
+
storage.clear();
|
|
24
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PartPool.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <deque>
|
|
11
|
+
#include <cstdint> // for uint32_t
|
|
12
|
+
|
|
13
|
+
class Part;
|
|
14
|
+
class Polyline;
|
|
15
|
+
|
|
16
|
+
class PartPool {
|
|
17
|
+
private:
|
|
18
|
+
std::deque<Part> storage;
|
|
19
|
+
|
|
20
|
+
public:
|
|
21
|
+
Part* acquire(uint32_t type, Polyline* poly);
|
|
22
|
+
void clear();
|
|
23
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Partitionable.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <utility>
|
|
11
|
+
#include <iostream>
|
|
12
|
+
#include "Partitionable.h"
|
|
13
|
+
#include "Polyline.h"
|
|
14
|
+
#include "Sequence.h"
|
|
15
|
+
#include "Tile.h"
|
|
16
|
+
#include "../Node.h"
|
|
17
|
+
#include "PartPool.h"
|
|
18
|
+
#include "Cluster.h"
|
|
19
|
+
|
|
20
|
+
class Polyline;
|
|
21
|
+
class Point;
|
|
22
|
+
class Tile;
|
|
23
|
+
|
|
24
|
+
void Partitionable::add_part(Part* new_part)
|
|
25
|
+
{ Part* last = this->parts_.empty() ? nullptr : this->parts_.back();
|
|
26
|
+
this->parts_.push_back(new_part);
|
|
27
|
+
if (last) {
|
|
28
|
+
last->next = last->circular_next = new_part;
|
|
29
|
+
}
|
|
30
|
+
new_part->prev = last;
|
|
31
|
+
new_part->circular_next = this->parts_.front();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void Partitionable::partition()
|
|
35
|
+
{ this->parts_.clear();
|
|
36
|
+
Polyline *polyline = dynamic_cast<Polyline*>(this);
|
|
37
|
+
PartPool& pool = polyline->tile->cluster->parts_pool;
|
|
38
|
+
Part *current_part = nullptr;
|
|
39
|
+
int n = 0;
|
|
40
|
+
Point* prev_position = nullptr;
|
|
41
|
+
for (Point* position : polyline->raw())
|
|
42
|
+
{ if (polyline->tile->tg_border(*position))
|
|
43
|
+
{ if (current_part == nullptr) {
|
|
44
|
+
current_part = pool.acquire(Part::SEAM, polyline);
|
|
45
|
+
} else if (!current_part->is(Part::SEAM)) {
|
|
46
|
+
this->add_part(current_part);
|
|
47
|
+
current_part = pool.acquire(Part::SEAM, polyline);
|
|
48
|
+
}
|
|
49
|
+
} else if (current_part == nullptr) {
|
|
50
|
+
current_part = pool.acquire(Part::EXCLUSIVE, polyline);
|
|
51
|
+
} else if (!current_part->is(Part::EXCLUSIVE)) {
|
|
52
|
+
this->add_part(current_part);
|
|
53
|
+
current_part = pool.acquire(Part::EXCLUSIVE, polyline);
|
|
54
|
+
}
|
|
55
|
+
if (n > 0 && *prev_position == *position) {
|
|
56
|
+
current_part->inverts = true;
|
|
57
|
+
}
|
|
58
|
+
current_part->add_position(position);
|
|
59
|
+
n++;
|
|
60
|
+
prev_position = position;
|
|
61
|
+
}
|
|
62
|
+
this->add_part(current_part);
|
|
63
|
+
|
|
64
|
+
this->trasmute_parts();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Part* Partitionable::find_first_part_by_position(Position* position) {
|
|
68
|
+
for (Part* part : this->parts_)
|
|
69
|
+
{ if ( part->is(Part::SEAM) &&
|
|
70
|
+
part->passes == 0 &&
|
|
71
|
+
position->end_point()->queues_include(part)) return(part);
|
|
72
|
+
}
|
|
73
|
+
return(nullptr);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
std::pair<
|
|
77
|
+
std::vector<std::vector<Point*>>,
|
|
78
|
+
std::vector<std::vector<Point*>>
|
|
79
|
+
>
|
|
80
|
+
Partitionable::sew(std::vector<Point*> intersection, Polyline* other)
|
|
81
|
+
{ std::vector<int> matching_part_indexes;
|
|
82
|
+
for (int i = 0; i < static_cast<int>(parts_.size()); ++i) {
|
|
83
|
+
Part* part = parts_[i];
|
|
84
|
+
if (!part || part->trasmuted) continue;
|
|
85
|
+
if (part->intersection_with_array(intersection)) {
|
|
86
|
+
matching_part_indexes.push_back(i);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
std::vector<int> other_matching_part_indexes;
|
|
90
|
+
for (int i = 0; i < static_cast<int>(other->parts_.size()); ++i) {
|
|
91
|
+
Part* part = other->parts_[i];
|
|
92
|
+
if (!part || part->trasmuted) continue;
|
|
93
|
+
if (part->intersection_with_array(intersection)) {
|
|
94
|
+
other_matching_part_indexes.push_back(i);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
std::vector<Part*> before_parts;
|
|
98
|
+
for (int i = other_matching_part_indexes.back() + 1;
|
|
99
|
+
i < static_cast<int>(other->parts_.size()); ++i)
|
|
100
|
+
{ before_parts.push_back(other->parts_[i]);
|
|
101
|
+
}
|
|
102
|
+
std::vector<Part*> after_parts;
|
|
103
|
+
for (int i = 0; i < other_matching_part_indexes.front(); ++i) {
|
|
104
|
+
after_parts.push_back(other->parts_[i]);
|
|
105
|
+
}
|
|
106
|
+
Part* part_start = parts_[matching_part_indexes.front()];
|
|
107
|
+
Part* part_end = parts_[matching_part_indexes.back()];
|
|
108
|
+
// They are inverted since they traverse in opposite directions
|
|
109
|
+
Sequence sequence;
|
|
110
|
+
sequence.add(part_start->head);
|
|
111
|
+
for (Part* p : before_parts) sequence.append(*p);
|
|
112
|
+
for (Part* p : after_parts) sequence.append(*p);
|
|
113
|
+
if (part_end->tail) sequence.add(part_end->tail);
|
|
114
|
+
part_start->replace(sequence);
|
|
115
|
+
part_start->type = Part::EXCLUSIVE;
|
|
116
|
+
if (part_start != part_end) part_end->reset();
|
|
117
|
+
|
|
118
|
+
std::vector<std::vector<Point*>> left;
|
|
119
|
+
|
|
120
|
+
for (int n = matching_part_indexes.front() + 1;
|
|
121
|
+
n <= matching_part_indexes.back() - 1;
|
|
122
|
+
++n)
|
|
123
|
+
{ if (std::find(matching_part_indexes.begin(),
|
|
124
|
+
matching_part_indexes.end(),
|
|
125
|
+
n) == matching_part_indexes.end())
|
|
126
|
+
{ auto pts = parts_[n]->to_vector();
|
|
127
|
+
left.push_back(pts);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// delete parts in reverse order
|
|
132
|
+
for (int n = matching_part_indexes.back() - 1;
|
|
133
|
+
n >= matching_part_indexes.front() + 1;
|
|
134
|
+
--n)
|
|
135
|
+
{ Part* delete_part = parts_[n];
|
|
136
|
+
if (delete_part->prev) delete_part->prev->next = delete_part->next;
|
|
137
|
+
if (delete_part->next) delete_part->next->prev = delete_part->prev;
|
|
138
|
+
parts_.erase(parts_.begin() + n);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
std::vector<std::vector<Point*>> right;
|
|
142
|
+
for (int n = other_matching_part_indexes.front() + 1;
|
|
143
|
+
n <= other_matching_part_indexes.back() - 1;
|
|
144
|
+
++n)
|
|
145
|
+
{ if (std::find(other_matching_part_indexes.begin(),
|
|
146
|
+
other_matching_part_indexes.end(),
|
|
147
|
+
n) == other_matching_part_indexes.end())
|
|
148
|
+
{ auto pts = other->parts_[n]->to_vector();
|
|
149
|
+
right.push_back(pts);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return { left, right };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
void Partitionable::trasmute_parts()
|
|
156
|
+
{ std::vector<Part*> insides;
|
|
157
|
+
for (Part* p : parts_) {
|
|
158
|
+
if (p->is(Part::SEAM)) insides.push_back(p);
|
|
159
|
+
}
|
|
160
|
+
if (insides.size() < 2) return;
|
|
161
|
+
|
|
162
|
+
for (Part* inside : insides)
|
|
163
|
+
{ for (Part* inside_compare : insides) {
|
|
164
|
+
if (inside == inside_compare || !inside_compare->is(Part::SEAM) ) continue;
|
|
165
|
+
bool all_match = true;
|
|
166
|
+
inside->each([&](QNode<Point>* pos) -> bool {
|
|
167
|
+
Position *position = dynamic_cast<Position*>(pos);
|
|
168
|
+
if (position->end_point()->queues_include(inside_compare))
|
|
169
|
+
{ return true;
|
|
170
|
+
}
|
|
171
|
+
all_match = false;
|
|
172
|
+
return false;
|
|
173
|
+
});
|
|
174
|
+
if (all_match) {
|
|
175
|
+
inside->type = Part::EXCLUSIVE;
|
|
176
|
+
inside->trasmuted = true;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Partitionable.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include <utility>
|
|
12
|
+
#include "Part.h"
|
|
13
|
+
|
|
14
|
+
class Partitionable {
|
|
15
|
+
public:
|
|
16
|
+
explicit Partitionable() {}
|
|
17
|
+
virtual ~Partitionable() = default;
|
|
18
|
+
void partition();
|
|
19
|
+
Part* find_first_part_by_position(Position* position);
|
|
20
|
+
std::pair<
|
|
21
|
+
std::vector<std::vector<Point*>>,
|
|
22
|
+
std::vector<std::vector<Point*>>> sew(std::vector<Point*> intersection, Polyline* other);
|
|
23
|
+
|
|
24
|
+
protected:
|
|
25
|
+
std::vector<Part*> parts_;
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
void add_part(Part* new_part);
|
|
29
|
+
void trasmute_parts();
|
|
30
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Polyline.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <limits>
|
|
11
|
+
#include <unordered_set>
|
|
12
|
+
#include "Polyline.h"
|
|
13
|
+
#include "Tile.h"
|
|
14
|
+
#include "Shape.h"
|
|
15
|
+
|
|
16
|
+
Polyline::Polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds)
|
|
17
|
+
: raw_(polygon),
|
|
18
|
+
tile(tile)
|
|
19
|
+
{ if (bounds.has_value()) {
|
|
20
|
+
min_x = bounds->min_x;
|
|
21
|
+
max_x = bounds->max_x;
|
|
22
|
+
min_y = bounds->min_y;
|
|
23
|
+
max_y_ = bounds->max_y;
|
|
24
|
+
} else {
|
|
25
|
+
this->find_boundary(); // TODO(ema): optimize when merging the bounds are the sum of the previouses
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void Polyline::precalc() {
|
|
30
|
+
next_tile_eligible_shapes_.clear(); // useless if called once
|
|
31
|
+
for (Shape* s : tile->circular_next->boundary_shapes())
|
|
32
|
+
{ if (!s->outer_polyline->is_on(Polyline::TRACKED_OUTER) && this->vert_intersect(*s->outer_polyline) )
|
|
33
|
+
{ next_tile_eligible_shapes_.push_back(s);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
bool Polyline::vert_intersect(Polyline& other) {
|
|
39
|
+
return( !(this->max_y_ < other.min_y || other.max_y_ < this->min_y));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
int Polyline::width() {
|
|
43
|
+
if (raw_.empty()) return 0;
|
|
44
|
+
return(max_x - min_x);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
bool Polyline::boundary() {
|
|
48
|
+
return( tile->tg_border(Point{min_x, 0}) || tile->tg_border(Point{max_x, 0}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void Polyline::find_boundary() {
|
|
52
|
+
if (raw_.empty()) return;
|
|
53
|
+
min_x = std::numeric_limits<int>::max();
|
|
54
|
+
max_x = -std::numeric_limits<int>::max();
|
|
55
|
+
min_y = std::numeric_limits<int>::max();
|
|
56
|
+
max_y_ = -std::numeric_limits<int>::max();
|
|
57
|
+
for (Point* p : raw_) {
|
|
58
|
+
if (!p) continue;
|
|
59
|
+
int x = p->x;
|
|
60
|
+
int y = p->y;
|
|
61
|
+
if (x < min_x) min_x = x;
|
|
62
|
+
if (x > max_x) max_x = x;
|
|
63
|
+
if (y < min_y) min_y = y;
|
|
64
|
+
if (y > max_y_) max_y_ = y;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
struct PointHash {
|
|
69
|
+
size_t operator()(const Point* p) const {
|
|
70
|
+
if (!p) return 0;
|
|
71
|
+
std::hash<double> hasher;
|
|
72
|
+
size_t h1 = hasher(p->x);
|
|
73
|
+
size_t h2 = hasher(p->y);
|
|
74
|
+
return h1 ^ (h2 << 1);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
struct PointEqual {
|
|
79
|
+
bool operator()(const Point* p1, const Point* p2) const {
|
|
80
|
+
if (!p1 || !p2) return p1 == p2;
|
|
81
|
+
return *p1 == *p2;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
std::vector<Point*> Polyline::intersection(const Polyline* other) const {
|
|
86
|
+
std::vector<Point*> result;
|
|
87
|
+
if (!other) return result;
|
|
88
|
+
std::unordered_set<Point*, PointHash, PointEqual> other_set;
|
|
89
|
+
other_set.reserve(other->raw().size());
|
|
90
|
+
for (Point* p : other->raw()) {
|
|
91
|
+
if (p) other_set.insert(p);
|
|
92
|
+
}
|
|
93
|
+
for (Point* p : raw_) {
|
|
94
|
+
if (!p) continue;
|
|
95
|
+
if (other_set.count(p)) {
|
|
96
|
+
result.push_back(p);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void Polyline::clear() {
|
|
103
|
+
this->raw_.clear();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
bool Polyline::is_empty() {
|
|
107
|
+
return raw_.empty();
|
|
108
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Polyline.h
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <list>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
#include <optional>
|
|
13
|
+
#include <vector>
|
|
14
|
+
#include "Partitionable.h"
|
|
15
|
+
#include "../RectBounds.h"
|
|
16
|
+
|
|
17
|
+
class Tile;
|
|
18
|
+
class Shape;
|
|
19
|
+
class Point;
|
|
20
|
+
|
|
21
|
+
class Polyline : public Partitionable {
|
|
22
|
+
public:
|
|
23
|
+
using Partitionable::Partitionable;
|
|
24
|
+
Polyline(Tile* tile, const std::vector<Point*>& polygon, const std::optional<RectBounds>& bounds = std::nullopt);
|
|
25
|
+
enum Flags : uint32_t {
|
|
26
|
+
TRACKED_OUTER = 1 << 0,
|
|
27
|
+
TRACKED_INNER = 1 << 1
|
|
28
|
+
};
|
|
29
|
+
void turn_on(Flags f) { flags_ |= f; }
|
|
30
|
+
void turn_off(Flags f) { flags_ &= ~f; }
|
|
31
|
+
bool is_on(Flags f) const { return(flags_ & f); }
|
|
32
|
+
bool boundary();
|
|
33
|
+
void precalc();
|
|
34
|
+
int width();
|
|
35
|
+
Tile *tile = nullptr;
|
|
36
|
+
Shape* shape = nullptr;
|
|
37
|
+
std::vector<Point*> raw() const { return raw_; }
|
|
38
|
+
const std::list<Shape*>& next_tile_eligible_shapes() const { return next_tile_eligible_shapes_; }
|
|
39
|
+
const std::vector<Part*>& parts() const { return parts_; }
|
|
40
|
+
std::vector<Point*> intersection(const Polyline* other) const;
|
|
41
|
+
const int max_y() const { return max_y_; }
|
|
42
|
+
void clear();
|
|
43
|
+
bool is_empty();
|
|
44
|
+
bool vert_intersect(Polyline& other);
|
|
45
|
+
|
|
46
|
+
private:
|
|
47
|
+
std::vector<Point*> raw_;
|
|
48
|
+
int min_x, max_x, min_y, max_y_;
|
|
49
|
+
void find_boundary();
|
|
50
|
+
uint32_t flags_ = 0;
|
|
51
|
+
std::list<Shape*> next_tile_eligible_shapes_;
|
|
52
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Poolable.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#include <utility>
|
|
10
|
+
#include "Poolable.h"
|
|
11
|
+
|
|
12
|
+
Poolable::Poolable(int number_of_threads) : stop(false) {
|
|
13
|
+
if (number_of_threads == -1) {
|
|
14
|
+
number_of_threads_ = static_cast<int>(std::thread::hardware_concurrency());
|
|
15
|
+
} else {
|
|
16
|
+
number_of_threads_ = number_of_threads;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (int i = 0; i < number_of_threads_; ++i) {
|
|
20
|
+
workers.emplace_back([this] {
|
|
21
|
+
while (true) {
|
|
22
|
+
std::function<void()> task;
|
|
23
|
+
{
|
|
24
|
+
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
|
25
|
+
this->condition.wait(lock, [this] {
|
|
26
|
+
return this->stop || !this->tasks.empty();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (this->stop && this->tasks.empty()) return;
|
|
30
|
+
|
|
31
|
+
task = std::move(this->tasks.front());
|
|
32
|
+
this->tasks.pop();
|
|
33
|
+
active_tasks++;
|
|
34
|
+
}
|
|
35
|
+
task();
|
|
36
|
+
active_tasks--;
|
|
37
|
+
wait_cv.notify_all();
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
Poolable::~Poolable() {
|
|
44
|
+
{
|
|
45
|
+
std::unique_lock<std::mutex> lock(queue_mutex);
|
|
46
|
+
stop = true;
|
|
47
|
+
}
|
|
48
|
+
condition.notify_all();
|
|
49
|
+
for (std::thread &worker : workers) {
|
|
50
|
+
if (worker.joinable()) worker.join();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
void Poolable::wait() {
|
|
55
|
+
std::unique_lock<std::mutex> lock(queue_mutex);
|
|
56
|
+
wait_cv.wait(lock, [this] {
|
|
57
|
+
return tasks.empty() && active_tasks == 0;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Poolable.cpp
|
|
3
|
+
*
|
|
4
|
+
* Created on: 23 nov 2025
|
|
5
|
+
* Author: ema
|
|
6
|
+
* Copyright 2025 Emanuele Cesaroni
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
#pragma once
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include <thread>
|
|
12
|
+
#include <queue>
|
|
13
|
+
#include <functional>
|
|
14
|
+
#include <mutex>
|
|
15
|
+
#include <condition_variable>
|
|
16
|
+
#include <atomic>
|
|
17
|
+
#include <utility>
|
|
18
|
+
|
|
19
|
+
class Poolable {
|
|
20
|
+
public:
|
|
21
|
+
// 0 (synch), -1 (maximum availables), or N thread
|
|
22
|
+
explicit Poolable(int number_of_threads);
|
|
23
|
+
~Poolable();
|
|
24
|
+
|
|
25
|
+
template<typename Payload, typename F>
|
|
26
|
+
void enqueue(Payload payload, F&& func) {
|
|
27
|
+
if (number_of_threads_ > 0) {
|
|
28
|
+
{
|
|
29
|
+
std::unique_lock<std::mutex> lock(queue_mutex);
|
|
30
|
+
tasks.emplace([payload = std::move(payload), fn = std::forward<F>(func)]() mutable {
|
|
31
|
+
fn(payload);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
condition.notify_one();
|
|
35
|
+
} else {
|
|
36
|
+
func(payload); // 0 thread
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
void wait();
|
|
40
|
+
|
|
41
|
+
private:
|
|
42
|
+
std::vector<std::thread> workers;
|
|
43
|
+
std::queue<std::function<void()>> tasks;
|
|
44
|
+
|
|
45
|
+
std::mutex queue_mutex;
|
|
46
|
+
std::condition_variable condition;
|
|
47
|
+
std::condition_variable wait_cv;
|
|
48
|
+
|
|
49
|
+
int number_of_threads_;
|
|
50
|
+
bool stop = false;
|
|
51
|
+
std::atomic<int> active_tasks{0};
|
|
52
|
+
};
|