C++ Boost RTree overlaps does not work correctly - c++

I am kinda confused and think I get something wrong but I really fail to see it.
I have a boost::geometry::index::rtree that stores 2D boxes of 2D geographic points. Now I try to check if a new box I add to that rtree overlaps with any box already in that rtree. And this check somehow fails for one test and I really don't get why because I do not believe the error is in the rtree/overlaps implementation.
My code is the following (in Visual Studio test environment):
using CoordinateSystem = boost::geometry::cs::geographic<boost::geometry::degree>;
using Point = boost::geometry::model::point<double, 2, CoordinateSystem>;
using RTreeBox = boost::geometry::model::box<Point>;
using RTreeEntry = std::pair<RTreeBox, uint64_t>;
constexpr static auto kRTreeMaxElementsPerNode = 4;
using RTreeAlgorithm = boost::geometry::index::rstar<kRTreeMaxElementsPerNode>;
using RTree = boost::geometry::index::rtree<RTreeEntry, RTreeAlgorithm>;
bool TestAddTreeEntry(RTree& tree, uint64_t index, RTreeBox box)
{
if (!boost::geometry::is_valid(box)) {
boost::geometry::correct(box);
}
std::vector<RTreeEntry> query_results;
tree.query(boost::geometry::index::overlaps(box), std::back_inserter(query_results));
if (query_results.size() > 0)
{
return false;
}
tree.insert(std::make_pair(box, index));
return true;
}
TEST_METHOD(test_rtree_mapping) {
RTree tree;
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 1 }, { 3, 3 })));
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 4, 1 }, { 9, 5 })));
Assert::IsTrue(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 4 }, { 2, 9 })));
Assert::IsFalse(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 2.75 }, { 2, 9 })));
Assert::IsFalse(TestAddTreeEntry(tree, 1, RTreeBox({ 1, 4 }, { 3.5, 9 })));
}
The first Assert::IsFalse works - but also unexpectedly only overlaps with the first box ({1, 1}, {3, 3}) and not with the third one ({1, 4}, {2, 9}). The second Assert::IsFalse does not work because the entry is successfully added.
Anyone knows a reason behind this? Has this something to do with geographic coordinates that I do not understand yet?
Kind regards

Overlaps doesn't do what you expect. It's too strict. The docs state:
The function overlaps implements function Overlaps from the OGC Simple Feature Specification.
The OGC document contains:
That's admittedly hard to parse, but that's the nature of technical specifications. Luckily, intersects is much simpler:
a.Intersects(b) ⇔ ! a.Disjoint(b)
DEMO
I created a test program that
allows you to override the RELATION (e.g. bgi::intersects, bgi::overlaps, !bgi::disjoint)
also writes a SVG vizualtion of the shapes involved.
Live On Compiler Explorer
#include <boost/geometry.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <fstream>
namespace bg = boost::geometry;
namespace bgm = bg::model;
namespace bgi = bg::index;
using CS = bg::cs::geographic<bg::degree>;
using Point = bg::model::point<double, 2, CS>;
using Box = bg::model::box<Point>;
using Tree = std::pair<Box, uint64_t>;
constexpr static auto kRTreeMaxElementsPerNode = 4;
using RTreeAlgorithm = bgi::rstar<kRTreeMaxElementsPerNode>;
using RTree = bgi::rtree<Tree, RTreeAlgorithm>;
#ifndef RELATION
#define RELATION bgi::intersects
#endif
#define RELATION_STR BOOST_PP_STRINGIZE(RELATION)
bool add(RTree& tree, uint64_t index, Box box) {
if (std::string reason; !bg::is_valid(box, reason)) {
std::cerr << "Trying to correct: " << bg::dsv(box) << " (" << reason << ")" << std::endl;
bg::correct(box);
assert(bg::is_valid(box));
}
for (auto it = qbegin(tree, RELATION(box)), e = qend(tree); it != e; ++it)
return false;
tree.insert(std::make_pair(box, index));
return true;
}
int main() {
std::cout << std::boolalpha;
RTree tree;
struct {
Box box;
char const* name;
char const* color;
} const shapes[]{
{{{1.00, 1.00}, {3.00, 3.00}}, "box1", "red"},
{{{4.00, 1.00}, {9.00, 5.00}}, "box2", "green"},
{{{1.00, 4.00}, {2.00, 9.00}}, "box3", "blue"},
{{{1.00, 2.75}, {2.00, 9.00}}, "probe1", "orange"},
{{{1.00, 4.00}, {3.50, 6.00}}, "probe2", "gray"},
};
for (auto const& s : shapes) {
auto idx = (&s - shapes);
auto added = add(tree, idx, s.box);
std::cout << "Adding " << s.name << " as #" << idx << ": "
<< (added ? "ACCEPT" : "REJECTED") << " " << bg::dsv(s.box)
<< "\n";
if (!added) {
for (auto it = qbegin(tree, RELATION(s.box)), e = qend(tree); it != e; ++it) {
std::cout << " - because " << s.name << " " << RELATION_STR
<< " " << shapes[it->second].name << "\n";
}
}
}
{
std::ofstream ofs("output.svg");
bg::svg_mapper<Point> svg(ofs, 400, 400);
auto style = [](std::string c) {
return "fill-rule:nonzero;fill-opacity:0.25;fill:" + c +
";stroke:" + c + ";stroke-width:1;";
};
for (auto const& [b, name, color] : shapes) {
svg.add(b);
}
for (auto const& [b, name, color] : shapes) {
auto h = b.max_corner().get<1>() - b.min_corner().get<1>();
auto mc = b.max_corner();
mc.set<1>(mc.get<1>() - h / 2);
svg.text(mc,
name +
("\n" + boost::lexical_cast<std::string>(bg::dsv(b))),
style(color));
}
for (auto const& [b, _, color] : shapes)
svg.map(b, style(color));
}
}
With either -DRELATION=bgi::intersects or -DRELATION=!bgi::disjoint:
Adding box1 as #0: ACCEPT ((1, 1), (3, 3))
Adding box2 as #1: ACCEPT ((4, 1), (9, 5))
Adding box3 as #2: ACCEPT ((1, 4), (2, 9))
Adding probe1 as #3: REJECTED ((1, 2.75), (2, 9))
- because probe1 bgi::intersects box1
- because probe1 bgi::intersects box3
Adding probe2 as #4: REJECTED ((1, 4), (3.5, 6))
- because probe2 bgi::intersects box3
(replacing bgi::intersects with !bgi::disjoint in the output obviously).
Visualization:
Note how the output changes if you change probe1:
{{{1.00, 2.75}, {1.50, 9.00}}, "probe1", "orange"},
That looks like:
This would behave as you expected even with the bgi::overlaps. Overlaps is just too strict for the expectated output.

Related

Custom object's vector attribute median c++

I am trying to find the median value from the third attribute of my objects. My objects are in a vector.
std::vector<Object> obj =
{ Object {V , H , 5},
Object {C , B , 2},
Object {D , F , 6},
Object {B , H , 4},
Object {B , H , 4}
};
answer:
4
I tried to use the nth_element method but it seems that I need to access the attribute.
std::nth_element(obj.begin(), (obj.begin() + obj.end())/2, obj.end());
By default, std::nth_element() applies the operator< to the dereferenced iterators provided as arguments.
In C++, there is no operator< defined for custom classes but the author is free to define (overload) one.
Alternatively, std::nth_element() can be called with a custom less predicate to force a specific order.
Could you show me a generic example ?
Here we go:
an example to get median according to a specific attribute of an object with
partial sorting (aka. std::nth_element()) and
a custom predicate to sort for Object::attr.
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
struct Object {
std::string id1, id2;
int attr;
};
std::ostream& operator<<(std::ostream &out, const Object &obj)
{
return out << "Object { id1: " << obj.id1
<< ", id2: " << obj.id2
<< ", attr: " << obj.attr << " }";
}
// demonstrate
int main()
{
std::vector<Object> obj =
{ Object {"V", "H" , 5},
Object {"C", "B" , 2},
Object {"D", "F" , 6},
Object {"B", "H" , 4},
Object {"B", "H" , 4}
};
// partial sorting with custom predicate (provided as lambda):
std::nth_element(obj.begin(), obj.begin() + obj.size() / 2, obj.end(),
[](const Object &obj1, const Object &obj2) { return obj1.attr < obj2.attr; });
// get result:
const std::vector<Object>::iterator iter
= obj.begin() + obj.size() / 2;
std::cout << "Median: " << *iter << '\n';
}
Output:
Median: Object { id1: B, id2: H, attr: 4 }
Live demo on coliru
Note:
OP mentioned the following snippet:
std::nth_element(obj.begin(), obj.begin() + obj.end()/2, obj.end());
obj.begin() + obj.end()/2 is yet another error.
It had to be obj.begin() + (obj.end() - obj.begin()) / 2.
I used instead the more compact obj.begin() + obj.size() / 2.

Does boost::combine() work with output of a method?

In the test case below, I use boost::combine to iterate on output of a function getPoints().
Expected Output
I expect (1, 2, 3) printed 6 times; since I effectively zip two lists -
([point, point, point], [point, point, point]).
Actual Output
The output is surprising to me, and wrong. The first two lines are off suggesting memory corruption?
(0, 0, 3) // <-- wrong!
(52246144, 0, 3) // <-- wrong! memory corruption?
(1, 2, 3)
(1, 2, 3)
(1, 2, 3)
(1, 2, 3)
This can also be verified online here, http://cpp.sh/622h4.
Is this a bug?
Code below -
#include <iostream>
#include <vector>
#include <boost/range/combine.hpp>
struct Point {
int x, y, z;
};
const std::vector<Point> getPoints() {
// There is only one Point in the entire code, which is (1, 2, 3).
const Point point = {1, 2, 3};
// Return a vectore of 3 copies of the point (1, 2, 3).
return {point, point, point};
}
int main() {
// Zip over two copies of 3-tuples of {1, 2, 3}.
for (const auto& zipped : boost::combine(getPoints(), getPoints())) {
auto p1 = zipped.get<0>();
auto p2 = zipped.get<1>();
// Expected output is (1, 2, 3), six times.
std::cout << "(" << p1.x << ", " << p1.y << ", " << p1.z << ")" << std::endl;
std::cout << "(" << p2.x << ", " << p2.y << ", " << p2.z << ")" << std::endl;
}
return 0;
}
You have undefined behavior here as you access a dangling reference. This can be fixed by
const auto points1 = getPoints();
const auto points2 = getPoints();
for (const auto& zipped : boost::combine(points1, points2)) {
// ...
}
Rvalue references are always problematic when dealing with range libraries. Obviously, a range algorithm like boost::combine doesn't copy the argument. And it creates a new proxy range object, which makes it impossible to extend the lifetime of the temporary range passed in.
Contrary, a range-based for loop for(const auto& item: getPoints()) {...} expands to
{
auto && __range = getPoints();
for (auto __begin = begin_expr, __end = end_expr; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
where the lifetime of getPoints() is extended by binding it to an rvalue reference. Imagine a function template combine as
template<class Rng>
auto combine(Rng&& rng) {
auto && == range; // Nice try but doesn't help
// ...
return someProxyRange;
}
This function template can't do anything about extending the lifetime of rng, as it acts in a different scope than rng, which comes from the client side. In a range based for loop, this is different. The scope of the temporary (e.g. getPoints()) and the forwarding reference auto&& __range are at the same scope, hence the lifetime can be extended.

How to create a map with custom class/comparator as key

I have a class named ItemType. It has two members - both double, named m_t and m_f. Two items of type ItemType are considered to be equal if these two members differ from each other within respective tolerance levels. With this logic, the comparator function is so defined as well. However, when I insert objects of this type as key into a map, only one key is produced in the map, even though at least three such keys should be present:
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <vector>
using namespace std;
class ItemKey
{
public:
ItemKey(double t, double f)
{
m_t = t;
m_f = f;
}
double m_t;
double m_f;
double m_tEpsilon = 3;
double m_fEpsilon = 0.1;
bool operator<(const ItemKey& itemKey) const
{
int s_cmp = (abs(itemKey.m_f - m_f) > m_fEpsilon);
if (s_cmp == 0)
{
return (abs(itemKey.m_t - m_t) > m_tEpsilon);
}
return s_cmp < 0;
}
};
int main()
{
// The pairs are the respective values of m_t and m_f.
vector<pair<double, double>> pairs;
// These two should belong in one bucket -> (109.9, 9.0), because m_f differs by 0.09 and m_t differs by just 1
pairs.emplace_back(109.9, 9.0);
pairs.emplace_back(110.9, 9.09);
// This one is separate from above two beause even though m_t is in range, m_f is beyong tolerance level
pairs.emplace_back(109.5, 10.0);
// Same for this as well, here both m_t and m_f are beyong tolerance of any of the two categories found above
pairs.emplace_back(119.9, 19.0);
// This one matches the second bucket - (109.5, 10.0)
pairs.emplace_back(109.9, 10.05);
// And this one too.
pairs.emplace_back(111.9, 9.87);
map<ItemKey, size_t> itemMap;
for (const auto& item: pairs)
{
ItemKey key(item.first, item.second);
auto iter = itemMap.find(key);
if (iter == itemMap.end())
{
itemMap[key] = 1;
}
else
{
itemMap[iter->first] = itemMap[iter->first] + 1;
}
}
// The map should have three keys - (109.9, 9.0) -> count 2, (109.5, 10.0) -> count 3 and (119.9, 19.0) -> count 1
cout << itemMap.size();
}
However, the map seems to have only 1 key. How do I make it work as expected?
Why isn't your version working?
You did well to create your own comparison function. To answer your question, you have an error in your operator<() function such that only returns true if m_f is outside of tolerance and m_t is within tolerance, which I'm guessing is not what you desired. Let's take a look.
int s_cmp = (abs(itemKey.m_f - m_f) > m_fEpsilon);
The above line basically is checking whether this->m_f and itemKey.m_f are within tolerance of eachother (meaning equal to each other). That is probably what was intended. Then you say
if (s_cmp == 0)
{
return (abs(itemKey.m_t - m_t) > m_tEpsilon);
}
If s_cmp is true, then it will have the value of 1, and it will have a value of 0 for false (meaning that they are not within tolerance of each other). Then you return true if the m_t value is within tolerance. Up to this point, you return true if m_f is not equal (according to tolerance) and if m_t is equal (according to tolerance). Then your last line of code
return s_cmp < 0;
will return true always since a boolean converted to an integer cannot ever be negative.
How to get it working?
#include <iostream>
#include <string>
#include <map>
#include <cmath>
#include <vector>
struct ItemKey
{
double m_t;
double m_f;
static constexpr double t_eps = 3;
static constexpr double f_eps = 0.1;
ItemKey(double t, double f) : m_t(t), m_f(f) {}
bool operator<(const ItemKey& other) const
{
// Here it is assumed that f_eps and t_eps are positive
// We also ignore overflow, underflow, and NaN
// This is written for readability, and assumed the compiler will be
// able to optimize it.
auto fuzzy_less_than = [] (double a, double b, double eps) {
return a < b - eps;
};
bool f_is_less_than = fuzzy_less_than(this->m_f, other.m_f, f_eps);
bool f_is_greater_than = fuzzy_less_than(other.m_f, this->m_f, f_eps);
bool f_is_equal = !f_is_less_than && !f_is_greater_than;
bool t_is_less_than = fuzzy_less_than(this->m_t, other.m_t, t_eps);
return f_is_less_than || (f_is_equal && t_is_less_than);
}
};
int main()
{
using namespace std;
// The pairs are the respective values of m_t and m_f.
vector<pair<double, double>> pairs;
// These two should belong in one bucket
// -> (109.9, 9.0), because m_f differs by 0.09 and m_t differs by just 1
pairs.emplace_back(109.9, 9.0);
pairs.emplace_back(110.9, 9.09);
// This one is separate from above two beause even though m_t is in range,
// m_f is beyong tolerance level
pairs.emplace_back(109.5, 10.0);
// Same for this as well, here both m_t and m_f are beyong tolerance of any
// of the two categories found above
pairs.emplace_back(119.9, 19.0);
// This one matches the second bucket - (109.5, 10.0)
pairs.emplace_back(109.9, 10.05);
// And this one too.
pairs.emplace_back(111.9, 9.87);
map<ItemKey, size_t> itemMap;
for (const auto& item: pairs)
{
ItemKey key(item.first, item.second);
auto iter = itemMap.find(key);
if (iter == itemMap.end())
{
itemMap[key] = 1;
}
else
{
itemMap[iter->first] = itemMap[iter->first] + 1;
}
}
// The map should have three keys
// - (109.9, 9.0) -> count 2
// - (109.5, 10.0) -> count 3
// - (119.9, 19.0) -> count 1
cout << itemMap.size();
cout << "itemMap contents:" << endl;
for (auto& item : itemMap) {
cout << " (" << item.first << ", " << ")" << endl;
}
return 0;
}
There are a few things I changed above. I have a few suggestions also unrelated to the programming mistake:
Do not store boolean values into integer variables.
There's a reason that C++ introduced the bool type.
Write your code to be readable and in a way that the compiler
can easily optimize. You may notice I used a lambda expression
and multiple booleans. Smart compilers will inline the calls to
that lambda expression since it is only used within the local scope.
Also smart compilers can simplify boolean logic and make it
performant for me.
The m_tEpsilon and m_fEpsilon are probably not good to be
changable variables of the class. In fact, it may be bad if one
object has a different epsilon than another one. If that were the
case, which do you use when you do the < operator? For this
reason, I set them as static const variables in the class.
For constructors, it is better to initialize your variables in the
initializer list rather than in the body of the constructor. That
is unless you are doing dynamic resource allocation, then you would
want to do it in the constructor and make sure to clean it up if
you end up throwing an exception (preferrably using the RAII
pattern). I'm starting to get too far off topic :)
Even though class and struct are basically identical except for
the default protection level (class is private by default and
struct is public by default). It is convention to have it as a
struct if you want direct access to the member variables. Although,
in this case, I would probably set your class as immutable. To do
that, set the m_t and m_f as private variables and have a getter
m() and f(). It might be a bad idea to modify an ItemKey
instance in a map after it has been inserted.
Potential problems with this approach
One of the problems you have with your approach here is that it will be dependent on the order in which you add elements. Consider the following pairs to be added: (3.0, 10.0) (5.0, 10.0) (7.0, 10.0). If we add them in that order, we will get (3.0, 10.0) (7.0, 10.0), since (5.0, 10.0) was deemed to be equal to (3.0, 10.0). But what if we were to have inserted (5.0, 10.0) first, then the other two? Well then the list would only have one element, (5.0, 10.0), since bother of the others would be considered equal to this one.
Instead, I would like to suggest that you use std::multiset instead, of course this will depend on your application. Consider these tests:
void simple_test_map() {
std::map<ItemKey, size_t> counter1;
counter1[{3.0, 10.0}] += 1;
counter1[{5.0, 10.0}] += 1;
counter1[{7.0, 10.0}] += 1;
for (auto &itempair : counter1) {
std::cout << "simple_test_map()::counter1: ("
<< itempair.first.m_t << ", "
<< itempair.first.m_f << ") - "
<< itempair.second << "\n";
}
std::cout << std::endl;
std::map<ItemKey, size_t> counter2;
counter2[{5.0, 10.0}] += 1;
counter2[{3.0, 10.0}] += 1;
counter2[{7.0, 10.0}] += 1;
for (auto &itempair : counter2) {
std::cout << "simple_test_map()::counter2: ("
<< itempair.first.m_t << ", "
<< itempair.first.m_f << ") - "
<< itempair.second << "\n";
}
std::cout << std::endl;
}
This outputs:
simple_test_map()::counter1: (3, 10) - 2
simple_test_map()::counter1: (7, 10) - 1
simple_test_map()::counter2: (5, 10) - 3
And for the multiset variant:
void simple_test_multiset() {
std::multiset<ItemKey> counter1 {{3.0, 10.0}, {5.0, 10.0}, {7.0, 10.0}};
for (auto &item : counter1) {
std::cout << "simple_test_multiset()::counter1: ("
<< item.m_t << ", "
<< item.m_f << ")\n";
}
std::cout << std::endl;
std::multiset<ItemKey> counter2 {{5.0, 10.0}, {3.0, 10.0}, {7.0, 10.0}};
for (auto &item : counter2) {
std::cout << "simple_test_multiset()::counter2: ("
<< item.m_t << ", "
<< item.m_f << ")\n";
}
std::cout << std::endl;
std::cout << "simple_test_multiset()::counter2.size() = "
<< counter2.size() << std::endl;
for (auto &item : counter1) {
std::cout << "simple_test_multiset()::counter2.count({"
<< item.m_t << ", "
<< item.m_f << "}) = "
<< counter1.count(item) << std::endl;
}
std::cout << std::endl;
}
This outputs
simple_test_multiset()::counter1: (3, 10)
simple_test_multiset()::counter1: (5, 10)
simple_test_multiset()::counter1: (7, 10)
simple_test_multiset()::counter2: (5, 10)
simple_test_multiset()::counter2: (3, 10)
simple_test_multiset()::counter2: (7, 10)
simple_test_multiset()::counter2.count({3, 10}) = 2
simple_test_multiset()::counter2.count({5, 10}) = 3
simple_test_multiset()::counter2.count({7, 10}) = 2
simple_test_multiset()::counter2.size() = 3
Note that count() here returns the number of elements within the multiset that are considered equal to the ItemKey passed in. This may be advantageous for situations where you want to ask "how many of my points are within my tolerance of a new point?"
Good luck!

Convert array of point to polygon

I have array of point with latitude and longitude, from this array generating LineString to display way on road by leaflet.
Now i want to improve code function to detect when user point (received from GPS device):
1) Out from waypoint
2) Position on waypoint
3) Direction (begin or back)
After having tried many ways to implement my idea i coming to convert my array of point to Polygon and control by boost::geometry::intersection
I tried realise this function by search near point in array that work perfect in one way road else code can lock point from neighbour way :(
Example of ways:
[start]--------------[end]
But it can be so
[start]
---------one_road---turning_road_and_reverse-]
-------two_road-----------
[end]
Now i want to convert array to one polygon
-----------------------------------------------
one_road
two_road
-----------------------------------------------
i think that i can easily release function to detect location without errors
May be someone know how easily convert linestring to polygon?
example
i have:
LINESTRING(-105.40392744645942 38.49004450086558,-105.40486621961463 38.491262147649266,-105.40443706617225 38.49272329662804,-105.40424394712318 38.49368058506501,-105.4055099497782 38.49443633010962,-105.40690469846595 38.494940155735165,-105.40694761381019 38.49450350706328,-105.40634679899085 38.49324392875914,-105.40510225400794 38.49146368720108,-105.40437269315589 38.490422393448746,-105.40394675757852 38.489957795386)
i want:
POLYGON((-105.40419674129225 38.49056599190572,-105.40475464076735 38.49046522094479,-105.40737247676589 38.494462360981586,-105.40685749263503 38.49520130375959,-105.40647554502357 38.493848529093356,-105.4052739153849 38.49193394396309,-105.4047160159098 38.49237060820819,-105.40473747358192 38.49344546276763,-105.40600347623695 38.49430197601443,-105.40664720640052 38.49480580257953,-105.40585327253211 38.494789008417456,-105.40432977781165 38.49394929532246,-105.40394353971351 38.493059188756156,-105.40465164289344 38.49129573761371,-105.40419674129225 38.49056599190572))
Please help!
Your question is in serious need of a SSCCE. Reading it you might be looking for anything from trivial type conversion to complicated routing algorithms.
Here's are two simple SSCCE's that show how to do the type conversions you describe.
NOTE The extra work to check that the polygon is valid (it needs to be closed, and the points need to have the correct orientation for the outer ring)
Array Of Point To Polygon
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <iostream>
#include <boost/geometry/io/io.hpp>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using point = bgm::d2::point_xy<int>;
using polygon = bgm::polygon<point>;
void debug_print(polygon const& p) {
std::string reason;
bool valid = bg::is_valid(p, reason);
std::cout << bg::dsv(p) << " - " << (!valid?"invalid ("+reason+")":"valid") << "\n";
}
int main() {
point arr[] { {1,3}, {4,5}, {9, 0} };
for (auto& p : arr)
std::cout << bg::wkt(p) << " ";
std::cout << "\n";
polygon p { {std::begin(arr), std::end(arr)} };
debug_print(p);
bg::correct(p);
debug_print(p);
std::cout << bg::wkt(p) << "\n";
}
Prints:
POINT(1 3) POINT(4 5) POINT(9 0)
(((1, 3), (4, 5), (9, 0))) - invalid (Geometry has too few points)
(((1, 3), (4, 5), (9, 0), (1, 3))) - valid
POLYGON((1 3,4 5,9 0,1 3))
LineString To Polygon
Live On Coliru
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <iostream>
#include <boost/geometry/io/io.hpp>
namespace bg = boost::geometry;
namespace bgm = bg::model;
using point = bgm::d2::point_xy<int>;
using linestring = bgm::linestring<point>;
using ring = bgm::ring<point>;
using polygon = bgm::polygon<point>;
void debug_print(polygon const& p) {
std::string reason;
bool valid = bg::is_valid(p, reason);
std::cout << bg::dsv(p) << " - " << (!valid?"invalid ("+reason+")":"valid") << "\n";
}
int main() {
linestring ls { {1,3}, {4,5}, {9, 0} };
std::cout << bg::wkt(ls) << "\n";
polygon p { ring{ls.begin(), ls.end()} };
debug_print(p);
bg::correct(p);
debug_print(p);
std::cout << bg::wkt(p) << "\n";
}
Prints
LINESTRING(1 3,4 5,9 0)
(((1, 3), (4, 5), (9, 0))) - invalid (Geometry has too few points)
(((1, 3), (4, 5), (9, 0), (1, 3))) - valid
POLYGON((1 3,4 5,9 0,1 3))
i found solution this is boost::geometry::buffer
using namespace boost::geometry::model;
namespace bg = boost::geometry;
typedef bg::model::point <double , 2, bg::cs::cartesian > point_t;
typedef boost::geometry::model::polygon <point_t> polygon_t;
typedef bg::model::linestring<point_t> linestring_t;
linestring_t ls1;
vector<BSONElement> point_records = record.getField("points").Array();
linestring_t ls1;
for(vector<BSONElement>::iterator it = point_records.begin(); it != point_records.end(); ++it)
{
BSONObj point_record = (*it).Obj();
bg::append(ls1, point_t(point_record.getField("lo").Double(), point_record.getField("lat").Double()));
}
const double buffer_distance = 1.0;
const int points_per_circle = 36;
// Declare other strategies
boost::geometry::strategy::buffer::distance_symmetric<double> distance_strategy(0.0002);
boost::geometry::strategy::buffer::join_round join_strategy(points_per_circle);
boost::geometry::strategy::buffer::end_round end_strategy(points_per_circle);
boost::geometry::strategy::buffer::point_circle circle_strategy(points_per_circle);
boost::geometry::strategy::buffer::side_straight side_strategy;
boost::geometry::model::multi_polygon<polygon_t> result;
/* polygon_t result; */
boost::geometry::buffer(ls1, result,
distance_strategy, side_strategy,
join_strategy, end_strategy, circle_strategy);
Please sorry for bad english!

C++ - Find adjacent elements in std::map

What is the most efficient way to look up the adjacent elements in a STL map using the examples I mention below:
Suppose I have a map of integer - string:
1 -> Test1
5 -> Test2
10 -> Test3
20 -> Test4
50 -> Test5
If I call:
get_adjacent(1) // Returns iterator to 1 and 5
get_adjacent(2) // Returns iterator to 1 and 5
get_adjacent(24) // Returns iterator to 20 and 50
get_adjacent(50) // Returns iterator to 20 and 50
Use std::lower_bound and std::upper_bound for exactly this.
Better yet std::map::equal_range combines the power of both:
See it live on http://liveworkspace.org/code/d3a5eb4ec726ae3b5236b497d81dcf27
#include <map>
#include <iostream>
const auto data = std::map<int, std::string> {
{ 1 , "Test1" },
{ 5 , "Test2" },
{ 10 , "Test3" },
{ 20 , "Test4" },
{ 50 , "Test5" },
};
template <typename Map, typename It>
void debug_print(Map const& map, It it)
{
if (it != map.end())
std::cout << it->first;
else
std::cout << "[end]";
}
void test(int key)
{
auto bounds = data.equal_range(key);
std::cout << key << ": " ; debug_print(data, bounds.first) ;
std::cout << ", " ; debug_print(data, bounds.second) ;
std::cout << '\n' ;
}
int main(int argc, const char *argv[])
{
test(1);
test(2);
test(24);
test(50);
}
Outputs:
1: 1, 5
2: 5, 5
24: 50, 50
50: 50, [end]