I have a closed polygon, that has attribute parameters at each edge. These are stored at the point at the beginning of the following line segment. So, point[0] holds the attribute for the edge point[0] -> point[1].
Now, I want to reverse the polygon. The edge information, however, is now to be stored at a different point.
Here's a working solution for that problem:
#include <iostream>
#include <vector>
#include <algorithm>
// assume
struct Point{
double x,y;
int att;
void setAttribute(int i){att=i;}
int attribute()const{return att;}
};
// and in my class I have
std::vector<Point> m_PList;
// where the std::vector is a hybrid std::list/std::vector container. Anyway.
void reverseMyPoly(){
auto swapStuff = [](Point* a, const Point* b) {
a->setAttribute(b->attribute());
// there's a lot more attribute code here
};
auto copy = m_PList; // !! this one is expensive !!
std::reverse(m_PList.begin(), m_PList.end());
const size_t n = m_PList.size();
// Each point i in the reversed polygon gets the edge_type that was
// originally associated with the edge from (i+1) % n to (i) % n
for (size_t i = 0; i < n; ++i) {
size_t original_index = (n - i - 2 + n) % n;
swapStuff(&m_PList[i], ©[original_index]);
}
}
int main()
{
m_PList = {{0,0,0}, {1,0,1}, {2,2,2}, {0,3,3}};
reverseMyPoly();
for(auto&p:m_PList){
std::cout << p.x <<", "<<p.y<<" ("<<p.attribute() <<")"<<std::endl;
}
return 0;
}
You see, each edge (I put either x or y as the original point index) has the lower point index as an attribute. So edge 2->3 must have attribute 2. The reversed edge 3->2 must have the attribute 2 at it's beginning point.
My method, however, requires a full copy of the polygon. I wish there was a solution to bypass this.
As you noted, reversing the polygon swaps the leading point for each edge. Edge (0, 1)
becomes (1, 0)
, (1, 2)
becomes (2, 1)
, and so on. To keep edge attributes consistent, point 1 must now have the attribute for point 0, and so on. Generalizing, points[i].attribute = points[(i - 1) % n].attribute
. Or, in the reversed polygon, reversedPoints[i].attribute = reversedPoints[(i + 1) % n].attribute
.
This can be implemented in a loop, as long as you account for the fact that the last point will need the attribute of the first point, which would have been overwritten earlier.
std::reverse(m_PList.begin(), m_PList.end());
const size_t n = m_PList.size();
const auto firstAttribute = m_PList[0].attribute();
for (size_t i = 0; i < n - 1; ++i) {
m_PList[i].setAttribute(m_PList[i+1].attribute());
}
m_PList[n-1].setAttribute(firstAttribute);
An alternative approach is to simply swap the attributes of consecutive points. This lets the first point's attribute "bubble up" to the last point without any special handling.
auto swapStuff = [](Point* a, Point* b) {
const auto bAttribute = b->attribute();
b->setAttribute(a->attribute());
a->setAttribute(bAttribute);
// there's a lot more attribute code here
};
std::reverse(m_PList.begin(), m_PList.end());
const size_t n = m_PList.size();
// Each point i in the reversed polygon gets the edge_type that was
// originally associated with the edge from (i-1) % n to (i) % n
// This was stored at (i-1) % n in the original list, (i+1) % n in the reversed list
for (size_t i = 0; i < n - 1; ++i) {
swapStuff(&m_PList[i], &m_PList[i+1]);
}