contrek 1.3.1 → 1.3.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/CHANGELOG.md +6 -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 +80 -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 +7 -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 +14 -37
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/StreamingMerger.h +11 -12
- 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 +56 -0
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +18 -3
- data/lib/contrek/cpp/cpp_geo_json_concurrent_streaming_merger.rb +11 -0
- data/lib/contrek/cpp/{cpp_concurrent_streaming_merger.rb → cpp_svg_concurrent_streaming_merger.rb} +1 -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/geo_json_streaming_merger.rb +46 -0
- data/lib/contrek/finder/concurrent/inner_polyline.rb +8 -25
- data/lib/contrek/finder/concurrent/sequence.rb +1 -17
- data/lib/contrek/finder/concurrent/streaming_merger.rb +5 -27
- data/lib/contrek/finder/concurrent/svg_streaming_merger.rb +35 -0
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +4 -1
- metadata +12 -6
|
@@ -11,36 +11,18 @@
|
|
|
11
11
|
#include <vector>
|
|
12
12
|
#include "InnerPolyline.h"
|
|
13
13
|
|
|
14
|
-
InnerPolyline::InnerPolyline(std::vector<Point> raw_coordinates, Shape* shape)
|
|
15
|
-
:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
InnerPolyline::InnerPolyline(ShapePool* shape_pool, std::vector<Point> raw_coordinates, Shape* shape)
|
|
15
|
+
: shape(shape),
|
|
16
|
+
shape_pool(shape_pool),
|
|
17
|
+
raw_coordinates_(std::move(raw_coordinates)) {}
|
|
18
|
+
InnerPolyline::InnerPolyline(ShapePool* shape_pool, Sequence* sequence)
|
|
19
|
+
: shape_pool(shape_pool) {
|
|
19
20
|
this->raw_coordinates_ = sequence->to_vector();
|
|
21
|
+
this->shape = sequence->shape;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
Bounds& InnerPolyline::vertical_bounds() {
|
|
27
|
-
if (sequence_ != nullptr) {
|
|
28
|
-
return(sequence_->vertical_bounds);
|
|
29
|
-
} else {
|
|
30
|
-
return(this->raw_vertical_bounds());
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
Shape* InnerPolyline::shape() {
|
|
35
|
-
if (sequence_ != nullptr) {
|
|
36
|
-
return(sequence_->shape);
|
|
37
|
-
} else {
|
|
38
|
-
return(this->shape_ ? this->shape_ : this->assigned_shape);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
Bounds& InnerPolyline::raw_vertical_bounds() {
|
|
43
|
-
if (!raw_coordinates_.empty()) {
|
|
24
|
+
void InnerPolyline::compute_vertical_bounds()
|
|
25
|
+
{ if (!raw_coordinates_.empty()) {
|
|
44
26
|
int min_y = raw_coordinates_[0].y;
|
|
45
27
|
int max_y = raw_coordinates_[0].y;
|
|
46
28
|
for (const auto& pos : raw_coordinates_) {
|
|
@@ -50,5 +32,4 @@ Bounds& InnerPolyline::raw_vertical_bounds() {
|
|
|
50
32
|
vertical_bounds_.min = min_y;
|
|
51
33
|
vertical_bounds_.max = max_y;
|
|
52
34
|
}
|
|
53
|
-
return(vertical_bounds_);
|
|
54
35
|
}
|
|
@@ -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,11 @@ class Part : public Queueable<Point> {
|
|
|
35
35
|
bool transmutation_skip = false;
|
|
36
36
|
bool dead_end = false;
|
|
37
37
|
bool mirror = false;
|
|
38
|
+
|
|
39
|
+
private:
|
|
40
|
+
bool touched_ = false;
|
|
41
|
+
|
|
42
|
+
public:
|
|
38
43
|
Part* next = nullptr;
|
|
39
44
|
Part* next_seam = nullptr;
|
|
40
45
|
Part* prev = nullptr;
|
|
@@ -45,8 +50,8 @@ class Part : public Queueable<Point> {
|
|
|
45
50
|
void add_position(const Point& point);
|
|
46
51
|
Types type;
|
|
47
52
|
bool innerable();
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
bool touched() const { return touched_; }
|
|
54
|
+
int versus() const { return versus_; }
|
|
50
55
|
void touch();
|
|
51
56
|
void orient();
|
|
52
57
|
std::string inspect();
|
|
@@ -57,6 +62,5 @@ class Part : public Queueable<Point> {
|
|
|
57
62
|
|
|
58
63
|
private:
|
|
59
64
|
int versus_ = 0;
|
|
60
|
-
bool touched_ = false;
|
|
61
65
|
Polyline* polyline_;
|
|
62
66
|
};
|
|
@@ -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
|
};
|
|
@@ -15,15 +15,11 @@
|
|
|
15
15
|
|
|
16
16
|
StreamingMerger::StreamingMerger(int number_of_threads,
|
|
17
17
|
std::vector<std::string>* options,
|
|
18
|
-
std::ofstream* stream_to
|
|
19
|
-
|
|
20
|
-
: VerticalMerger(number_of_threads, options), stream(stream_to), total_width(total_width), total_height(total_height) {
|
|
18
|
+
std::ofstream* stream_to)
|
|
19
|
+
: VerticalMerger(number_of_threads, options), stream(stream_to) {
|
|
21
20
|
if (!stream) {
|
|
22
21
|
throw std::invalid_argument("Streaming requires a valid destination output. stream_to cannot be null.");
|
|
23
22
|
}
|
|
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
23
|
}
|
|
28
24
|
|
|
29
25
|
void StreamingMerger::add_tile(ProcessResult& result, bool flush)
|
|
@@ -38,7 +34,7 @@ void StreamingMerger::add_tile(ProcessResult& result, bool flush)
|
|
|
38
34
|
|
|
39
35
|
ProcessResult* StreamingMerger::process_info() {
|
|
40
36
|
ProcessResult *pr = VerticalMerger::process_info();
|
|
41
|
-
pr->groups =
|
|
37
|
+
pr->groups = this->moved;
|
|
42
38
|
return(pr);
|
|
43
39
|
}
|
|
44
40
|
|
|
@@ -65,53 +61,34 @@ void StreamingMerger::stream_polygons(Tile* tile, bool flush) {
|
|
|
65
61
|
|
|
66
62
|
void StreamingMerger::stream_raw_polygon(const Shape* shape) {
|
|
67
63
|
std::ostringstream outer_oss;
|
|
64
|
+
|
|
65
|
+
this->write_outer_polygon_start();
|
|
68
66
|
const std::vector<Point>& points = shape->outer_polyline->raw();
|
|
69
67
|
for (size_t i = 0; i < points.size(); ++i) {
|
|
70
|
-
|
|
71
|
-
if (i < points.size() - 1)
|
|
68
|
+
*stream << points[i].y << "," << points[i].x;
|
|
69
|
+
if (i < points.size() - 1) *stream << " ";
|
|
72
70
|
}
|
|
73
|
-
|
|
71
|
+
this->write_outer_polygon_end();
|
|
74
72
|
|
|
75
73
|
for (const auto& inner_polyline : shape->inner_polylines) {
|
|
76
|
-
|
|
74
|
+
this->write_inner_polygon_start();
|
|
77
75
|
const std::vector<Point>& inner_points = inner_polyline->raw();
|
|
78
76
|
for (size_t i = 0; i < inner_points.size(); ++i) {
|
|
79
|
-
|
|
80
|
-
if (i < inner_points.size() - 1)
|
|
77
|
+
*stream << inner_points[i].y << "," << inner_points[i].x;
|
|
78
|
+
if (i < inner_points.size() - 1) *stream << " ";
|
|
81
79
|
}
|
|
82
|
-
|
|
80
|
+
this->write_inner_polygon_end();
|
|
83
81
|
}
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
void StreamingMerger::ensure_header() {
|
|
87
85
|
if (stream && stream->tellp() == 0) {
|
|
88
|
-
|
|
86
|
+
this->write_header();
|
|
89
87
|
}
|
|
90
88
|
}
|
|
91
89
|
|
|
92
90
|
void StreamingMerger::ensure_footer() {
|
|
93
91
|
if (stream) {
|
|
94
|
-
|
|
92
|
+
this->write_footer();
|
|
95
93
|
}
|
|
96
94
|
}
|
|
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,26 +16,25 @@
|
|
|
16
16
|
#include <vector>
|
|
17
17
|
|
|
18
18
|
class StreamingMerger : public VerticalMerger {
|
|
19
|
-
|
|
19
|
+
protected:
|
|
20
20
|
std::ofstream* stream;
|
|
21
|
-
int total_width;
|
|
22
|
-
int total_height;
|
|
23
21
|
int moved = 0;
|
|
22
|
+
|
|
23
|
+
void stream_polygons(Tile* tile, bool flush = false);
|
|
24
|
+
virtual void stream_raw_polygon(const Shape* shape);
|
|
25
|
+
virtual void write_header() = 0;
|
|
26
|
+
virtual void write_footer() = 0;
|
|
27
|
+
virtual void write_outer_polygon_start() = 0;
|
|
28
|
+
virtual void write_outer_polygon_end() = 0;
|
|
29
|
+
virtual void write_inner_polygon_start() = 0;
|
|
30
|
+
virtual void write_inner_polygon_end() = 0;
|
|
24
31
|
void ensure_header();
|
|
25
32
|
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
33
|
|
|
34
34
|
public:
|
|
35
35
|
StreamingMerger(int number_of_threads,
|
|
36
36
|
std::vector<std::string>* options,
|
|
37
|
-
std::ofstream* stream_to
|
|
38
|
-
int total_width, int total_height);
|
|
37
|
+
std::ofstream* stream_to);
|
|
39
38
|
void add_tile(ProcessResult& result, bool flush = false);
|
|
40
39
|
ProcessResult* process_info() override;
|
|
41
40
|
};
|
|
@@ -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,56 @@
|
|
|
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 <vector>
|
|
13
|
+
#include "StreamingMerger.h"
|
|
14
|
+
|
|
15
|
+
class SvgStreamingMerger : public StreamingMerger {
|
|
16
|
+
private:
|
|
17
|
+
int total_width;
|
|
18
|
+
int total_height;
|
|
19
|
+
std::string svg_css() {
|
|
20
|
+
return ".out{fill:none;stroke:red;stroke-width:1;}.in{fill:none;stroke:green;stroke-width:1;}.out:hover{stroke:yellow;}";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected:
|
|
24
|
+
void write_header() override {
|
|
25
|
+
*stream << "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"" << total_width
|
|
26
|
+
<< "\" height=\"" << total_height << "\"><style>" << svg_css() << "</style>";
|
|
27
|
+
}
|
|
28
|
+
void write_footer() override {
|
|
29
|
+
*stream << "</svg>";
|
|
30
|
+
}
|
|
31
|
+
void write_outer_polygon_start() override {
|
|
32
|
+
*stream << "<polygon points=\"";
|
|
33
|
+
}
|
|
34
|
+
void write_outer_polygon_end() override {
|
|
35
|
+
*stream << "\" class=\"out\"/>";
|
|
36
|
+
}
|
|
37
|
+
void write_inner_polygon_start() override {
|
|
38
|
+
*stream << "<polygon points=\"";
|
|
39
|
+
}
|
|
40
|
+
void write_inner_polygon_end() override {
|
|
41
|
+
*stream << "\" class=\"in\"/>";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public:
|
|
45
|
+
SvgStreamingMerger(int number_of_threads,
|
|
46
|
+
std::vector<std::string>* options,
|
|
47
|
+
std::ofstream* stream_to,
|
|
48
|
+
int total_width, int total_height)
|
|
49
|
+
: StreamingMerger(number_of_threads, options, stream_to),
|
|
50
|
+
total_width(total_width),
|
|
51
|
+
total_height(total_height) {
|
|
52
|
+
if (total_width <= 0 || total_height <= 0) {
|
|
53
|
+
throw std::invalid_argument("SVG Streaming requires valid canvas dimensions (width and height must be > 0).");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
@@ -96,6 +96,8 @@
|
|
|
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"
|
|
100
|
+
#include "PolygonFinder/src/polygon/finder/concurrent/GeoJsonStreamingMerger.h"
|
|
99
101
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.h"
|
|
100
102
|
#include "PolygonFinder/src/polygon/finder/concurrent/ShapePool.cpp"
|
|
101
103
|
extern "C" {
|
|
@@ -308,14 +310,23 @@ struct OfstreamWrapper {
|
|
|
308
310
|
std::ofstream& get_stream() { return stream; }
|
|
309
311
|
};
|
|
310
312
|
|
|
311
|
-
|
|
313
|
+
SvgStreamingMerger* create_svg_streaming_merger(Object self,
|
|
312
314
|
int number_of_threads,
|
|
313
315
|
std::vector<std::string>* options,
|
|
314
316
|
Object stream_obj,
|
|
315
317
|
int total_width,
|
|
316
318
|
int total_height) {
|
|
317
319
|
OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
|
|
318
|
-
return new
|
|
320
|
+
return new SvgStreamingMerger(number_of_threads, options, &wrapper->get_stream(), total_width, total_height);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
GeoJsonStreamingMerger* create_geo_json_streaming_merger(Object self,
|
|
324
|
+
int number_of_threads,
|
|
325
|
+
std::vector<std::string>* options,
|
|
326
|
+
Object stream_obj,
|
|
327
|
+
int pixel_val) {
|
|
328
|
+
OfstreamWrapper* wrapper = Rice::detail::From_Ruby<OfstreamWrapper*>().convert(stream_obj.value());
|
|
329
|
+
return new GeoJsonStreamingMerger(number_of_threads, options, &wrapper->get_stream(),pixel_val);
|
|
319
330
|
}
|
|
320
331
|
|
|
321
332
|
OfstreamWrapper* create_ofstream(Object self, std::string path) {
|
|
@@ -436,7 +447,11 @@ void Init_cpp_polygon_finder() {
|
|
|
436
447
|
ProcessResult pr = Rice::detail::ruby_result_to_process_result(rb_result);
|
|
437
448
|
self.add_tile(pr, flush);
|
|
438
449
|
});
|
|
439
|
-
|
|
450
|
+
|
|
451
|
+
Data_Type<SvgStreamingMerger> rb_csvgstreaming_merger = define_class<SvgStreamingMerger, StreamingMerger>("CPPSvgStreamingMerger");
|
|
452
|
+
rb_csvgstreaming_merger.define_singleton_method("new", &create_svg_streaming_merger);
|
|
453
|
+
Data_Type<GeoJsonStreamingMerger> rb_cgeojsonstreaming_merger = define_class<GeoJsonStreamingMerger, StreamingMerger>("CPPGeoJsonStreamingMerger");
|
|
454
|
+
rb_cgeojsonstreaming_merger.define_singleton_method("new", &create_geo_json_streaming_merger);
|
|
440
455
|
|
|
441
456
|
Module mContrek = define_module("Contrek");
|
|
442
457
|
Module mCpp = define_module_under(mContrek, "Cpp");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Contrek
|
|
4
|
+
module Cpp
|
|
5
|
+
class CPPGeoJsonConcurrentStreamingMerger < CPPGeoJsonStreamingMerger
|
|
6
|
+
def self.new(stream_to:, number_of_threads: 0, options: nil, pixel_val: 0)
|
|
7
|
+
super(number_of_threads, options, stream_to, pixel_val)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
data/lib/contrek/cpp/{cpp_concurrent_streaming_merger.rb → cpp_svg_concurrent_streaming_merger.rb}
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Contrek
|
|
4
4
|
module Cpp
|
|
5
|
-
class
|
|
5
|
+
class CPPSvgConcurrentStreamingMerger < CPPSvgStreamingMerger
|
|
6
6
|
def self.new(stream_to:, total_width:, total_height:, number_of_threads: 0, options: nil)
|
|
7
7
|
super(number_of_threads, options, stream_to, total_width, total_height)
|
|
8
8
|
end
|