/* Test the method 'scaleSize'.*/ TEST_F(PositionVectorTest, test_method_scaleSize) { PositionVector square; square.push_back(Position(0,0)); square.push_back(Position(1,0)); square.push_back(Position(1,1)); square.push_back(Position(0,1)); square.push_back(Position(0,0)); EXPECT_DOUBLE_EQ(square.area(), 1); square.scaleSize(3); EXPECT_DOUBLE_EQ(square.area(), 9); PositionVector expected; expected.push_back(Position(-1,-1)); expected.push_back(Position(2,-1)); expected.push_back(Position(2,2)); expected.push_back(Position(-1,2)); expected.push_back(Position(-1,-1)); EXPECT_EQ(expected.getCentroid(), square.getCentroid()); for (size_t i = 0; i < square.size(); i++) { EXPECT_DOUBLE_EQ(expected[i].x(), square[i].x()); EXPECT_DOUBLE_EQ(expected[i].y(), square[i].y()); } }
Position PositionVector::getCentroid() const { PositionVector tmp = *this; if (!isClosed()) { // make sure its closed tmp.push_back(tmp[0]); } const int endIndex = (int)tmp.size() - 1; SUMOReal div = 0; // 6 * area including sign SUMOReal x = 0; SUMOReal y = 0; if (tmp.area() != 0) { // numerical instability ? // http://en.wikipedia.org/wiki/Polygon for (int i = 0; i < endIndex; i++) { const SUMOReal z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y(); div += z; // area formula x += (tmp[i].x() + tmp[i + 1].x()) * z; y += (tmp[i].y() + tmp[i + 1].y()) * z; } div *= 3; // 6 / 2, the 2 comes from the area formula return Position(x / div, y / div); } else { // compute by decomposing into line segments // http://en.wikipedia.org/wiki/Centroid#By_geometric_decomposition SUMOReal lengthSum = 0; for (int i = 0; i < endIndex; i++) { SUMOReal length = tmp[i].distanceTo(tmp[i + 1]); x += (tmp[i].x() + tmp[i + 1].x()) * length / 2; y += (tmp[i].y() + tmp[i + 1].y()) * length / 2; lengthSum += length; } if (lengthSum == 0) { // it is probably only one point return tmp[0]; } return Position(x / lengthSum, y / lengthSum); } }