contrek 1.2.8 → 1.3.0
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 +2 -1
- data/.rubocop.yml +11 -0
- data/CHANGELOG.md +7 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +2 -0
- data/contrek.gemspec +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/CMakeLists.txt +2 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +118 -19
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.cpp +5 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +4 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.cpp +14 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +2 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Polygon.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +13 -13
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +79 -354
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +6 -6
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +3 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +8 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/EndPoint.h +4 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.h +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +6 -6
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Merger.cpp +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.cpp +29 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +45 -30
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +18 -19
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +6 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +4 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +7 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +8 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.h +4 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +19 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +6 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp +117 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +41 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.cpp +9 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Tile.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp +4 -13
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.cpp +8 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/LinearReducer.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/Reducer.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.cpp +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/UniqReducer.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.cpp +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/reducers/VisvalingamReducer.h +10 -10
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +66 -16
- data/ext/cpp_polygon_finder/extconf.rb +2 -0
- data/lib/contrek/bitmaps/bitmap.rb +2 -0
- data/lib/contrek/bitmaps/chunky_bitmap.rb +13 -0
- data/lib/contrek/bitmaps/painting.rb +2 -0
- data/lib/contrek/bitmaps/png_bitmap.rb +2 -0
- data/lib/contrek/bitmaps/raw_bitmap.rb +2 -0
- data/lib/contrek/bitmaps/rgb_color.rb +2 -0
- data/lib/contrek/bitmaps/rgb_cpp_color.rb +2 -0
- data/lib/contrek/bitmaps/sample_generator.rb +2 -0
- data/lib/contrek/cpp/cpp_concurrent_finder.rb +2 -0
- data/lib/contrek/cpp/cpp_concurrent_horizontal_merger.rb +2 -0
- data/lib/contrek/cpp/cpp_concurrent_merger.rb +2 -0
- data/lib/contrek/cpp/cpp_concurrent_streaming_merger.rb +11 -0
- data/lib/contrek/cpp/cpp_concurrent_vertical_merger.rb +2 -0
- data/lib/contrek/cpp/cpp_result.rb +2 -0
- data/lib/contrek/cpp/cpp_tempfile.rb +28 -0
- data/lib/contrek/finder/bounds.rb +2 -0
- data/lib/contrek/finder/concurrent/clipped_polygon_finder.rb +2 -0
- data/lib/contrek/finder/concurrent/cluster.rb +3 -1
- data/lib/contrek/finder/concurrent/cursor.rb +2 -0
- data/lib/contrek/finder/concurrent/end_point.rb +2 -0
- data/lib/contrek/finder/concurrent/fake_cluster.rb +2 -0
- data/lib/contrek/finder/concurrent/finder.rb +6 -0
- data/lib/contrek/finder/concurrent/horizontal_merger.rb +2 -0
- data/lib/contrek/finder/concurrent/hub.rb +2 -0
- data/lib/contrek/finder/concurrent/inner_polyline.rb +2 -0
- data/lib/contrek/finder/concurrent/listable.rb +2 -0
- data/lib/contrek/finder/concurrent/merger.rb +4 -0
- data/lib/contrek/finder/concurrent/part.rb +13 -0
- data/lib/contrek/finder/concurrent/partitionable.rb +33 -17
- data/lib/contrek/finder/concurrent/polyline.rb +2 -0
- data/lib/contrek/finder/concurrent/poolable.rb +2 -0
- data/lib/contrek/finder/concurrent/position.rb +2 -0
- data/lib/contrek/finder/concurrent/queueable.rb +2 -0
- data/lib/contrek/finder/concurrent/sequence.rb +2 -0
- data/lib/contrek/finder/concurrent/shape.rb +2 -0
- data/lib/contrek/finder/concurrent/streaming_merger.rb +89 -0
- data/lib/contrek/finder/concurrent/tile.rb +2 -0
- data/lib/contrek/finder/concurrent/vertical_merger.rb +8 -2
- data/lib/contrek/finder/list.rb +2 -0
- data/lib/contrek/finder/list_entry.rb +2 -0
- data/lib/contrek/finder/listable.rb +2 -0
- data/lib/contrek/finder/lists.rb +2 -0
- data/lib/contrek/finder/node.rb +2 -0
- data/lib/contrek/finder/node_cluster.rb +3 -1
- data/lib/contrek/finder/polygon_finder.rb +4 -1
- data/lib/contrek/finder/result.rb +2 -0
- data/lib/contrek/map/mercator_projection.rb +2 -0
- data/lib/contrek/matchers/matcher.rb +2 -0
- data/lib/contrek/matchers/matcher_hsb.rb +2 -0
- data/lib/contrek/matchers/value_not_matcher.rb +2 -0
- data/lib/contrek/reducers/linear_reducer.rb +2 -0
- data/lib/contrek/reducers/reducer.rb +2 -0
- data/lib/contrek/reducers/uniq_reducer.rb +2 -0
- data/lib/contrek/reducers/visvalingam_reducer.rb +2 -0
- data/lib/contrek/shared/result.rb +2 -0
- data/lib/contrek/version.rb +3 -1
- data/lib/contrek.rb +5 -0
- metadata +11 -5
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* StreamingMerger.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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "StreamingMerger.h"
|
|
11
|
+
#include <sstream>
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <vector>
|
|
14
|
+
#include <string>
|
|
15
|
+
|
|
16
|
+
StreamingMerger::StreamingMerger(int number_of_threads,
|
|
17
|
+
std::vector<std::string>* options,
|
|
18
|
+
std::ofstream* stream_to,
|
|
19
|
+
int total_width, int total_height)
|
|
20
|
+
: VerticalMerger(number_of_threads, options), stream(stream_to), total_width(total_width), total_height(total_height) {
|
|
21
|
+
if (!stream) {
|
|
22
|
+
throw std::invalid_argument("Streaming requires a valid destination output. stream_to cannot be null.");
|
|
23
|
+
}
|
|
24
|
+
if (total_width <= 0 || total_height <= 0) {
|
|
25
|
+
throw std::invalid_argument("Streaming requires valid canvas dimensions (width and height must be > 0).");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
void StreamingMerger::add_tile(ProcessResult& result, bool flush)
|
|
30
|
+
{ VerticalMerger::add_tile(result);
|
|
31
|
+
if (tiles_.size() == 2) {
|
|
32
|
+
this->process_tiles();
|
|
33
|
+
this->tiles_.queue_push(this->whole_tile);
|
|
34
|
+
this->stream_polygons(this->whole_tile, flush);
|
|
35
|
+
this->whole_tile->shapes().shrink_to_fit();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ProcessResult* StreamingMerger::process_info() {
|
|
40
|
+
ProcessResult *pr = VerticalMerger::process_info();
|
|
41
|
+
pr->groups = this->moved;
|
|
42
|
+
return(pr);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
|
|
46
|
+
ensure_header();
|
|
47
|
+
if (int tile_end_x = tile->end_x(); true) {
|
|
48
|
+
tile->shapes().erase(
|
|
49
|
+
std::remove_if(tile->shapes().begin(), tile->shapes().end(), [this, flush, tile_end_x](Shape* shape) {
|
|
50
|
+
if (flush || shape->outer_polyline->max_x() < (tile_end_x - 1)) {
|
|
51
|
+
this->moved++;
|
|
52
|
+
this->stream_raw_polygon(shape);
|
|
53
|
+
shape->detach_from_pool();
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}),
|
|
58
|
+
tile->shapes().end());
|
|
59
|
+
}
|
|
60
|
+
stream->flush();
|
|
61
|
+
if (flush) {
|
|
62
|
+
ensure_footer();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void StreamingMerger::stream_raw_polygon(const Shape* shape) {
|
|
67
|
+
std::ostringstream outer_oss;
|
|
68
|
+
const std::vector<Point>& points = shape->outer_polyline->raw();
|
|
69
|
+
for (size_t i = 0; i < points.size(); ++i) {
|
|
70
|
+
outer_oss << points[i].y << "," << points[i].x;
|
|
71
|
+
if (i < points.size() - 1) outer_oss << " ";
|
|
72
|
+
}
|
|
73
|
+
*stream << svg_outer_polygon_string(outer_oss.str());
|
|
74
|
+
|
|
75
|
+
for (const auto& inner_polyline : shape->inner_polylines) {
|
|
76
|
+
std::ostringstream inner_oss;
|
|
77
|
+
const std::vector<Point>& inner_points = inner_polyline->raw();
|
|
78
|
+
for (size_t i = 0; i < inner_points.size(); ++i) {
|
|
79
|
+
inner_oss << inner_points[i].y << "," << inner_points[i].x;
|
|
80
|
+
if (i < inner_points.size() - 1) inner_oss << " ";
|
|
81
|
+
}
|
|
82
|
+
*stream << svg_inner_polygon_string(inner_oss.str());
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
void StreamingMerger::ensure_header() {
|
|
87
|
+
if (stream && stream->tellp() == 0) {
|
|
88
|
+
*stream << svg_header_string();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
void StreamingMerger::ensure_footer() {
|
|
93
|
+
if (stream) {
|
|
94
|
+
*stream << svg_footer_string();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
std::string StreamingMerger::svg_css() {
|
|
99
|
+
return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
std::string StreamingMerger::svg_header_string() {
|
|
103
|
+
return "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" + std::to_string(total_width) +
|
|
104
|
+
"\" height=\"" + std::to_string(total_height) + "\"><style>" + svg_css() + "</style>";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
std::string StreamingMerger::svg_footer_string() {
|
|
108
|
+
return "</svg>";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
std::string StreamingMerger::svg_outer_polygon_string(std::string_view points) {
|
|
112
|
+
return "<polygon points=\"" + std::string(points) + "\" class=\"out\"/>";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
std::string StreamingMerger::svg_inner_polygon_string(std::string_view points) {
|
|
116
|
+
return "<polygon points=\"" + std::string(points) + "\" class=\"in\"/>";
|
|
117
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* StreamingMerger.h
|
|
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
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
#include "VerticalMerger.h"
|
|
12
|
+
#include <fstream>
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <string_view>
|
|
15
|
+
#include <stdexcept>
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
class StreamingMerger : public VerticalMerger {
|
|
19
|
+
private:
|
|
20
|
+
std::ofstream* stream;
|
|
21
|
+
int total_width;
|
|
22
|
+
int total_height;
|
|
23
|
+
int moved = 0;
|
|
24
|
+
void ensure_header();
|
|
25
|
+
void ensure_footer();
|
|
26
|
+
void stream_polygons(Tile* tile, bool flush = false);
|
|
27
|
+
void stream_raw_polygon(const Shape* shape);
|
|
28
|
+
virtual std::string svg_css();
|
|
29
|
+
virtual std::string svg_header_string();
|
|
30
|
+
virtual std::string svg_footer_string();
|
|
31
|
+
virtual std::string svg_outer_polygon_string(std::string_view points);
|
|
32
|
+
virtual std::string svg_inner_polygon_string(std::string_view points);
|
|
33
|
+
|
|
34
|
+
public:
|
|
35
|
+
StreamingMerger(int number_of_threads,
|
|
36
|
+
std::vector<std::string>* options,
|
|
37
|
+
std::ofstream* stream_to,
|
|
38
|
+
int total_width, int total_height);
|
|
39
|
+
void add_tile(ProcessResult& result, bool flush = false);
|
|
40
|
+
ProcessResult* process_info() override;
|
|
41
|
+
};
|
|
@@ -27,6 +27,7 @@ Tile::Tile(Finder *finder, int start_x, int end_x, std::string name, const Bench
|
|
|
27
27
|
name_(name),
|
|
28
28
|
benchmarks(b) {
|
|
29
29
|
this->shapes_pool = new ShapePool();
|
|
30
|
+
this->shapes_pool->set_owner(this);
|
|
30
31
|
this->shapes_pools.push_back(this->shapes_pool);
|
|
31
32
|
}
|
|
32
33
|
|
|
@@ -156,6 +157,14 @@ std::vector<std::pair<int, int>> Tile::compute_treemap()
|
|
|
156
157
|
void Tile::adopt(Tile* other) {
|
|
157
158
|
for (ShapePool* pool : other->shapes_pools) {
|
|
158
159
|
this->shapes_pools.push_back(pool);
|
|
160
|
+
pool->set_owner(this);
|
|
159
161
|
}
|
|
160
162
|
other->shapes_pools.clear();
|
|
161
163
|
}
|
|
164
|
+
|
|
165
|
+
void Tile::unregister_pool(ShapePool* shape_pool) {
|
|
166
|
+
auto it = std::find(this->shapes_pools.begin(), this->shapes_pools.end(), shape_pool);
|
|
167
|
+
if (it != this->shapes_pools.end()) {
|
|
168
|
+
this->shapes_pools.erase(it);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
#include <vector>
|
|
13
13
|
#include <algorithm>
|
|
14
14
|
#include <utility>
|
|
15
|
-
#include <unordered_set>
|
|
16
15
|
#include "VerticalMerger.h"
|
|
17
16
|
|
|
18
17
|
VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *options)
|
|
@@ -36,21 +35,13 @@ ProcessResult* VerticalMerger::process_info() {
|
|
|
36
35
|
|
|
37
36
|
void VerticalMerger::transpose(ProcessResult& result) {
|
|
38
37
|
std::swap(result.width, result.height);
|
|
39
|
-
std::unordered_set<Point*> seen;
|
|
40
38
|
for (auto& polygon : result.polygons) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (seen.insert(p).second) {
|
|
44
|
-
std::swap(p->x, p->y);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
for (Point* p : polygon.outer) {
|
|
49
|
-
process_p(p);
|
|
39
|
+
for (Point& p : polygon.outer) {
|
|
40
|
+
std::swap(p.x, p.y);
|
|
50
41
|
}
|
|
51
42
|
for (auto& sequence : polygon.inner) {
|
|
52
|
-
for (Point
|
|
53
|
-
|
|
43
|
+
for (Point& p : sequence) {
|
|
44
|
+
std::swap(p.x, p.y);
|
|
54
45
|
}
|
|
55
46
|
}
|
|
56
47
|
std::swap(polygon.bounds.min_x, polygon.bounds.min_y);
|
|
@@ -17,6 +17,7 @@ class VerticalMerger : public Merger {
|
|
|
17
17
|
VerticalMerger(int number_of_threads, std::vector<std::string> *options);
|
|
18
18
|
void add_tile(ProcessResult& result) override;
|
|
19
19
|
ProcessResult* process_info() override;
|
|
20
|
+
bool transpose() const override { return true; };
|
|
20
21
|
|
|
21
22
|
private:
|
|
22
23
|
void transpose(ProcessResult& result);
|
|
@@ -14,23 +14,23 @@
|
|
|
14
14
|
#include "LinearReducer.h"
|
|
15
15
|
#include "Reducer.h"
|
|
16
16
|
|
|
17
|
-
LinearReducer::LinearReducer(std::vector<Point
|
|
17
|
+
LinearReducer::LinearReducer(std::vector<Point>& list_of_points)
|
|
18
18
|
: Reducer(list_of_points) {
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
void LinearReducer::reduce() {
|
|
22
22
|
if (points.size() < 2) return;
|
|
23
23
|
|
|
24
|
-
Point
|
|
25
|
-
Point
|
|
24
|
+
Point start_p = points[0];
|
|
25
|
+
Point end_p = points[1];
|
|
26
26
|
auto dir = seq_dir(start_p, end_p);
|
|
27
27
|
|
|
28
28
|
for (size_t i = 2; i < points.size(); ++i) {
|
|
29
|
-
Point
|
|
29
|
+
Point point = points[i];
|
|
30
30
|
auto act_seq = seq_dir(end_p, point);
|
|
31
31
|
if (act_seq == dir) {
|
|
32
|
-
auto it = std::find_if(points.begin(), points.end(), [&](Point
|
|
33
|
-
return p
|
|
32
|
+
auto it = std::find_if(points.begin(), points.end(), [&](const Point& p) { // TODO(ema): optimize...
|
|
33
|
+
return p.x == end_p.x && p.y == end_p.y;
|
|
34
34
|
});
|
|
35
35
|
if (it != points.end()) {
|
|
36
36
|
size_t removed_idx = std::distance(points.begin(), it);
|
|
@@ -44,6 +44,6 @@ void LinearReducer::reduce() {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
std::array<int, 2> LinearReducer::seq_dir(Point
|
|
48
|
-
{ return { b
|
|
47
|
+
std::array<int, 2> LinearReducer::seq_dir(const Point& a, const Point& b)
|
|
48
|
+
{ return { b.x - a.x, b.y - a.y };
|
|
49
49
|
}
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
|
|
15
15
|
class LinearReducer : public Reducer {
|
|
16
16
|
public:
|
|
17
|
-
explicit LinearReducer(std::vector<Point
|
|
17
|
+
explicit LinearReducer(std::vector<Point>& list_of_points);
|
|
18
18
|
void reduce();
|
|
19
19
|
|
|
20
20
|
private:
|
|
21
|
-
std::array<int, 2> seq_dir(Point
|
|
21
|
+
std::array<int, 2> seq_dir(const Point& a, const Point& b);
|
|
22
22
|
};
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
struct Point;
|
|
16
16
|
class Reducer {
|
|
17
17
|
public:
|
|
18
|
-
explicit Reducer(std::vector<Point
|
|
18
|
+
explicit Reducer(std::vector<Point>& list_of_points);
|
|
19
19
|
virtual void reduce();
|
|
20
20
|
protected:
|
|
21
|
-
std::vector<Point
|
|
21
|
+
std::vector<Point> &points;
|
|
22
22
|
};
|
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
#include "UniqReducer.h"
|
|
14
14
|
#include "Reducer.h"
|
|
15
15
|
|
|
16
|
-
UniqReducer::UniqReducer(std::vector<Point
|
|
16
|
+
UniqReducer::UniqReducer(std::vector<Point>& list_of_points) : Reducer(list_of_points) {
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
struct is_near {
|
|
20
|
-
bool operator() (Point
|
|
21
|
-
return first
|
|
20
|
+
bool operator() (const Point& first, const Point& second) const {
|
|
21
|
+
return first.x == second.x && first.y == second.y;
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
#include <vector>
|
|
11
11
|
#include "VisvalingamReducer.h"
|
|
12
12
|
|
|
13
|
-
VisvalingamReducer::VisvalingamReducer(std::vector<Point
|
|
13
|
+
VisvalingamReducer::VisvalingamReducer(std::vector<Point>& list_of_points, float tolerance)
|
|
14
14
|
: Reducer(list_of_points) {
|
|
15
15
|
this->tolerance = tolerance * tolerance;
|
|
16
16
|
}
|
|
@@ -18,11 +18,11 @@ VisvalingamReducer::VisvalingamReducer(std::vector<Point*>& list_of_points, floa
|
|
|
18
18
|
VisvalingamReducer::~VisvalingamReducer() {}
|
|
19
19
|
|
|
20
20
|
void VisvalingamReducer::reduce() {
|
|
21
|
-
std::vector<Point
|
|
21
|
+
std::vector<Point> new_points = this->simplify();
|
|
22
22
|
points.assign(new_points.begin(), new_points.end());
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
std::vector<Point
|
|
25
|
+
std::vector<Point> VisvalingamReducer::simplify() {
|
|
26
26
|
Vertex* vwLine = Vertex::buildLine(points);
|
|
27
27
|
float minArea = this->tolerance;
|
|
28
28
|
for (;;) {
|
|
@@ -17,21 +17,21 @@ struct Point;
|
|
|
17
17
|
|
|
18
18
|
class VisvalingamReducer : public Reducer {
|
|
19
19
|
public:
|
|
20
|
-
VisvalingamReducer(std::vector<Point
|
|
20
|
+
VisvalingamReducer(std::vector<Point>& list_of_points, float tolerance);
|
|
21
21
|
virtual ~VisvalingamReducer();
|
|
22
22
|
void reduce();
|
|
23
|
-
std::vector<Point
|
|
23
|
+
std::vector<Point> simplify();
|
|
24
24
|
|
|
25
25
|
class Triangle {
|
|
26
26
|
public:
|
|
27
|
-
static int area(Point
|
|
28
|
-
return std::abs(((c
|
|
27
|
+
static int area(const Point& a, const Point& b, const Point& c) {
|
|
28
|
+
return std::abs(((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / 2);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
class Vertex {
|
|
33
33
|
const float MAX_AREA = std::numeric_limits<float>::max();
|
|
34
|
-
explicit Vertex(Point
|
|
34
|
+
explicit Vertex(const Point& pt) {
|
|
35
35
|
this->pt = pt;
|
|
36
36
|
this->prev = nullptr;
|
|
37
37
|
this->next = nullptr;
|
|
@@ -40,7 +40,7 @@ class VisvalingamReducer : public Reducer {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
public:
|
|
43
|
-
Point
|
|
43
|
+
Point pt;
|
|
44
44
|
void setNext(Vertex* nextp) { this->next = nextp; }
|
|
45
45
|
void setPrec(Vertex* prev) { this->prev = prev; }
|
|
46
46
|
void updateArea() {
|
|
@@ -54,10 +54,10 @@ class VisvalingamReducer : public Reducer {
|
|
|
54
54
|
Vertex* get_next() { return this->next; }
|
|
55
55
|
bool isLiving() { return this->isLive; }
|
|
56
56
|
|
|
57
|
-
static Vertex* buildLine(std::vector<Point
|
|
57
|
+
static Vertex* buildLine(std::vector<Point>& pts) {
|
|
58
58
|
Vertex* first = nullptr;
|
|
59
59
|
Vertex* prev = nullptr;
|
|
60
|
-
for (Point
|
|
60
|
+
for (const Point& p : pts) {
|
|
61
61
|
Vertex* v = new Vertex(p);
|
|
62
62
|
if (!first) first = v;
|
|
63
63
|
v->setPrec(prev);
|
|
@@ -88,8 +88,8 @@ class VisvalingamReducer : public Reducer {
|
|
|
88
88
|
return result;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
static std::vector<Point
|
|
92
|
-
std::vector<Point
|
|
91
|
+
static std::vector<Point> getCoordinates(Vertex* head) {
|
|
92
|
+
std::vector<Point> coords;
|
|
93
93
|
Vertex* curr = head;
|
|
94
94
|
while (curr) {
|
|
95
95
|
coords.push_back(curr->pt);
|
|
@@ -27,8 +27,6 @@
|
|
|
27
27
|
#include "PolygonFinder/src/polygon/finder/List.h"
|
|
28
28
|
#include "PolygonFinder/src/polygon/finder/Lists.cpp"
|
|
29
29
|
#include "PolygonFinder/src/polygon/finder/Lists.h"
|
|
30
|
-
#include "PolygonFinder/src/polygon/finder/PointPool.h"
|
|
31
|
-
#include "PolygonFinder/src/polygon/finder/PointPool.cpp"
|
|
32
30
|
#include "PolygonFinder/src/polygon/finder/Polygon.h"
|
|
33
31
|
#include "PolygonFinder/src/polygon/bitmaps/Bitmap.h"
|
|
34
32
|
#include "PolygonFinder/src/polygon/bitmaps/Bitmap.cpp"
|
|
@@ -96,6 +94,8 @@
|
|
|
96
94
|
#include "PolygonFinder/src/polygon/finder/concurrent/HorizontalMerger.cpp"
|
|
97
95
|
#include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.h"
|
|
98
96
|
#include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp"
|
|
97
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h"
|
|
98
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp"
|
|
99
99
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.h"
|
|
100
100
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp"
|
|
101
101
|
extern "C" {
|
|
@@ -184,24 +184,25 @@ class To_Ruby<ProcessResult*>
|
|
|
184
184
|
return_me[Symbol("named_sequence")] = pr->named_sequence;
|
|
185
185
|
return_me[Symbol("width")] = pr->width;
|
|
186
186
|
return_me[Symbol("height")] = pr->height;
|
|
187
|
+
return_me[Symbol("versus")] = Symbol(pr->versus == Node::O ? "o" : "a");
|
|
187
188
|
|
|
188
189
|
Rice::Array out;
|
|
189
190
|
for (Polygon& x : pr->polygons)
|
|
190
191
|
{ Rice::Hash poly_hash = Rice::Hash();
|
|
191
|
-
// OUTER: std::vector<Point
|
|
192
|
+
// OUTER: std::vector<Point>
|
|
192
193
|
Rice::Array outer_flat;
|
|
193
|
-
for (Point
|
|
194
|
-
outer_flat.push(p
|
|
195
|
-
outer_flat.push(p
|
|
194
|
+
for (const Point& p : x.outer) {
|
|
195
|
+
outer_flat.push(p.x);
|
|
196
|
+
outer_flat.push(p.y);
|
|
196
197
|
}
|
|
197
198
|
poly_hash[Symbol("outer")] = outer_flat;
|
|
198
|
-
// INNER: std::list<std::vector<Point
|
|
199
|
+
// INNER: std::list<std::vector<Point>>
|
|
199
200
|
Rice::Array inner_collection;
|
|
200
|
-
for (const std::vector<Point
|
|
201
|
+
for (const std::vector<Point>& sequence : x.inner) {
|
|
201
202
|
Rice::Array sequence_flat;
|
|
202
|
-
for (Point
|
|
203
|
-
sequence_flat.push(p
|
|
204
|
-
sequence_flat.push(p
|
|
203
|
+
for (const Point& p : sequence) {
|
|
204
|
+
sequence_flat.push(p.x);
|
|
205
|
+
sequence_flat.push(p.y);
|
|
205
206
|
}
|
|
206
207
|
inner_collection.push(sequence_flat);
|
|
207
208
|
}
|
|
@@ -249,6 +250,7 @@ ProcessResult ruby_result_to_process_result(Rice::Object rb_result) {
|
|
|
249
250
|
Rice::Hash metadata = rb_result.iv_get("@metadata_storage");
|
|
250
251
|
pr.width = detail::From_Ruby<int>().convert(metadata[Symbol("width")].value());
|
|
251
252
|
pr.height = detail::From_Ruby<int>().convert(metadata[Symbol("height")].value());
|
|
253
|
+
pr.versus = metadata[Symbol("versus")] == Symbol("o") ? Node::O : Node::A;
|
|
252
254
|
|
|
253
255
|
Rice::Array rb_polygons = rb_result.iv_get("@polygons_storage");
|
|
254
256
|
for (size_t i = 0; i < rb_polygons.size(); ++i) {
|
|
@@ -268,17 +270,17 @@ ProcessResult ruby_result_to_process_result(Rice::Object rb_result) {
|
|
|
268
270
|
for (size_t j = 0; j < outer_flat.size(); j += 2) {
|
|
269
271
|
int px = detail::From_Ruby<int>().convert(outer_flat[j].value());
|
|
270
272
|
int py = detail::From_Ruby<int>().convert(outer_flat[j+1].value());
|
|
271
|
-
poly.outer.push_back(
|
|
273
|
+
poly.outer.push_back(Point(px, py));
|
|
272
274
|
}
|
|
273
275
|
// INNER
|
|
274
276
|
Rice::Array inner_collection = (Rice::Array)rb_poly[Symbol("inner")];
|
|
275
277
|
for (size_t j = 0; j < inner_collection.size(); ++j) {
|
|
276
278
|
Rice::Array sequence_flat = (Rice::Array)inner_collection[j];
|
|
277
|
-
std::vector<Point
|
|
279
|
+
std::vector<Point> hole;
|
|
278
280
|
for (size_t k = 0; k < sequence_flat.size(); k += 2) {
|
|
279
281
|
int px = detail::From_Ruby<int>().convert(sequence_flat[k].value());
|
|
280
282
|
int py = detail::From_Ruby<int>().convert(sequence_flat[k+1].value());
|
|
281
|
-
hole.push_back(
|
|
283
|
+
hole.push_back(Point(px, py));
|
|
282
284
|
}
|
|
283
285
|
poly.inner.push_back(hole);
|
|
284
286
|
}
|
|
@@ -290,6 +292,36 @@ ProcessResult ruby_result_to_process_result(Rice::Object rb_result) {
|
|
|
290
292
|
|
|
291
293
|
} // namespace Rice::detail
|
|
292
294
|
|
|
295
|
+
struct OfstreamWrapper {
|
|
296
|
+
std::string path;
|
|
297
|
+
std::ofstream stream;
|
|
298
|
+
OfstreamWrapper(std::string p) : path(p), stream(p, std::ios::out) {}
|
|
299
|
+
void close() { stream.close(); }
|
|
300
|
+
bool closed() { return !stream.is_open(); }
|
|
301
|
+
void rewind() { /* noop */ }
|
|
302
|
+
std::string read() {
|
|
303
|
+
stream.flush();
|
|
304
|
+
std::ifstream in(path);
|
|
305
|
+
return std::string((std::istreambuf_iterator<char>(in)),
|
|
306
|
+
std::istreambuf_iterator<char>());
|
|
307
|
+
}
|
|
308
|
+
std::ofstream& get_stream() { return stream; }
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
StreamingMerger* create_streaming_merger(Object self,
|
|
312
|
+
int number_of_threads,
|
|
313
|
+
std::vector<std::string>* options,
|
|
314
|
+
Object stream_obj,
|
|
315
|
+
int total_width,
|
|
316
|
+
int total_height) {
|
|
317
|
+
OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
|
|
318
|
+
return new StreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
OfstreamWrapper* create_ofstream(Object self, std::string path) {
|
|
322
|
+
return new OfstreamWrapper(path);
|
|
323
|
+
}
|
|
324
|
+
|
|
293
325
|
extern "C"
|
|
294
326
|
void Init_cpp_polygon_finder() {
|
|
295
327
|
#ifdef HAVE_TCMALLOC
|
|
@@ -384,9 +416,27 @@ void Init_cpp_polygon_finder() {
|
|
|
384
416
|
define_class<HorizontalMerger, Merger>("CPPHorizontalMerger")
|
|
385
417
|
.define_constructor(Constructor<HorizontalMerger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Arg("yield_gvl") = true);
|
|
386
418
|
|
|
387
|
-
|
|
419
|
+
Data_Type<VerticalMerger> rb_cVerticalMerger =
|
|
388
420
|
define_class<VerticalMerger, Merger>("CPPVerticalMerger")
|
|
389
|
-
.define_constructor(Constructor<VerticalMerger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Arg("yield_gvl") = true)
|
|
421
|
+
.define_constructor(Constructor<VerticalMerger, int, std::vector<std::string>*>(), Arg("number_of_threads"), Arg("options") = nullptr, Arg("yield_gvl") = true)
|
|
422
|
+
.define_method("add_tile", [](VerticalMerger& self, Object rb_result) {
|
|
423
|
+
ProcessResult pr = Rice::detail::ruby_result_to_process_result(rb_result);
|
|
424
|
+
self.add_tile(pr);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
Data_Type<OfstreamWrapper> rb_cstd_ofstream = define_class<OfstreamWrapper>("CPPOfstream");
|
|
428
|
+
rb_cstd_ofstream.define_singleton_method("new", &create_ofstream);
|
|
429
|
+
rb_cstd_ofstream.define_method("close", [](OfstreamWrapper& self) { self.close(); });
|
|
430
|
+
rb_cstd_ofstream.define_method("closed?", [](OfstreamWrapper& self) { return self.closed(); });
|
|
431
|
+
rb_cstd_ofstream.define_method("rewind", [](OfstreamWrapper& self) { self.rewind(); });
|
|
432
|
+
rb_cstd_ofstream.define_method("read", [](OfstreamWrapper& self) { return self.read(); });
|
|
433
|
+
|
|
434
|
+
Data_Type<StreamingMerger> rb_cstreaming_merger = define_class<StreamingMerger, VerticalMerger>("CPPStreamingMerger");
|
|
435
|
+
rb_cstreaming_merger.define_method("add_tile", [](StreamingMerger& self, Object rb_result, bool flush) {
|
|
436
|
+
ProcessResult pr = Rice::detail::ruby_result_to_process_result(rb_result);
|
|
437
|
+
self.add_tile(pr, flush);
|
|
438
|
+
});
|
|
439
|
+
rb_cstreaming_merger.define_singleton_method("new", &create_streaming_merger);
|
|
390
440
|
|
|
391
441
|
Module mContrek = define_module("Contrek");
|
|
392
442
|
Module mCpp = define_module_under(mContrek, "Cpp");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Contrek
|
|
2
4
|
module Bitmaps
|
|
3
5
|
class ChunkyBitmap < Bitmap
|
|
@@ -87,6 +89,17 @@ module Contrek
|
|
|
87
89
|
puts
|
|
88
90
|
end
|
|
89
91
|
|
|
92
|
+
def transpose!
|
|
93
|
+
transposed = ""
|
|
94
|
+
w.times do |x|
|
|
95
|
+
h.times do |y|
|
|
96
|
+
transposed += value_at(x, y)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
@raw = transposed
|
|
100
|
+
@module = h
|
|
101
|
+
end
|
|
102
|
+
|
|
90
103
|
private
|
|
91
104
|
|
|
92
105
|
def next_color(color)
|