contrek 1.3.1 → 1.3.2
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/CHANGELOG.md +3 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +23 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/Node.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/NodeCluster.h +4 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +6 -6
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +16 -10
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +16 -15
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +3 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +1 -9
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h +81 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.cpp +9 -28
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/InnerPolyline.h +10 -11
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +5 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +4 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +7 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.cpp +0 -14
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Sequence.h +0 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Shape.cpp +5 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp +31 -26
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/ShapePool.h +7 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp +12 -31
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +10 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SubPool.h +47 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h +43 -0
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +2 -1
- data/lib/contrek/finder/concurrent/cluster.rb +6 -5
- data/lib/contrek/finder/concurrent/cursor.rb +2 -1
- data/lib/contrek/finder/concurrent/finder.rb +1 -12
- data/lib/contrek/finder/concurrent/inner_polyline.rb +8 -25
- data/lib/contrek/finder/concurrent/sequence.rb +1 -17
- data/lib/contrek/version.rb +1 -1
- metadata +8 -5
|
@@ -12,19 +12,18 @@
|
|
|
12
12
|
#include <optional>
|
|
13
13
|
#include "Sequence.h"
|
|
14
14
|
|
|
15
|
+
class ShapePool;
|
|
15
16
|
class InnerPolyline {
|
|
16
17
|
public:
|
|
17
|
-
explicit InnerPolyline(std::vector<Point> raw_coordinates, Shape* shape);
|
|
18
|
-
explicit InnerPolyline(Sequence* sequence);
|
|
19
|
-
std::vector<Point>& raw();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
explicit InnerPolyline(ShapePool* shape_pool, std::vector<Point> raw_coordinates, Shape* shape);
|
|
19
|
+
explicit InnerPolyline(ShapePool* shape_pool, Sequence* sequence);
|
|
20
|
+
std::vector<Point>& raw() { return this->raw_coordinates_; }
|
|
21
|
+
Bounds& vertical_bounds() { return this->vertical_bounds_; }
|
|
22
|
+
Shape* shape = nullptr;
|
|
23
|
+
ShapePool* shape_pool = nullptr;
|
|
24
|
+
void compute_vertical_bounds();
|
|
25
|
+
|
|
24
26
|
private:
|
|
25
27
|
std::vector<Point> raw_coordinates_;
|
|
26
|
-
|
|
27
|
-
Shape* shape_;
|
|
28
|
-
Bounds& raw_vertical_bounds();
|
|
29
|
-
Bounds vertical_bounds_;
|
|
28
|
+
Bounds vertical_bounds_{0, 0};
|
|
30
29
|
};
|
|
@@ -35,6 +35,9 @@ class Part : public Queueable<Point> {
|
|
|
35
35
|
bool transmutation_skip = false;
|
|
36
36
|
bool dead_end = false;
|
|
37
37
|
bool mirror = false;
|
|
38
|
+
private:
|
|
39
|
+
bool touched_ = false;
|
|
40
|
+
public:
|
|
38
41
|
Part* next = nullptr;
|
|
39
42
|
Part* next_seam = nullptr;
|
|
40
43
|
Part* prev = nullptr;
|
|
@@ -45,8 +48,8 @@ class Part : public Queueable<Point> {
|
|
|
45
48
|
void add_position(const Point& point);
|
|
46
49
|
Types type;
|
|
47
50
|
bool innerable();
|
|
48
|
-
|
|
49
|
-
|
|
51
|
+
bool touched() const { return touched_; }
|
|
52
|
+
int versus() const { return versus_; }
|
|
50
53
|
void touch();
|
|
51
54
|
void orient();
|
|
52
55
|
std::string inspect();
|
|
@@ -57,6 +60,5 @@ class Part : public Queueable<Point> {
|
|
|
57
60
|
|
|
58
61
|
private:
|
|
59
62
|
int versus_ = 0;
|
|
60
|
-
bool touched_ = false;
|
|
61
63
|
Polyline* polyline_;
|
|
62
64
|
};
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
#include "Tile.h"
|
|
18
18
|
#include "Shape.h"
|
|
19
19
|
|
|
20
|
-
Polyline::Polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds)
|
|
21
|
-
:
|
|
22
|
-
|
|
20
|
+
Polyline::Polyline(ShapePool* shape_pool, Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds)
|
|
21
|
+
: tile(tile),
|
|
22
|
+
shape_pool(shape_pool),
|
|
23
|
+
raw_(std::move(polygon))
|
|
23
24
|
{ if (bounds.has_value()) {
|
|
24
25
|
min_x = bounds->min_x;
|
|
25
26
|
max_x_ = bounds->max_x;
|
|
@@ -22,13 +22,14 @@
|
|
|
22
22
|
|
|
23
23
|
class Tile;
|
|
24
24
|
class Shape;
|
|
25
|
+
class ShapePool;
|
|
25
26
|
class Point;
|
|
26
27
|
class InnerPolyline;
|
|
27
28
|
|
|
28
29
|
class Polyline : public Partitionable {
|
|
29
30
|
public:
|
|
30
31
|
using Partitionable::Partitionable;
|
|
31
|
-
Polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt);
|
|
32
|
+
Polyline(ShapePool* shape_pool, Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt);
|
|
32
33
|
enum Flags : uint32_t {
|
|
33
34
|
TRACKED_OUTER = 1 << 0
|
|
34
35
|
};
|
|
@@ -39,12 +40,13 @@ class Polyline : public Partitionable {
|
|
|
39
40
|
void precalc();
|
|
40
41
|
int width();
|
|
41
42
|
Tile *tile = nullptr;
|
|
43
|
+
ShapePool* shape_pool = nullptr;
|
|
42
44
|
Shape* shape = nullptr;
|
|
43
45
|
const std::vector<Point>& raw() const { return raw_; }
|
|
44
46
|
const std::vector<Part*>& parts() const { return parts_; }
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
int max_y() const { return max_y_; }
|
|
48
|
+
int min_y() const { return min_y_; }
|
|
49
|
+
int max_x() const { return max_x_; }
|
|
48
50
|
void clear();
|
|
49
51
|
bool is_empty();
|
|
50
52
|
bool any_ancients = false;
|
|
@@ -60,6 +62,6 @@ class Polyline : public Partitionable {
|
|
|
60
62
|
int min_x, max_x_, min_y_, max_y_;
|
|
61
63
|
void find_boundary();
|
|
62
64
|
uint32_t flags_ = 0;
|
|
63
|
-
std::string named_;
|
|
64
65
|
int name;
|
|
66
|
+
std::string named_;
|
|
65
67
|
};
|
|
@@ -32,7 +32,7 @@ Position::Position(EndPoint* end_point)
|
|
|
32
32
|
{ this->end_point_ = end_point;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
void Position::before_rem(Queueable<Point>*
|
|
35
|
+
void Position::before_rem(Queueable<Point>*) {
|
|
36
36
|
/*if (this->end_point_ != nullptr)
|
|
37
37
|
{ if (q->listable())
|
|
38
38
|
{ auto& v = this->end_point_->queues();
|
|
@@ -26,8 +26,8 @@ class QNode {
|
|
|
26
26
|
Queueable<T>* owner {nullptr};
|
|
27
27
|
explicit QNode(const T& value) : payload(value) {}
|
|
28
28
|
virtual ~QNode() = default;
|
|
29
|
-
virtual void before_rem(Queueable<T>*
|
|
30
|
-
virtual void after_add(Queueable<T>*
|
|
29
|
+
virtual void before_rem(Queueable<T>*) {}
|
|
30
|
+
virtual void after_add(Queueable<T>*) {}
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
|
|
@@ -34,17 +34,3 @@ bool Sequence::is_not_vertical()
|
|
|
34
34
|
}
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
void Sequence::compute_vertical_bounds()
|
|
39
|
-
{ const auto& cache = get_vector_cache();
|
|
40
|
-
if (!cache.empty()) {
|
|
41
|
-
int min_y = cache[0].y;
|
|
42
|
-
int max_y = cache[0].y;
|
|
43
|
-
for (const auto& pos : cache) {
|
|
44
|
-
if (pos.y < min_y) min_y = pos.y;
|
|
45
|
-
if (pos.y > max_y) max_y = pos.y;
|
|
46
|
-
}
|
|
47
|
-
vertical_bounds.min = min_y;
|
|
48
|
-
vertical_bounds.max = max_y;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -22,8 +22,6 @@ class Sequence : public Queueable<Point>{
|
|
|
22
22
|
std::string toString();
|
|
23
23
|
bool is_not_vertical();
|
|
24
24
|
Shape* shape = nullptr;
|
|
25
|
-
Bounds vertical_bounds;
|
|
26
|
-
void compute_vertical_bounds();
|
|
27
25
|
const std::vector<Point>& get_vector_cache() {
|
|
28
26
|
if (vector_cache.empty() && this->size > 0) {
|
|
29
27
|
vector_cache = this->to_vector();
|
|
@@ -17,17 +17,17 @@
|
|
|
17
17
|
Shape::Shape(ShapePool* shape_pool, Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines)
|
|
18
18
|
: outer_polyline(outer_polyline),
|
|
19
19
|
inner_polylines(inner_polylines),
|
|
20
|
-
shape_pool_(shape_pool) {
|
|
21
|
-
for (InnerPolyline* ip : inner_polylines) {
|
|
22
|
-
ip->assigned_shape = this;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
20
|
+
shape_pool_(shape_pool) {}
|
|
25
21
|
|
|
26
22
|
void Shape::clear_inner() {
|
|
27
23
|
inner_polylines.clear();
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
void Shape::detach_from_pool() {
|
|
27
|
+
this->outer_polyline->shape_pool->detach_polyline();
|
|
28
|
+
for (InnerPolyline* inner_polyline : this->inner_polylines) {
|
|
29
|
+
inner_polyline->shape_pool->detach_inner_polyline();
|
|
30
|
+
}
|
|
31
31
|
shape_pool_->detach_shape();
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -9,49 +9,54 @@
|
|
|
9
9
|
|
|
10
10
|
#include <vector>
|
|
11
11
|
#include <utility>
|
|
12
|
+
#include <iostream>
|
|
12
13
|
#include "Shape.h"
|
|
13
14
|
#include "ShapePool.h"
|
|
14
15
|
#include "Tile.h"
|
|
15
16
|
|
|
16
17
|
Shape* ShapePool::acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines) {
|
|
17
|
-
|
|
18
|
-
Shape* shape = &shapes_storage.back();
|
|
19
|
-
this->shapes_count++;
|
|
18
|
+
Shape* shape = this->shapes.acquire(this, outer_polyline, inner_polylines);
|
|
20
19
|
return shape;
|
|
21
20
|
}
|
|
22
21
|
|
|
22
|
+
Polyline* ShapePool::acquire_polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds = std::nullopt) {
|
|
23
|
+
return this->polylines.acquire(this, tile, std::move(polygon), bounds);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
InnerPolyline* ShapePool::acquire_inner_polyline(std::vector<Point> coords, Shape* shape) {
|
|
27
|
+
return this->inner_polylines.acquire(this, std::move(coords), shape);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
InnerPolyline* ShapePool::acquire_inner_polyline(Sequence* seq) {
|
|
31
|
+
return this->inner_polylines.acquire(this, seq);
|
|
32
|
+
}
|
|
33
|
+
|
|
23
34
|
void ShapePool::set_owner(Tile* tile) {
|
|
24
35
|
this->owner_tile_ = tile;
|
|
25
36
|
}
|
|
26
37
|
|
|
27
38
|
void ShapePool::detach_shape() {
|
|
28
|
-
this->
|
|
29
|
-
|
|
30
|
-
this->owner_tile_->unregister_pool(this);
|
|
31
|
-
delete this;
|
|
32
|
-
}
|
|
39
|
+
this->shapes.decrement();
|
|
40
|
+
this->check_destruction();
|
|
33
41
|
}
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
return ip;
|
|
43
|
+
void ShapePool::detach_polyline() {
|
|
44
|
+
this->polylines.decrement();
|
|
45
|
+
this->check_destruction();
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return ip;
|
|
48
|
+
void ShapePool::detach_inner_polyline() {
|
|
49
|
+
this->inner_polylines.decrement();
|
|
50
|
+
this->check_destruction();
|
|
45
51
|
}
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return p;
|
|
53
|
+
void ShapePool::check_destruction() {
|
|
54
|
+
if (this->shapes.is_released() &&
|
|
55
|
+
this->polylines.is_released() &&
|
|
56
|
+
this->inner_polylines.is_released()) {
|
|
57
|
+
if (this->owner_tile_) {
|
|
58
|
+
this->owner_tile_->unregister_pool(this);
|
|
59
|
+
}
|
|
60
|
+
delete this;
|
|
61
|
+
}
|
|
57
62
|
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include "Shape.h"
|
|
14
14
|
#include "../RectBounds.h"
|
|
15
15
|
#include "Polyline.h"
|
|
16
|
+
#include "SubPool.h"
|
|
16
17
|
|
|
17
18
|
class Shape;
|
|
18
19
|
class Tile;
|
|
@@ -20,19 +21,18 @@ class Polyline;
|
|
|
20
21
|
class InnerPolyline;
|
|
21
22
|
class ShapePool {
|
|
22
23
|
private:
|
|
23
|
-
int shapes_count = 0;
|
|
24
24
|
Tile* owner_tile_ = nullptr;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
std::deque<Polyline> polylines_storage;
|
|
29
|
-
|
|
25
|
+
SubPool<Shape> shapes{this};
|
|
26
|
+
SubPool<Polyline> polylines{this};
|
|
27
|
+
SubPool<InnerPolyline> inner_polylines{this};
|
|
30
28
|
public:
|
|
31
29
|
Shape* acquire_shape(Polyline* outer_polyline, const std::vector<InnerPolyline*>& inner_polylines);
|
|
32
30
|
InnerPolyline* acquire_inner_polyline(std::vector<Point> coords, Shape* s);
|
|
33
31
|
InnerPolyline* acquire_inner_polyline(Sequence* seq);
|
|
34
|
-
Sequence* acquire_sequence();
|
|
35
32
|
Polyline* acquire_polyline(Tile* tile, std::vector<Point> polygon, const std::optional<RectBounds>& bounds);
|
|
36
33
|
void set_owner(Tile* tile);
|
|
37
34
|
void detach_shape();
|
|
35
|
+
void detach_polyline();
|
|
36
|
+
void detach_inner_polyline();
|
|
37
|
+
void check_destruction();
|
|
38
38
|
};
|
|
@@ -38,7 +38,7 @@ void StreamingMerger::add_tile(ProcessResult& result, bool flush)
|
|
|
38
38
|
|
|
39
39
|
ProcessResult* StreamingMerger::process_info() {
|
|
40
40
|
ProcessResult *pr = VerticalMerger::process_info();
|
|
41
|
-
pr->groups =
|
|
41
|
+
pr->groups = this->moved;
|
|
42
42
|
return(pr);
|
|
43
43
|
}
|
|
44
44
|
|
|
@@ -65,53 +65,34 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
|
|
|
65
65
|
|
|
66
66
|
void StreamingMerger::stream_raw_polygon(const Shape* shape) {
|
|
67
67
|
std::ostringstream outer_oss;
|
|
68
|
+
|
|
69
|
+
this->write_outer_polygon_start();
|
|
68
70
|
const std::vector<Point>& points = shape->outer_polyline->raw();
|
|
69
71
|
for (size_t i = 0; i < points.size(); ++i) {
|
|
70
|
-
|
|
71
|
-
if (i < points.size() - 1)
|
|
72
|
+
*stream << points[i].y << "," << points[i].x;
|
|
73
|
+
if (i < points.size() - 1) *stream << " ";
|
|
72
74
|
}
|
|
73
|
-
|
|
75
|
+
this->write_outer_polygon_end();
|
|
74
76
|
|
|
75
77
|
for (const auto& inner_polyline : shape->inner_polylines) {
|
|
76
|
-
|
|
78
|
+
this->write_inner_polygon_start();
|
|
77
79
|
const std::vector<Point>& inner_points = inner_polyline->raw();
|
|
78
80
|
for (size_t i = 0; i < inner_points.size(); ++i) {
|
|
79
|
-
|
|
80
|
-
if (i < inner_points.size() - 1)
|
|
81
|
+
*stream << inner_points[i].y << "," << inner_points[i].x;
|
|
82
|
+
if (i < inner_points.size() - 1) *stream << " ";
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
this->write_inner_polygon_end();
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
void StreamingMerger::ensure_header() {
|
|
87
89
|
if (stream && stream->tellp() == 0) {
|
|
88
|
-
|
|
90
|
+
this->write_header();
|
|
89
91
|
}
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
void StreamingMerger::ensure_footer() {
|
|
93
95
|
if (stream) {
|
|
94
|
-
|
|
96
|
+
this->write_footer();
|
|
95
97
|
}
|
|
96
98
|
}
|
|
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
|
-
}
|
|
@@ -16,20 +16,22 @@
|
|
|
16
16
|
#include <vector>
|
|
17
17
|
|
|
18
18
|
class StreamingMerger : public VerticalMerger {
|
|
19
|
-
|
|
19
|
+
protected:
|
|
20
20
|
std::ofstream* stream;
|
|
21
21
|
int total_width;
|
|
22
22
|
int total_height;
|
|
23
23
|
int moved = 0;
|
|
24
|
+
|
|
25
|
+
void stream_polygons(Tile* tile, bool flush = false);
|
|
26
|
+
virtual void stream_raw_polygon(const Shape* shape);
|
|
27
|
+
virtual void write_header() = 0;
|
|
28
|
+
virtual void write_footer() = 0;
|
|
29
|
+
virtual void write_outer_polygon_start() = 0;
|
|
30
|
+
virtual void write_outer_polygon_end() = 0;
|
|
31
|
+
virtual void write_inner_polygon_start() = 0;
|
|
32
|
+
virtual void write_inner_polygon_end() = 0;
|
|
24
33
|
void ensure_header();
|
|
25
34
|
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
35
|
|
|
34
36
|
public:
|
|
35
37
|
StreamingMerger(int number_of_threads,
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SubPool.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 <deque>
|
|
12
|
+
#include <memory>
|
|
13
|
+
#include <utility>
|
|
14
|
+
|
|
15
|
+
class ShapePool;
|
|
16
|
+
|
|
17
|
+
template <typename T>
|
|
18
|
+
class SubPool {
|
|
19
|
+
private:
|
|
20
|
+
std::unique_ptr<std::deque<T>> storage_;
|
|
21
|
+
uint32_t active_count_ = 0;
|
|
22
|
+
ShapePool* macro_pool_ = nullptr;
|
|
23
|
+
|
|
24
|
+
public:
|
|
25
|
+
explicit SubPool(ShapePool* macro_pool) : macro_pool_(macro_pool) {
|
|
26
|
+
storage_ = std::make_unique<std::deque<T>>();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
template <typename... Args>
|
|
30
|
+
T* acquire(Args&&... args) {
|
|
31
|
+
storage_->emplace_back(std::forward<Args>(args)...);
|
|
32
|
+
T* ptr = &storage_->back();
|
|
33
|
+
active_count_++;
|
|
34
|
+
return ptr;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
void decrement() {
|
|
38
|
+
active_count_--;
|
|
39
|
+
if (active_count_ == 0 && storage_ != nullptr) {
|
|
40
|
+
storage_.reset();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
bool is_released() const {
|
|
45
|
+
return storage_ == nullptr;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SvgStreamingMerger.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 <string>
|
|
12
|
+
#include "StreamingMerger.h"
|
|
13
|
+
|
|
14
|
+
class SvgStreamingMerger : public StreamingMerger {
|
|
15
|
+
private:
|
|
16
|
+
std::string svg_css() {
|
|
17
|
+
return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected:
|
|
21
|
+
void write_header() override {
|
|
22
|
+
*stream << "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" << total_width
|
|
23
|
+
<< "\" height=\"" << total_height << "\"><style>" << svg_css() << "</style>";
|
|
24
|
+
}
|
|
25
|
+
void write_footer() override {
|
|
26
|
+
*stream << "</svg>";
|
|
27
|
+
}
|
|
28
|
+
void write_outer_polygon_start() override {
|
|
29
|
+
*stream << "<polygon points=\"";
|
|
30
|
+
}
|
|
31
|
+
void write_outer_polygon_end() override {
|
|
32
|
+
*stream << "\" class=\"out\"/>";
|
|
33
|
+
}
|
|
34
|
+
void write_inner_polygon_start() override {
|
|
35
|
+
*stream << "<polygon points=\"";
|
|
36
|
+
}
|
|
37
|
+
void write_inner_polygon_end() override {
|
|
38
|
+
*stream << "\" class=\"in\"/>";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public:
|
|
42
|
+
using StreamingMerger::StreamingMerger;
|
|
43
|
+
};
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
#include "PolygonFinder/src/polygon/finder/concurrent/VerticalMerger.cpp"
|
|
97
97
|
#include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h"
|
|
98
98
|
#include "PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.cpp"
|
|
99
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/SvgStreamingMerger.h"
|
|
99
100
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.h"
|
|
100
101
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp"
|
|
101
102
|
extern "C" {
|
|
@@ -315,7 +316,7 @@ StreamingMerger* create_streaming_merger(Object self,
|
|
|
315
316
|
int total_width,
|
|
316
317
|
int total_height) {
|
|
317
318
|
OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
|
|
318
|
-
return new
|
|
319
|
+
return new SvgStreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
|
|
319
320
|
}
|
|
320
321
|
|
|
321
322
|
OfstreamWrapper* create_ofstream(Object self, std::string path) {
|
|
@@ -5,7 +5,7 @@ module Contrek
|
|
|
5
5
|
class Cluster
|
|
6
6
|
attr_reader :tiles, :hub, :finder
|
|
7
7
|
|
|
8
|
-
def initialize(finder:, height
|
|
8
|
+
def initialize(finder:, height:)
|
|
9
9
|
@finder = finder
|
|
10
10
|
@tiles = []
|
|
11
11
|
@hub = Hub.new(height:)
|
|
@@ -57,23 +57,24 @@ module Contrek
|
|
|
57
57
|
new_inners = shape.inner_polylines
|
|
58
58
|
new_inner_polylines = []
|
|
59
59
|
tot_inner += Benchmark.measure do
|
|
60
|
-
new_inner_polylines = cursor.join_inners!(
|
|
60
|
+
new_inner_polylines = cursor.join_inners!(treemap)
|
|
61
61
|
new_inners += new_inner_polylines
|
|
62
62
|
if treemap
|
|
63
63
|
new_inner_polylines.each do |inner_polyline|
|
|
64
|
-
inner_polyline.
|
|
64
|
+
inner_polyline.compute_vertical_bounds!
|
|
65
65
|
all_new_inner_polylines += new_inner_polylines
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
new_inners += cursor.orphan_inners
|
|
69
69
|
end.real
|
|
70
|
+
shape.clear_inner!
|
|
70
71
|
|
|
71
72
|
polyline = Polyline.new(tile: tile, polygon: new_outer.to_a)
|
|
72
73
|
inserting_new_shape = Shape.init_by(polyline, new_inners)
|
|
73
74
|
new_shapes << inserting_new_shape
|
|
74
75
|
polyline.shape = inserting_new_shape
|
|
75
76
|
|
|
76
|
-
new_inner_polylines.each { |inner_polyline| inner_polyline.
|
|
77
|
+
new_inner_polylines.each { |inner_polyline| inner_polyline.shape = inserting_new_shape }
|
|
77
78
|
|
|
78
79
|
if treemap
|
|
79
80
|
cursor.shapes_sequence.each do |merged_shape|
|
|
@@ -115,7 +116,7 @@ module Contrek
|
|
|
115
116
|
private
|
|
116
117
|
|
|
117
118
|
def assign_ancestry(shape, inner_polyline)
|
|
118
|
-
shape.set_parent_shape(inner_polyline.
|
|
119
|
+
shape.set_parent_shape(inner_polyline.shape)
|
|
119
120
|
shape.parent_inner_polyline = inner_polyline
|
|
120
121
|
shape.fixed = true
|
|
121
122
|
end
|
|
@@ -40,7 +40,7 @@ module Contrek
|
|
|
40
40
|
outer_joined_polyline
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def join_inners!(
|
|
43
|
+
def join_inners!(treemap)
|
|
44
44
|
return_inner_polylines = []
|
|
45
45
|
shape_index = 0
|
|
46
46
|
|
|
@@ -174,6 +174,7 @@ module Contrek
|
|
|
174
174
|
if !dest_part.polyline.on?(Polyline::TRACKED_OUTER)
|
|
175
175
|
@shapes_sequence << shape
|
|
176
176
|
@orphan_inners += shape.inner_polylines
|
|
177
|
+
shape.clear_inner!
|
|
177
178
|
end
|
|
178
179
|
dest_part.polyline.turn_on(Polyline::TRACKED_OUTER)
|
|
179
180
|
if !dest_part.touched
|
|
@@ -114,18 +114,7 @@ module Contrek
|
|
|
114
114
|
return
|
|
115
115
|
end
|
|
116
116
|
if (twin_tile = arriving_tiles.find { |b| (b.start_x == (tile.end_x - 1)) || ((b.end_x - 1) == tile.start_x) })
|
|
117
|
-
|
|
118
|
-
if twin_tile.start_x == (tile.end_x - 1)
|
|
119
|
-
start_x = tile.start_x
|
|
120
|
-
end_x = twin_tile.end_x
|
|
121
|
-
else
|
|
122
|
-
start_x = twin_tile.start_x
|
|
123
|
-
end_x = tile.end_x
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
# puts "start = #{start_x} end = #{end_x}"
|
|
127
|
-
|
|
128
|
-
cluster = Cluster.new(finder: self, height: height, start_x:, end_x:)
|
|
117
|
+
cluster = Cluster.new(finder: self, height: height)
|
|
129
118
|
if twin_tile.start_x == (tile.end_x - 1)
|
|
130
119
|
cluster.add(tile)
|
|
131
120
|
cluster.add(twin_tile)
|
|
@@ -3,37 +3,20 @@
|
|
|
3
3
|
module Contrek
|
|
4
4
|
module Concurrent
|
|
5
5
|
class InnerPolyline
|
|
6
|
-
attr_reader :
|
|
6
|
+
attr_reader :raw, :vertical_bounds
|
|
7
|
+
attr_accessor :shape
|
|
7
8
|
|
|
8
9
|
def initialize(shape: nil, raw_coordinates: [], sequence: nil)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def raw
|
|
15
|
-
@sequence ? @sequence.to_a : @raw
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def vertical_bounds
|
|
19
|
-
if @sequence
|
|
20
|
-
@sequence.vertical_bounds
|
|
10
|
+
if sequence
|
|
11
|
+
@shape = sequence.shape
|
|
12
|
+
@raw = sequence.to_a
|
|
21
13
|
else
|
|
22
|
-
|
|
14
|
+
@shape = shape
|
|
15
|
+
@raw = raw_coordinates
|
|
23
16
|
end
|
|
24
17
|
end
|
|
25
18
|
|
|
26
|
-
def
|
|
27
|
-
if @sequence
|
|
28
|
-
@sequence.shape
|
|
29
|
-
else
|
|
30
|
-
@shape
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
def raw_vertical_bounds
|
|
19
|
+
def compute_vertical_bounds!
|
|
37
20
|
@vertical_bounds ||= begin
|
|
38
21
|
min_y = Float::INFINITY
|
|
39
22
|
max_y = 0
|