Boost.Geometry doesn't find second point of polygon-line intersecion - c++

I'm trying to use Boost.Geometry library to find the intersection of square and line,
model::ring<model::d2::point_xy<double>> ring { {0, 0}, {2, 0}, {2, 2}, {0, 2} };
model::polygon<model::d2::point_xy<double>> pol;
pol.inners().push_back (ring);
model::linestring<model::d2::point_xy<double>> line { {1, 3}, {-1, -1} };
model::multi_point<model::d2::point_xy<double>> out;
intersection (pol, line, out); //out returns only {0.5, 2}, but not {0, 1}
but it returns only one point, althougt actually there is two points of intersection
How can I find all the points of intersection?

Close your ring and put it in the expected order (by default clockwise, see default template parameters):
model::ring<model::d2::point_xy<double>> ring {
{0, 0}, {0, 2}, {2, 2}, {2, 0}, {0, 0}
};
Your ring was not valid, i.e. not fullfilling the requirements of the specified template arguments.
As per documentation (see under rules) using an invalid geometry as input may give wrong results and validity is neither checked not corrected by the algorithm.
The ring is also not automatically closed on construction or before first use (how should it know you are not going to append more points?). Here is an example construction with repeated closing point.
There are however is_valid and correct to remedy this.
You also probably want to push the points to the exterior ring, i.e. pol.outer(). Your polygon needs to have an exterior ring, interior rings determine holes. You can directly construct the polygon without interior rings:
model::polygon<model::d2::point_xy<double>> pol {
{ {0, 0}, {0, 2}, {2, 2}, {2, 0}, {0, 0} }
};

Related

C++ Unordered map initializer map not initializing properly

I'm relatively new to hash maps. I have the following code in my program:
std::unordered_map<int, int> XY ({
{0, 0}, {0, 3}, {0, 6},
{3, 0}, {3, 3}, {3, 6},
{6, 0}, {6, 3}, {6, 6}
});
For some reason, the map only contains the first three pairs ({0, 0}, {0, 3}, and {0, 6}). Even when I cout the bucket count, it outputs 11. Yet, there's still only three in my map.
How do I fix this? It seems unreasonable to do a bunch of .insert()'s.

strange behavior while sorting vector of pairs

I am populating the following vector with non-negative integers for a codejam problem:
vector<pair<int,pair<int,int> > > v;
Following way of sorting fails the submission:
sort(v.begin(),v.end(),[](auto a,auto b){
return a.first < b.first;
});
But if i just change the sorting as below:
sort(v.begin(),v.end());
The submission passes.
What's wrong with the lamda function that I am using for sorting?
Thanks
Your lambda only takes the first element into account, but obivously a pair consists of two elements. With your lambda pairs with identical first but different second elements will be considered as equal. Thus their relative order after sorting is unspecified.
If you want to sort data like the following:
{1, {1, 1}},
{0, {2, 2}},
{1, {3, 3}},
Then the first and last item are considered equal and sorting can either produce
{0, {2, 2}},
{1, {1, 1}},
{1, {3, 3}},
or
{0, {2, 2}},
{1, {3, 3}},
{1, {1, 1}},
But std::pair's default comparison operator compares the first and second element.

How to filter vector elements relative to other ones?

I a vector of vectors, each representing a a set (in the mathematical sense). For example:
{{1, 3}, {4, 9, 14}, {1, 3}, {1, 4, 8, 9, 10, 14, 16}, {1, 3, 9}, {4, 9, 17, 22}}
I want to make the most efficient C++ possible function capable of filtering (in place, if possible) the vector in order to remove every item that contains another.
For example, here:
{1, 3} is contained by {1, 3} and {1, 3, 9}
{4, 9, 14} is contained by {1, 4, 8, 9, 10, 14, 16}
The resulting vector would then be:
{{1, 3}, {4, 9, 14}, {4, 9, 17, 22}}
As I'm beginning with C++ don't really have any clue of how to do this efficiently. I found, on other answers here, the erase / remove idiom, which doesn't seem to be very appropriate here, except by passing erase a closure as predicate. Which doesn't seem really idiomatic in C++.
Please note that keeping the original ordering doesn't matter, nor does the ordering of values inside each set.
Given what I learnt so far, thanks to your very helpful comments, the solution I came up with is:
struct std::vector<size_t> colset;
bool less_colsets(const colset& a, const colset& b) {
return a.size() < b.size();
}
void sort_colsets(std::list<colset>& l) {
l.sort(less_colsets);
}
void strip_subsets(std::list<colset>& l) {
sort_colsets(l);
for (std::list<colset>::iterator i = l.begin(); i != l.end(); ++i) {
std::list<colset>::iterator j = next(i, 1);
while (j != l.end()) {
if (includes((*j).begin(), (*j).end(), (*i).begin(), (*i).end())) {
j = l.erase(j);
}
else {
++j;
}
}
}
}
Note that I replaced the outermost std::vector by std::list which is much more optimised for element removal anywhere.
This seems to work as expected, though I'd need some more tests to prove this. The next step will be to use a more efficient comparison function than includes, which would take into account the fact that each vector is lexically ordered (which the program guarantees). I'll try this tomorrow.
Edit: Looks like std::includes already takes care of this fact. YAY!
Thanks everybody.

2D int array in C++

So I want to initialize an int 2d array very quickly, but I can't figure out how to do it. I've done a few searches and none of them say how to initialize a 2D array, except to do:
int [SOME_CONSTANT][ANOTHER_CONSTANT] = {{0}};
Basically, I've got 8 vertices, and I'm listing the 4 vertices of each face of a cube in an array. I've tried this:
int[6][4] sides = {{0, 1, 2, 3}, {4, 5, 6, 7}, {0, 4, 7, 3}, {7, 6, 2, 3}, {5, 1, 2, 6}, {0, 1, 5, 4}};
But that tells me that there's an error with 'sides', and that it expected a semi-colon. Is there any way to initialize an array quickly like this?
Thanks!
You have the [][] on the wrong side. Try this:
int sides[6][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {0, 4, 7, 3}, {7, 6, 2, 3}, {5, 1, 2, 6}, {0, 1, 5, 4}};
Keep in mind that what you really have is:
int **sides
(A pointer to a pointer of ints). It's sides that has the dimensions, not the int. Therefore, you could also do:
int x, y[2], z[3][4], ...;
I think You meant to say
int sides[6][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {0, 4, 7, 3}, {7, 6, 2, 3}, {5, 1, 2, 6}, {0, 1, 5, 4}};
int array[n][m] behaves just like int array[n * m].
In fact, array[i][j] = array[m * i + j] for all i, j.
So int array[2][3] = {1, 2, 3, 4, 5, 6}; is a valid declaration and, for example,
array[1][1] = array[3 * 1 + 1] = array[4] = 5.
int sides[6][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {0, 4, 7, 3}, {7, 6, 2, 3}, {5, 1, 2, 6}, {0, 1, 5, 4}};
I'm not a regular c++ programmer but I looks like int sides[6][4] seems to compile while int[6][4] sides fails. Languages like C# lets you have the [][] on either sides but apparently c++ doesn't.
int sides[6][4] = ... should do the trick. This sounds like you may be coming from a Java (or other language) background so I do recommend a C++ book The Definitive C++ Book Guide and List for more details.
Yes, the intended type of sides is int[6][4], but C++ has confusing syntax sometimes. The way to declare said array is:
int sides[6][4] = {/*stuff*/};
You run into this with function pointers too, but even worse:
int (*myfuncptr)(int); //creates a function pointer called myfuncptr
With function pointers though, you can do this:
typedef int (*func_ptr_type)(int);
func_ptr_type myfuncptr;
Unfortunately, there's no corresponding magic trick for arrays.
i would make a array outside of function and just assign it it to your local. this will very likely invoke memcpy or just inline memory copying loop
this is the fastest you can get

How to create a 2D array in C++ using this specific container

I'm trying to port a
int a[][]
from Java to C++. I'm using this class as a container ArrayRef for ints because it handles references, and the project uses it extensively. In the AbstractReader class I declared
const ArrayRef<int> START_END_PATTERN_;
const ArrayRef<int> MIDDLE_PATTERN_;
const ArrayRef<ArrayRef<int> > L_PATTERNS_;
const ArrayRef<ArrayRef<int> > L_AND_G_PATTERNS_;
and
static int START_END_PATTERN[];
static int MIDDLE_PATTERN[];
static int L_PATTERNS[10][4];
static int L_AND_G_PATTERNS[20][4];
Note the trailing underscore to differentiate the two variables.
I'm not sure what to do in order to initialize the two-dimensional ArrayRef. What I'm posting here will segfault because those ArrayRefs are being allocated on the stack. Anybody have a clever way to do this?
The only way I've actually managed to get it to work is using a ArrayRef< Ref<ArrayRef<int> > > by making ArrayRef inherit from Counted, which is basically a class that allows for Reference Counting in C++. But in order to access the elements I hen have to do something like *(foo[i])[j], which is slightly nastier than foo[i][j].
int AbstractReader::L\_AND\_G_PATTERNS[20][4] = {
{3, 2, 1, 1}, // 0
{2, 2, 2, 1}, // 1
{2, 1, 2, 2}, // 2
{1, 4, 1, 1}, // 3
{1, 1, 3, 2}, // 4
{1, 2, 3, 1}, // 5
{1, 1, 1, 4}, // 6
{1, 3, 1, 2}, // 7
{1, 2, 1, 3}, // 8
{3, 1, 1, 2}, // 9
// G patterns
{1, 1, 2, 3}, // 0
{1, 2, 2, 2}, // 1
{2, 2, 1, 2}, // 2
{1, 1, 4, 1}, // 3
{2, 3, 1, 1}, // 4
{1, 3, 2, 1}, // 5
{4, 1, 1, 1}, // 6
{2, 1, 3, 1}, // 7
{3, 1, 2, 1}, // 8
{2, 1, 1, 3} // 9
};
AbstractReader::AbstractReader()
: decodeRowStringBuffer_(ostringstream::app),
START_END_PATTERN_(START_END_PATTERN, 3),
MIDDLE_PATTERN_(MIDDLE_PATTERN, 5),
L_PATTERNS_(10),
L_AND_G_PATTERNS_(20) {
for (int i = 0; i < 20; i++) {
if (i < 10) {
L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
}
ArrayRef<int> lgpattern((L_AND_G_PATTERNS[i]), 4);
L_AND_G_PATTERNS_[i] = lgpattern;
}
}
What you have should be safe. The (stack allocated) ArrayRefs create heap allocated Arrays to back them, and then share those Arrays.
Edit: Thanks for posting Counted. Took a bit of work, but I think I see what's going on.
Solution: Don't declare L_PATTERNS_ or L_AND_G_PATTERNS_ as const. Alternately, const_cast to get the desired operator[]. E.g.
const_cast<ArrayRef<ArrayRef<int> > &>(L_PATTERNS_)[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
Rationale:
In AbstractReader, you declare:
const ArrayRef<ArrayRef<int> > L_PATTERNS_;
Then in its constructor, you attempt an assignment:
AbstractReader::AbstractReader() :
{
...
L_PATTERNS_[i] = ArrayRef<int> ((L_PATTERNS[i]), 4);
...
}
Since L_PATTERNS_ is const, L_PATTERNS_[i] invokes a method from ArrayRef<ArrayRef<int> >:
T operator[](size_t i) const { return (*array_)[i]; }
This returns a brand new copy of what was at L_PATTERNS_[i]. The assignment then occurs (into a temporary), leaving the original unchanged. When you later go back to access L_PATTERNS_[xxx], you're looking at the original, uninitialized value (which is a NULL reference/pointer). Thus the segfault.
Somewhat surprising is that ArrayRef even allows this assignment. Certainly it breaks the "Principle of Least Surprise". One would expect the compiler to issue an error. To make sure that the compiler is more helpful in the future, we need to give a slightly different definition of ArrayRef's operator[] const (Array.h:121), such as:
const T operator[](size_t i) const { return (*array_)[i]; }
or perhaps (with caveats):
const T& operator[](size_t i) const { return (*array_)[i]; }
After making either change, the compiler disallows allow the assignment. GCC, for example, reports:
error: passing 'const common::ArrayRef<int>' as 'this' argument of 'common::ArrayRef<T>& common::ArrayRef<T>::operator=(const common::ArrayRef<T>&) [with T = int]' discards qualifiers
Causes may be several. For instance, you don't include in your paste the "Counted" class, and at some point, a->retain() is called (line 130). This method is not shown.