contrek 1.1.2 → 1.1.3
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 +1 -0
- data/CHANGELOG.md +6 -1
- data/Gemfile.lock +1 -1
- data/LICENSE-MIT.md +9 -0
- data/README.md +41 -1
- data/contrek.gemspec +0 -1
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +14 -2
- data/ext/cpp_polygon_finder/PolygonFinder/LICENSE_AGPL.txt +661 -0
- data/ext/cpp_polygon_finder/PolygonFinder/examples/example.cpp +9 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +9 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +13 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.cpp +74 -82
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/List.h +12 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.cpp +0 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Lists.h +0 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +39 -39
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +10 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +24 -39
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +5 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +6 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +9 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +33 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +5 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +8 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +2 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +13 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +2 -0
- data/ext/cpp_polygon_finder/extconf.rb +12 -2
- data/lib/contrek/bitmaps/painting.rb +1 -0
- data/lib/contrek/finder/concurrent/cursor.rb +5 -5
- data/lib/contrek/finder/concurrent/finder.rb +2 -1
- data/lib/contrek/finder/concurrent/part.rb +12 -3
- data/lib/contrek/finder/concurrent/partitionable.rb +7 -5
- data/lib/contrek/finder/node.rb +41 -29
- data/lib/contrek/finder/node_cluster.rb +18 -12
- data/lib/contrek/finder/polygon_finder.rb +4 -3
- data/lib/contrek/version.rb +1 -1
- metadata +8 -7
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/*
|
|
2
|
+
* example.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
8
9
|
|
|
9
10
|
#include <iostream>
|
|
10
11
|
#include "ContrekApi.h"
|
|
@@ -29,6 +30,7 @@ int main() {
|
|
|
29
30
|
cfg.threads = 4;
|
|
30
31
|
cfg.tiles = 4;
|
|
31
32
|
cfg.compress_unique = true;
|
|
33
|
+
cfg.connectivity_mode = Contrek::Connectivity::OMNIDIRECTIONAL;
|
|
32
34
|
|
|
33
35
|
CpuTimer cpu_timer;
|
|
34
36
|
cpu_timer.start();
|
|
@@ -26,6 +26,11 @@ enum class MatchMode {
|
|
|
26
26
|
EXACT_COLOR // Tracks border of what exactly matchs target color
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
enum class Connectivity {
|
|
30
|
+
ORTHOGONAL = 4, // up, down, left, right 4 directions
|
|
31
|
+
OMNIDIRECTIONAL = 8 // 8 directions
|
|
32
|
+
};
|
|
33
|
+
|
|
29
34
|
struct Config {
|
|
30
35
|
int threads = 4;
|
|
31
36
|
int tiles = 2;
|
|
@@ -35,6 +40,7 @@ struct Config {
|
|
|
35
40
|
bool treemap = false;
|
|
36
41
|
int32_t target_color = -1;
|
|
37
42
|
MatchMode mode = MatchMode::NOT_COLOR;
|
|
43
|
+
Connectivity connectivity_mode = Connectivity::ORTHOGONAL;
|
|
38
44
|
};
|
|
39
45
|
|
|
40
46
|
inline std::unique_ptr<ProcessResult> trace(const std::string& image_path, const Config& cfg = Config()) {
|
|
@@ -64,6 +70,9 @@ inline std::unique_ptr<ProcessResult> trace(const std::string& image_path, const
|
|
|
64
70
|
if (m.flag) internal_args.emplace_back(m.arg);
|
|
65
71
|
}
|
|
66
72
|
internal_args.push_back("--number_of_tiles=" + std::to_string(cfg.tiles));
|
|
73
|
+
if(cfg.connectivity_mode == Connectivity::OMNIDIRECTIONAL) {
|
|
74
|
+
internal_args.push_back("--connectivity=" + std::to_string(8));
|
|
75
|
+
}
|
|
67
76
|
|
|
68
77
|
Finder finder(cfg.threads, bitmap.get(), matcher.get(), &internal_args);
|
|
69
78
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* See the LICENSE file in this directory for the full license text.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
#include <sys/mman.h>
|
|
10
11
|
#include <iostream>
|
|
11
12
|
#include <vector>
|
|
12
13
|
#include <fstream>
|
|
@@ -38,6 +39,7 @@ FastPngBitmap::FastPngBitmap(std::string filename) : Bitmap("", 0) {
|
|
|
38
39
|
size_t out_size;
|
|
39
40
|
spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);
|
|
40
41
|
this->image.resize(out_size);
|
|
42
|
+
madvise(this->image.data(), out_size, MADV_HUGEPAGE);
|
|
41
43
|
int error = spng_decode_image(ctx, image.data(), out_size, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
|
|
42
44
|
spng_ctx_free(ctx);
|
|
43
45
|
this->png_error = error;
|
|
@@ -22,7 +22,7 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
|
|
|
22
22
|
char** argv = &argv0[0];
|
|
23
23
|
int argc = argv0.size() -1;
|
|
24
24
|
|
|
25
|
-
enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, NUMBER_OF_TILES, COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP, NAMED_SEQUENCES, BOUNDS};
|
|
25
|
+
enum optionIndex { COMPRESS_UNIQ, VERSUS, COMPRESS_VISVALINGAM, COMPRESS_LINEAR, NUMBER_OF_TILES, COMPRESS_VISVALINGAM_TOLERANCE, TREEMAP, NAMED_SEQUENCES, BOUNDS, CONNECTIVITY};
|
|
26
26
|
const option::Descriptor usage[] = {
|
|
27
27
|
// {UNKNOWN, 0,"" , "" ,option::Arg::None, 0},
|
|
28
28
|
{COMPRESS_VISVALINGAM, 0, "" , "compress_visvalingam", option::Arg::None, 0},
|
|
@@ -34,6 +34,7 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
|
|
|
34
34
|
{NAMED_SEQUENCES, 0, "", "named_sequences", option::Arg::None, 0},
|
|
35
35
|
{BOUNDS, 0, "", "bounds", option::Arg::None, 0},
|
|
36
36
|
{VERSUS, 0, "v", "versus", option::Arg::Optional, 0},
|
|
37
|
+
{CONNECTIVITY, 0, "c", "connectivity", option::Arg::Optional, 0},
|
|
37
38
|
{0, 0, 0, 0, 0, 0}
|
|
38
39
|
};
|
|
39
40
|
|
|
@@ -58,9 +59,19 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
|
|
|
58
59
|
if (ioptions[NUMBER_OF_TILES].count() > 0)
|
|
59
60
|
{ try {
|
|
60
61
|
options.number_of_tiles = std::stoi(ioptions[NUMBER_OF_TILES].arg);
|
|
62
|
+
if (options.number_of_tiles <= 0) options.number_of_tiles = 1;
|
|
61
63
|
}
|
|
62
64
|
catch (const std::invalid_argument&) {
|
|
63
|
-
std::cerr << "Errore: --number_of_tiles
|
|
65
|
+
std::cerr << "Errore: --number_of_tiles requires a number\n";
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// CONNECTIVITY
|
|
69
|
+
if (ioptions[CONNECTIVITY].count() > 0)
|
|
70
|
+
{ try {
|
|
71
|
+
if (std::stoi(ioptions[CONNECTIVITY].arg) == 8) options.connectivity_offset = 1;
|
|
72
|
+
}
|
|
73
|
+
catch (const std::invalid_argument&) {
|
|
74
|
+
std::cerr << "Errore: --connectivity requires a number\n";
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
// TREEMAP
|
|
@@ -10,109 +10,101 @@
|
|
|
10
10
|
#include "List.h"
|
|
11
11
|
#include <iostream>
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
List::List(int id) : start(nullptr), end(nullptr), isize(0), idd(id) {}
|
|
14
14
|
|
|
15
|
-
List::
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this->idd = id;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Listable *List::first() {
|
|
23
|
-
return(this->start);
|
|
24
|
-
}
|
|
25
|
-
Listable *List::last() {
|
|
26
|
-
return(this->end);
|
|
27
|
-
}
|
|
15
|
+
Listable *List::first() { return this->start; }
|
|
16
|
+
Listable *List::last() { return this->end; }
|
|
17
|
+
int List::get_id() { return this->idd; }
|
|
18
|
+
int List::size() { return this->isize; }
|
|
28
19
|
|
|
29
20
|
bool List::contains(Listable *entry) {
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
int List::get_id() {
|
|
33
|
-
return(this->idd);
|
|
21
|
+
return entry->data_pointer[this->idd].inside;
|
|
34
22
|
}
|
|
35
23
|
|
|
36
|
-
void List::
|
|
37
|
-
if (source_list->size() == 0) return;
|
|
38
|
-
int source_list_idd = source_list->get_id();
|
|
39
|
-
Listable *source_list_start_entry = source_list->first();
|
|
40
|
-
|
|
41
|
-
Listable *act = source_list->last();
|
|
42
|
-
while (true)
|
|
43
|
-
{ if ((act = act->data_pointer[source_list_idd].prev) == nullptr) break;
|
|
44
|
-
}
|
|
45
|
-
Listable *source_entry = source_list->first();
|
|
46
|
-
while (true)
|
|
47
|
-
{ source_entry->data_pointer[this->idd] = source_entry->data_pointer[source_list_idd];
|
|
48
|
-
Listable *next_entry = source_entry->data_pointer[source_list_idd].next;
|
|
49
|
-
source_entry->data_pointer[source_list_idd].inside = false;
|
|
50
|
-
source_entry->data_pointer[source_list_idd].next = nullptr;
|
|
51
|
-
source_entry->data_pointer[source_list_idd].prev = nullptr;
|
|
52
|
-
if (next_entry == nullptr) break;
|
|
53
|
-
source_entry = next_entry;
|
|
54
|
-
}
|
|
55
|
-
source_list_start_entry->data_pointer[this->idd].prev = this->end;
|
|
56
|
-
if (this->end != nullptr) this->end->data_pointer[this->idd].next = source_list_start_entry;
|
|
57
|
-
this->end = source_list->last();
|
|
58
|
-
if (this->start == nullptr) this->start = source_list->first();
|
|
59
|
-
this->isize += source_list->size();
|
|
60
|
-
source_list->reset();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
void List::reset() {
|
|
24
|
+
void List::reset() {
|
|
64
25
|
this->end = nullptr;
|
|
65
26
|
this->start = nullptr;
|
|
66
27
|
this->isize = 0;
|
|
67
28
|
}
|
|
68
29
|
|
|
69
|
-
Listable *List::shift() {
|
|
70
|
-
if (this->isize == 0) return(nullptr);
|
|
71
|
-
Listable *retme = this->start;
|
|
72
|
-
Listable *next_of_retme = retme->data_pointer[this->idd].next;
|
|
73
|
-
this->start = next_of_retme;
|
|
74
|
-
if (retme == this->end) this->end = nullptr;
|
|
75
|
-
if (next_of_retme != nullptr) next_of_retme->data_pointer[this->idd].prev = nullptr;
|
|
76
|
-
this->isize--;
|
|
77
|
-
retme->data_pointer[this->idd].next = nullptr;
|
|
78
|
-
retme->data_pointer[this->idd].prev = nullptr;
|
|
79
|
-
retme->data_pointer[this->idd].inside = false;
|
|
80
|
-
return (retme);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
30
|
void List::push_back(Listable *entry) {
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
31
|
+
auto& meta = entry->data_pointer[this->idd];
|
|
32
|
+
if (meta.inside) return;
|
|
33
|
+
|
|
34
|
+
if (this->isize > 0) {
|
|
35
|
+
this->end->data_pointer[this->idd].next = entry;
|
|
36
|
+
meta.prev = this->end;
|
|
88
37
|
} else {
|
|
89
38
|
this->start = entry;
|
|
39
|
+
meta.prev = nullptr;
|
|
90
40
|
}
|
|
41
|
+
|
|
42
|
+
meta.next = nullptr;
|
|
91
43
|
this->end = entry;
|
|
92
|
-
|
|
44
|
+
meta.inside = true;
|
|
93
45
|
this->isize++;
|
|
94
46
|
}
|
|
95
|
-
int List::size() {
|
|
96
|
-
return(this->isize);
|
|
97
|
-
}
|
|
98
47
|
|
|
99
48
|
void List::remove(Listable *entry) {
|
|
100
|
-
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
Listable *
|
|
49
|
+
auto& meta = entry->data_pointer[this->idd];
|
|
50
|
+
if (this->isize == 0 || !meta.inside) return;
|
|
51
|
+
|
|
52
|
+
Listable *nxt = meta.next;
|
|
53
|
+
Listable *prv = meta.prev;
|
|
54
|
+
|
|
55
|
+
if (entry == this->start) this->start = nxt;
|
|
56
|
+
if (entry == this->end) this->end = prv;
|
|
57
|
+
|
|
58
|
+
if (nxt) nxt->data_pointer[this->idd].prev = prv;
|
|
59
|
+
if (prv) prv->data_pointer[this->idd].next = nxt;
|
|
60
|
+
|
|
61
|
+
meta.next = nullptr;
|
|
62
|
+
meta.prev = nullptr;
|
|
63
|
+
meta.inside = false;
|
|
64
|
+
this->isize--;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
Listable *List::shift() {
|
|
68
|
+
if (this->isize == 0) return nullptr;
|
|
69
|
+
Listable *retme = this->start;
|
|
70
|
+
auto& meta = retme->data_pointer[this->idd];
|
|
71
|
+
|
|
72
|
+
this->start = meta.next;
|
|
73
|
+
if (retme == this->end) this->end = nullptr;
|
|
74
|
+
if (this->start) this->start->data_pointer[this->idd].prev = nullptr;
|
|
75
|
+
|
|
76
|
+
this->isize--;
|
|
77
|
+
meta.next = nullptr;
|
|
78
|
+
meta.prev = nullptr;
|
|
79
|
+
meta.inside = false;
|
|
80
|
+
return retme;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
void List::grab(List *source_list) {
|
|
84
|
+
if (source_list->isize == 0) return;
|
|
104
85
|
|
|
105
|
-
|
|
106
|
-
|
|
86
|
+
int src_idd = source_list->idd;
|
|
87
|
+
Listable *current = source_list->start;
|
|
88
|
+
|
|
89
|
+
while (current) {
|
|
90
|
+
auto& src_meta = current->data_pointer[src_idd];
|
|
91
|
+
auto& dst_meta = current->data_pointer[this->idd];
|
|
92
|
+
dst_meta = src_meta;
|
|
93
|
+
src_meta.inside = false;
|
|
94
|
+
src_meta.next = nullptr;
|
|
95
|
+
src_meta.prev = nullptr;
|
|
96
|
+
current = dst_meta.next;
|
|
107
97
|
}
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
|
|
99
|
+
if (this->isize > 0) {
|
|
100
|
+
this->end->data_pointer[this->idd].next = source_list->start;
|
|
101
|
+
source_list->start->data_pointer[this->idd].prev = this->end;
|
|
102
|
+
this->end = source_list->end;
|
|
103
|
+
} else {
|
|
104
|
+
this->start = source_list->start;
|
|
105
|
+
this->end = source_list->end;
|
|
110
106
|
}
|
|
111
107
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
entry->data_pointer[this->idd].next = nullptr;
|
|
115
|
-
entry->data_pointer[this->idd].prev = nullptr;
|
|
116
|
-
this->isize--;
|
|
117
|
-
entry->data_pointer[this->idd].inside = false;
|
|
108
|
+
this->isize += source_list->isize;
|
|
109
|
+
source_list->reset();
|
|
118
110
|
}
|
|
@@ -8,13 +8,21 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
#pragma once
|
|
11
|
+
#include <array>
|
|
12
|
+
|
|
13
|
+
// Forward declaration
|
|
14
|
+
class Listable;
|
|
15
|
+
|
|
16
|
+
// Definizione completa di Link (necessaria per std::array)
|
|
17
|
+
struct Link {
|
|
18
|
+
Listable* next = nullptr;
|
|
19
|
+
Listable* prev = nullptr;
|
|
20
|
+
bool inside = false;
|
|
21
|
+
};
|
|
11
22
|
|
|
12
|
-
#include <vector>
|
|
13
|
-
#include "Lists.h"
|
|
14
|
-
struct Link;
|
|
15
23
|
class Listable {
|
|
16
24
|
public:
|
|
17
|
-
std::
|
|
25
|
+
std::array<Link, 3> data_pointer;
|
|
18
26
|
};
|
|
19
27
|
|
|
20
28
|
class List {
|
|
@@ -25,13 +25,3 @@ List *Lists::add_list() {
|
|
|
25
25
|
lists.push_back(list);
|
|
26
26
|
return(list);
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
std::vector<Link> Lists::get_data_pointer() {
|
|
30
|
-
std::vector<Link> data(this->lists.size());
|
|
31
|
-
for (auto& dt : data) {
|
|
32
|
-
dt.inside = false;
|
|
33
|
-
dt.next = nullptr;
|
|
34
|
-
dt.prev = nullptr;
|
|
35
|
-
}
|
|
36
|
-
return data;
|
|
37
|
-
}
|
|
@@ -11,19 +11,12 @@
|
|
|
11
11
|
#include <list>
|
|
12
12
|
#include <vector>
|
|
13
13
|
#include "List.h"
|
|
14
|
-
class List;
|
|
15
|
-
class Listable;
|
|
16
|
-
struct Link {
|
|
17
|
-
Listable *next, *prev;
|
|
18
|
-
bool inside;
|
|
19
|
-
};
|
|
20
14
|
|
|
21
15
|
class Lists {
|
|
22
16
|
public:
|
|
23
17
|
Lists() {}
|
|
24
18
|
virtual ~Lists();
|
|
25
19
|
List *add_list();
|
|
26
|
-
std::vector<Link> get_data_pointer();
|
|
27
20
|
private:
|
|
28
21
|
std::list<List*> lists;
|
|
29
22
|
};
|
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
#include <string>
|
|
12
12
|
#include <iostream>
|
|
13
13
|
#include <algorithm>
|
|
14
|
+
#include <limits>
|
|
14
15
|
#include <vector>
|
|
15
16
|
#include <list>
|
|
16
17
|
#include "Node.h"
|
|
18
|
+
#include "NodeCluster.h"
|
|
17
19
|
|
|
18
|
-
Node::Node(int min_x, int max_x, int y, char name)
|
|
20
|
+
Node::Node(int min_x, int max_x, int y, char name)
|
|
21
|
+
: start_point(min_x, y),
|
|
22
|
+
end_point(max_x, y) {
|
|
19
23
|
this->name = name;
|
|
20
24
|
this->min_x = min_x;
|
|
21
25
|
this->max_x = max_x;
|
|
@@ -32,64 +36,59 @@ Node::Node(int min_x, int max_x, int y, char name) {
|
|
|
32
36
|
bool Node::get_trackmax() {
|
|
33
37
|
return((this->track & OMAX) != 0);
|
|
34
38
|
}
|
|
39
|
+
|
|
35
40
|
bool Node::track_complete() {
|
|
36
41
|
return((this->track & OCOMPLETE) == OCOMPLETE);
|
|
37
42
|
}
|
|
43
|
+
|
|
38
44
|
bool Node::track_uncomplete() {
|
|
39
45
|
return((this->track & OCOMPLETE) != OCOMPLETE);
|
|
40
46
|
}
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
void Node::add_intersection(Node& other_node, int other_node_index) {
|
|
49
|
+
if (other_node.y < this->y) {
|
|
50
|
+
upper_start = std::min(upper_start, other_node_index);
|
|
51
|
+
upper_end = std::max(upper_end, other_node_index);
|
|
52
|
+
} else {
|
|
53
|
+
lower_start = std::min(lower_start, other_node_index);
|
|
54
|
+
lower_end = std::max(lower_end, other_node_index);
|
|
55
|
+
}
|
|
49
56
|
}
|
|
50
57
|
|
|
51
|
-
void Node::precalc_tangs_sequences(
|
|
58
|
+
void Node::precalc_tangs_sequences(NodeCluster& cluster) {
|
|
52
59
|
this->tangs_sequence.clear();
|
|
53
|
-
this->tangs_sequence.reserve(tangs[T_UP].size() + tangs[T_DOWN].size());
|
|
54
|
-
std::vector<Node*> up_copy = tangs[T_UP];
|
|
55
|
-
std::vector<Node*> down_copy = tangs[T_DOWN];
|
|
56
60
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
int lower_size = this->lower_end >= 0 ? (this->lower_end - this->lower_start + 1) : 0;
|
|
62
|
+
int upper_size = this->upper_end >= 0 ? (this->upper_end - this->upper_start + 1) : 0;
|
|
63
|
+
this->tangs_sequence.reserve(lower_size + upper_size);
|
|
64
|
+
|
|
65
|
+
if (this->upper_end >= 0) {
|
|
66
|
+
this->up_indexer = -cluster.vert_nodes[y + T_UP][this->upper_start].abs_x_index;
|
|
61
67
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
// --- CLOCKWISE (UP) ---
|
|
69
|
+
for (int upper_pos = this->upper_start; upper_pos <= this->upper_end; upper_pos++) {
|
|
70
|
+
Node& t_node = cluster.vert_nodes[y + T_UP][upper_pos];
|
|
71
|
+
tangs_sequence.emplace_back(NodeDescriptor{
|
|
72
|
+
&t_node,
|
|
73
|
+
Tangent{ &t_node.end_point, OMAX},
|
|
74
|
+
Tangent{ &t_node.start_point, OMIN}
|
|
67
75
|
});
|
|
68
76
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
std::sort(down_copy.begin(), down_copy.end(), sort_max_x);
|
|
72
|
-
std::reverse(down_copy.begin(), down_copy.end());
|
|
73
|
-
if (!down_copy.empty()) {
|
|
74
|
-
this->down_indexer = (down_copy.back()->abs_x_index +
|
|
75
|
-
tangs[T_UP].size() + tangs[T_DOWN].size() - 1);
|
|
77
|
+
if (this->lower_end >= 0) {
|
|
78
|
+
this->down_indexer = (cluster.vert_nodes[y + T_DOWN][this->lower_start].abs_x_index + lower_size + upper_size - 1);
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
// --- COUNTER-CLOCKWISE (DOWN) ---
|
|
81
|
+
for (int lower_pos = this->lower_end; lower_pos >= this->lower_start; lower_pos--) {
|
|
82
|
+
Node& t_node = cluster.vert_nodes[y + T_DOWN][lower_pos];
|
|
83
|
+
tangs_sequence.emplace_back(NodeDescriptor{
|
|
84
|
+
&t_node,
|
|
85
|
+
Tangent{&t_node.start_point, OMIN},
|
|
86
|
+
Tangent{&t_node.end_point, OMAX}
|
|
82
87
|
});
|
|
83
88
|
}
|
|
84
89
|
this->tangs_count = this->tangs_sequence.size();
|
|
85
90
|
}
|
|
86
91
|
|
|
87
|
-
bool Node::sort_min_x(Node *a, Node *b) {
|
|
88
|
-
return(a->min_x <= b->min_x);
|
|
89
|
-
}
|
|
90
|
-
bool Node::sort_max_x(Node *a, Node *b) {
|
|
91
|
-
return(a->max_x <= b->max_x);
|
|
92
|
-
}
|
|
93
92
|
Node* Node::my_next_inner(Node *last, int versus) {
|
|
94
93
|
unsigned int last_node_index;
|
|
95
94
|
if (last->y < this->y) last_node_index = last->abs_x_index + this->up_indexer;
|
|
@@ -98,6 +97,7 @@ Node* Node::my_next_inner(Node *last, int versus) {
|
|
|
98
97
|
else last_node_index == this->tangs_sequence.size() - 1 ? last_node_index = 0 : last_node_index++;
|
|
99
98
|
return((this->tangs_sequence)[last_node_index].node);
|
|
100
99
|
}
|
|
100
|
+
|
|
101
101
|
Node* Node::my_next_outer(Node *last, int versus) {
|
|
102
102
|
unsigned int last_node_index;
|
|
103
103
|
if (last->y < this->y) last_node_index = last->abs_x_index + this->up_indexer;
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
#include <string>
|
|
12
12
|
#include <vector>
|
|
13
13
|
#include <list>
|
|
14
|
+
#include <limits>
|
|
15
|
+
#include <algorithm>
|
|
14
16
|
#include <map>
|
|
15
17
|
#include "List.h"
|
|
16
18
|
|
|
@@ -32,10 +34,9 @@ struct Tangent {
|
|
|
32
34
|
};
|
|
33
35
|
struct NodeDescriptor;
|
|
34
36
|
|
|
35
|
-
|
|
36
37
|
class Node : public Listable {
|
|
37
38
|
public:
|
|
38
|
-
static const int T_UP =
|
|
39
|
+
static const int T_UP = -1;
|
|
39
40
|
static const int T_DOWN = 1;
|
|
40
41
|
static const int O = 0;
|
|
41
42
|
static const int A = 1;
|
|
@@ -50,7 +51,6 @@ class Node : public Listable {
|
|
|
50
51
|
static const int OUTER = 0;
|
|
51
52
|
static const int INNER = 1;
|
|
52
53
|
|
|
53
|
-
std::vector<Node*> tangs[2];
|
|
54
54
|
int y;
|
|
55
55
|
int abs_x_index;
|
|
56
56
|
int up_indexer, down_indexer;
|
|
@@ -58,8 +58,12 @@ class Node : public Listable {
|
|
|
58
58
|
char name;
|
|
59
59
|
int track;
|
|
60
60
|
int outer_index, inner_index;
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
int upper_start = std::numeric_limits<int>::max();
|
|
62
|
+
int upper_end = -1;
|
|
63
|
+
int lower_start = std::numeric_limits<int>::max();
|
|
64
|
+
int lower_end = -1;
|
|
65
|
+
Point start_point, end_point;
|
|
66
|
+
void add_intersection(Node& other_node, int other_node_index);
|
|
63
67
|
std::vector<NodeDescriptor> tangs_sequence;
|
|
64
68
|
Point* coords_entering_to(Node *enter_to, int mode, int tracking);
|
|
65
69
|
Node* my_next_outer(Node *last, int versus);
|
|
@@ -68,14 +72,10 @@ class Node : public Listable {
|
|
|
68
72
|
bool track_complete();
|
|
69
73
|
bool get_trackmax();
|
|
70
74
|
|
|
71
|
-
private:
|
|
72
|
-
static bool sort_min_x(Node *a, Node *b);
|
|
73
|
-
static bool sort_max_x(Node *a, Node *b);
|
|
74
|
-
|
|
75
75
|
public:
|
|
76
76
|
int min_x, max_x;
|
|
77
77
|
Node(int min_x, int max_x, int y, char name);
|
|
78
|
-
void precalc_tangs_sequences(
|
|
78
|
+
void precalc_tangs_sequences(NodeCluster& cluster);
|
|
79
79
|
bool processed = false;
|
|
80
80
|
};
|
|
81
81
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include <string>
|
|
15
15
|
#include <vector>
|
|
16
16
|
#include <utility>
|
|
17
|
+
#include <deque>
|
|
17
18
|
#include "NodeCluster.h"
|
|
18
19
|
#include "Node.h"
|
|
19
20
|
#include "RectBounds.h"
|
|
@@ -30,15 +31,9 @@ NodeCluster::NodeCluster(int h, int w, pf_Options *options) {
|
|
|
30
31
|
this->nodes = 0;
|
|
31
32
|
|
|
32
33
|
this->vert_nodes.resize(h);
|
|
33
|
-
for (int i = 0; i < h; ++i) {
|
|
34
|
-
this->vert_nodes[i].reserve(w/2);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
34
|
this->root_nodes = this->lists.add_list();
|
|
38
35
|
this->inner_plot = this->lists.add_list();
|
|
39
36
|
this->inner_new = this->lists.add_list();
|
|
40
|
-
|
|
41
|
-
this->points.reserve(w * h);
|
|
42
37
|
}
|
|
43
38
|
|
|
44
39
|
NodeCluster::~NodeCluster() {
|
|
@@ -74,32 +69,33 @@ void NodeCluster::compress_coords(std::list<Polygon>& polygons, pf_Options optio
|
|
|
74
69
|
void NodeCluster::build_tangs_sequence() {
|
|
75
70
|
for (auto& line : vert_nodes) {
|
|
76
71
|
for (Node& node : line) {
|
|
77
|
-
node.precalc_tangs_sequences(this
|
|
72
|
+
node.precalc_tangs_sequences(*this);
|
|
78
73
|
}
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
Node* NodeCluster::add_node(int min_x, int max_x, int y, char name) {
|
|
77
|
+
Node* NodeCluster::add_node(int min_x, int max_x, int y, char name, int offset) {
|
|
83
78
|
vert_nodes[y].emplace_back(min_x, max_x, y, name);
|
|
84
79
|
|
|
85
80
|
Node& node = vert_nodes[y].back();
|
|
86
|
-
node.data_pointer = this->lists.get_data_pointer();
|
|
87
81
|
node.abs_x_index = vert_nodes[y].size() - 1;
|
|
88
82
|
this->nodes++;
|
|
89
83
|
|
|
90
84
|
root_nodes->push_back(&node);
|
|
91
85
|
|
|
92
86
|
if (y > 0) {
|
|
93
|
-
std::
|
|
87
|
+
std::deque<Node>& up_nodes = vert_nodes[y - 1];
|
|
94
88
|
if (!up_nodes.empty()) {
|
|
95
89
|
auto it = std::lower_bound(up_nodes.begin(), up_nodes.end(), node.min_x,
|
|
96
|
-
[](const Node& a, int val) {
|
|
97
|
-
|
|
90
|
+
[&](const Node& a, int val) {
|
|
91
|
+
return ((a.max_x + offset) < val);
|
|
98
92
|
});
|
|
93
|
+
|
|
99
94
|
while (it != up_nodes.end()) {
|
|
100
|
-
if (it->min_x > node.max_x) break;
|
|
101
|
-
|
|
102
|
-
|
|
95
|
+
if ((it->min_x - offset) > node.max_x) break;
|
|
96
|
+
int current_index = std::distance(up_nodes.begin(), it);
|
|
97
|
+
node.add_intersection(*it, current_index);
|
|
98
|
+
it->add_intersection(node, node.abs_x_index);
|
|
103
99
|
++it;
|
|
104
100
|
}
|
|
105
101
|
}
|
|
@@ -159,13 +155,20 @@ void NodeCluster::plot(int versus) {
|
|
|
159
155
|
|
|
160
156
|
first->inner_index = index_inner;
|
|
161
157
|
|
|
162
|
-
Node
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
158
|
+
Node* next_node = nullptr;
|
|
159
|
+
|
|
160
|
+
if (first->get_trackmax()) {
|
|
161
|
+
if (inner_v == Node::A) {
|
|
162
|
+
if (first->upper_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_UP][first->upper_start];
|
|
163
|
+
} else {
|
|
164
|
+
if (first->lower_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_DOWN][first->lower_start];
|
|
165
|
+
}
|
|
166
166
|
} else {
|
|
167
|
-
if (inner_v == Node::A)
|
|
168
|
-
|
|
167
|
+
if (inner_v == Node::A) {
|
|
168
|
+
if (first->lower_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_DOWN][first->lower_end];
|
|
169
|
+
} else {
|
|
170
|
+
if (first->upper_end >= 0) next_node = &this->vert_nodes[first->y + Node::T_UP][first->upper_end];
|
|
171
|
+
}
|
|
169
172
|
}
|
|
170
173
|
|
|
171
174
|
if (next_node != nullptr)
|
|
@@ -309,21 +312,3 @@ void NodeCluster::plot_node(std::vector<Point*>& sequence_coords, Node *node, No
|
|
|
309
312
|
current_node = next_node;
|
|
310
313
|
}
|
|
311
314
|
}
|
|
312
|
-
|
|
313
|
-
void NodeCluster::list_track(Node *node, std::list<Node*> *list) {
|
|
314
|
-
std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
|
|
315
|
-
if (i == list->end()) list->push_back(node);
|
|
316
|
-
else list_delete(node, list);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
void NodeCluster::list_delete(Node *node, std::list<Node*> *list) {
|
|
320
|
-
std::list<Node*>::iterator i;
|
|
321
|
-
while ((i = std::find(list->begin(), list->end(), node)) != list->end())
|
|
322
|
-
{ list->erase(i);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
bool NodeCluster::list_present(Node *node, std::list<Node*> *list) {
|
|
327
|
-
std::list<Node*>::iterator i = std::find(list->begin(), list->end(), node);
|
|
328
|
-
return(!(i == list->end()));
|
|
329
|
-
}
|