57 std::copy(v.begin(), v.end(), std::back_inserter(*
this));
62 std::copy(beg, end, std::back_inserter(*
this));
87 for (const_iterator i = begin(); i != (end() - 1); i++) {
93 (i + 1)->y() - p.
y());
98 (end() - 1)->x() - p.
x(),
99 (end() - 1)->y() - p.
y());
101 begin()->x() - p.
x(),
102 begin()->y() - p.
y());
105 return (!(fabs(angle) <
M_PI));
119 for (const_iterator i = begin(); i != end() - 1; i++) {
120 if (poly.
crosses(*i, *(i + 1))) {
124 if (size() > 2 && poly.
crosses(back(), front())) {
135 if ((size() == 0) || (poly.size() == 0)) {
139 for (const_iterator i = begin(); i != end() - 1; i++) {
142 if (fabs(closest.
z() - (*i).z()) < zThreshold) {
148 for (const_iterator i = poly.begin(); i != poly.end() - 1; i++) {
151 if (fabs(closest.
z() - (*i).z()) < zThreshold) {
165 for (const_iterator i = begin(); i != end() - 1; i++) {
179 for (const_iterator i = begin(); i != end() - 1; i++) {
190 for (const_iterator i = begin(); i != end() - 1; i++) {
192 if (
intersects(*i, *(i + 1), p1, p2, withinDist, &x, &y, &m)) {
202 for (const_iterator i = begin(); i != end() - 1; i++) {
220 if (index >= 0 && index < (
int)size()) {
222 }
else if (index < 0 && -index <= (
int)size()) {
223 return at((
int)size() + index);
239 if (index >= 0 && index < (
int)size()) {
241 }
else if (index < 0 && -index <= (
int)size()) {
242 return at((
int)size() + index);
257 const_iterator i = begin();
258 double seenLength = 0;
260 const double nextLength = (*i).distanceTo(*(i + 1));
261 if (seenLength + nextLength > pos) {
264 seenLength += nextLength;
265 }
while (++i != end() - 1);
266 if (lateralOffset == 0 || size() < 2) {
269 return positionAtOffset(*(end() - 2), *(end() - 1), (*(end() - 2)).distanceTo(*(end() - 1)), lateralOffset);
282 const_iterator i = begin();
283 double seenLength = 0;
285 const double nextLength = (*i).distanceTo(*(i + 1));
286 if (seenLength + nextLength > pos) {
289 seenLength += nextLength;
290 }
while (++i != end() - 1);
291 return sidePositionAtAngle(*(end() - 2), *(end() - 1), (*(end() - 2)).distanceTo(*(end() - 1)), lateralOffset, angle);
303 const_iterator i = begin();
304 double seenLength = 0;
306 const double nextLength = (*i).distanceTo2D(*(i + 1));
307 if (seenLength + nextLength > pos) {
310 seenLength += nextLength;
311 }
while (++i != end() - 1);
318 if ((size() == 0) || (size() == 1)) {
324 const_iterator i = begin();
325 double seenLength = 0;
330 if (seenLength + nextLength > pos) {
333 seenLength += nextLength;
334 }
while (++i != end() - 1);
352 const_iterator i = begin();
353 double seenLength = 0;
358 if (seenLength + nextLength > pos) {
361 seenLength += nextLength;
362 }
while (++i != end() - 1);
372 if (pos < 0. || dist < pos) {
375 if (lateralOffset != 0) {
383 return p1 + (p2 - p1) * (pos / dist) + offset;
388 return p1 + (p2 - p1) * (pos / dist);
395 if (pos < 0. || dist < pos || dist == 0) {
399 const Position offset(cos(angle) * lateralOffset, sin(angle) * lateralOffset);
400 return p1 + (p2 - p1) * (pos / dist) + offset;
407 if (pos < 0 || dist < pos) {
410 if (lateralOffset != 0) {
415 return p1 + (p2 - p1) * (pos / dist) + offset;
420 return p1 + (p2 - p1) * (pos / dist);
447 return Position(x / (
double) size(), y / (
double) size(), z / (
double)size());
455 }
else if (size() == 1) {
457 }
else if (size() == 2) {
458 return ((*
this)[0] + (*
this)[1]) * 0.5;
462 tmp.push_back(tmp[0]);
468 const int endIndex = (int)tmp.size() - 1;
472 if (tmp.
area() != 0) {
474 for (
int i = 0; i < endIndex; i++) {
475 const double z = tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
477 x += (tmp[i].x() + tmp[i + 1].x()) * z;
478 y += (tmp[i].y() + tmp[i + 1].y()) * z;
481 result =
Position(x / div, y / div);
485 double lengthSum = 0;
486 for (
int i = 0; i < endIndex; i++) {
487 double length = tmp[i].distanceTo(tmp[i + 1]);
488 x += (tmp[i].x() + tmp[i + 1].x()) *
length / 2;
489 y += (tmp[i].y() + tmp[i + 1].y()) *
length / 2;
492 if (lengthSum == 0) {
496 result =
Position(x / lengthSum, y / lengthSum) + offset;
498 return result + offset;
505 for (
int i = 0; i < static_cast<int>(size()); i++) {
506 (*this)[i] = centroid + (((*this)[i] - centroid) * factor);
514 for (
int i = 0; i < static_cast<int>(size()); i++) {
515 (*this)[i] = centroid + (((*this)[i] - centroid) + offset);
536 for (const_iterator i = begin(); i != end() - 1; i++) {
537 len += (*i).distanceTo(*(i + 1));
549 for (const_iterator i = begin(); i != end() - 1; i++) {
550 len += (*i).distanceTo2D(*(i + 1));
564 tmp.push_back(tmp[0]);
566 const int endIndex = (int)tmp.size() - 1;
568 for (
int i = 0; i < endIndex; i++) {
569 area += tmp[i].x() * tmp[i + 1].y() - tmp[i + 1].x() * tmp[i].y();
583 for (const_iterator i = begin(); i != end(); i++) {
584 if (poly.
around(*i, offset)) {
598std::pair<PositionVector, PositionVector>
604 if (where < 0 || where > len) {
607 if (where <= POSITION_EPS || where >= len - POSITION_EPS) {
611 first.push_back((*
this)[0]);
613 const_iterator it = begin() + 1;
614 double next = use2D ? first.back().distanceTo2D(*it) : first.back().distanceTo(*it);
616 while (where >= seen + next + POSITION_EPS) {
618 first.push_back(*it);
620 next = use2D ? first.back().distanceTo2D(*it) : first.back().distanceTo(*it);
622 if (fabs(where - (seen + next)) > POSITION_EPS || it == end() - 1) {
631 first.push_back(*it);
634 for (; it != end(); it++) {
635 second.push_back(*it);
637 assert(first.size() >= 2);
638 assert(second.size() >= 2);
639 assert(first.back() == second.front());
641 return std::pair<PositionVector, PositionVector>(first, second);
647 for (PositionVector::const_iterator i = geom.begin(); i != geom.end(); i++) {
648 if (i != geom.begin()) {
663 const Position centroid = std::accumulate(begin(), end(),
Position(0, 0)) / (double)size();
672 for (
int i = 0; i < (int)size(); i++) {
673 (*this)[i].add(xoff, yoff, zoff);
680 add(-offset.
x(), -offset.
y(), -offset.
z());
686 add(offset.
x(), offset.
y(), offset.
z());
693 for (
auto i1 = begin(); i1 != end(); ++i1) {
694 pv.push_back(*i1 + offset);
702 for (
int i = 0; i < (int)size(); i++) {
703 (*this)[i].mul(1, -1);
713 double angle1 = atAngle2D(p1);
714 double angle2 = atAngle2D(p2);
715 if (angle1 > angle2) {
718 if (angle1 == angle2) {
721 if (squaredDistance1 < squaredDistance2) {
731 double angle = atan2(p.
y(), p.
x());
732 return angle < 0.0 ? angle : angle + 2.0 *
M_PI;
746 if (p1.
x() != p2.
x()) {
747 return p1.
x() < p2.
x();
749 return p1.
y() < p2.
y();
755 return (P1.
x() - P0.
x()) * (P2.
y() - P0.
y()) - (P2.
x() - P0.
x()) * (P1.
y() - P0.
y());
761 if ((size() > 0) && (v.size() > 0) && (back().distanceTo(v[0]) < sameThreshold)) {
762 copy(v.begin() + 1, v.end(), back_inserter(*
this));
764 copy(v.begin(), v.end(), back_inserter(*
this));
771 if ((size() > 0) && (v.size() > 0) && (front().distanceTo(v.back()) < sameThreshold)) {
772 insert(begin(), v.begin(), v.end() - 1);
774 insert(begin(), v.begin(), v.end());
783 if (beginOffset > POSITION_EPS) {
787 if (endOffset <
length() - POSITION_EPS) {
790 ret.push_back(begPos);
793 const_iterator i = begin();
795 while ((i + 1) != end()
797 seen + (*i).distanceTo(*(i + 1)) < beginOffset) {
798 seen += (*i).distanceTo(*(i + 1));
802 while ((i + 1) != end()
804 seen + (*i).distanceTo(*(i + 1)) < endOffset) {
807 seen += (*i).distanceTo(*(i + 1));
812 if (ret.size() == 1) {
813 ret.push_back(endPos);
826 if (beginOffset > POSITION_EPS) {
830 if (endOffset <
length2D() - POSITION_EPS) {
833 ret.push_back(begPos);
836 const_iterator i = begin();
838 while ((i + 1) != end()
840 seen + (*i).distanceTo2D(*(i + 1)) < beginOffset) {
841 seen += (*i).distanceTo2D(*(i + 1));
845 while ((i + 1) != end()
847 seen + (*i).distanceTo2D(*(i + 1)) < endOffset) {
850 seen += (*i).distanceTo2D(*(i + 1));
855 if (ret.size() == 1) {
856 ret.push_back(endPos);
867 if (beginIndex < 0) {
868 beginIndex += (int)size();
871 assert(beginIndex < (
int)size());
872 assert(beginIndex + count <= (
int)size());
874 for (
int i = beginIndex; i < beginIndex + count; ++i) {
875 result.push_back((*
this)[i]);
886 return front().angleTo2D(back());
895 double minDist = std::numeric_limits<double>::max();
898 for (const_iterator i = begin(); i != end() - 1; i++) {
902 if (dist2 < minDist) {
903 nearestPos = pos + seen;
909 if (cornerDist2 < minDist) {
914 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
916 minDist = cornerDist2;
920 seen += (*i).distanceTo2D(*(i + 1));
931 double minDist = std::numeric_limits<double>::max();
934 for (const_iterator i = begin(); i != end() - 1; i++) {
938 if (dist < minDist) {
939 const double pos25D = pos * (*i).distanceTo(*(i + 1)) / (*i).distanceTo2D(*(i + 1));
940 nearestPos = pos25D + seen;
946 if (cornerDist < minDist) {
951 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
953 minDist = cornerDist;
957 seen += (*i).distanceTo(*(i + 1));
975 double minDist = std::numeric_limits<double>::max();
976 double nearestPos = -1;
979 for (const_iterator i = begin(); i != end() - 1; i++) {
983 if (dist < minDist) {
984 nearestPos = pos + seen;
986 sign =
isLeft(*i, *(i + 1), p) >= 0 ? -1 : 1;
991 if (cornerDist < minDist) {
996 if (pos1 == (*(i - 1)).distanceTo2D(*i) && pos2 == 0.) {
998 minDist = cornerDist;
999 sign =
isLeft(*(i - 1), *i, p) >= 0 ? -1 : 1;
1003 seen += (*i).distanceTo2D(*(i + 1));
1005 if (nearestPos != -1) {
1006 return Position(nearestPos, sign * minDist);
1018 double minDist = std::numeric_limits<double>::max();
1021 for (
int i = 0; i < (int)size(); i++) {
1024 if (dist < minDist) {
1038 double minDist = std::numeric_limits<double>::max();
1039 int insertionIndex = 1;
1040 for (
int i = 0; i < (int)size() - 1; i++) {
1044 if (dist < minDist) {
1045 insertionIndex = i + 1;
1052 const double previousZ = (begin() + (insertionIndex - 1))->z();
1053 const double nextZ = (begin() + insertionIndex)->z();
1055 insert(begin() + insertionIndex,
Position(p.
x(), p.
y(), ((previousZ + nextZ) / 2.0)));
1057 insert(begin() + insertionIndex, p);
1059 return insertionIndex;
1068 double minDist = std::numeric_limits<double>::max();
1069 int removalIndex = 0;
1070 for (
int i = 0; i < (int)size(); i++) {
1072 if (dist < minDist) {
1077 erase(begin() + removalIndex);
1078 return removalIndex;
1084 std::vector<double> ret;
1085 if (other.size() == 0) {
1088 for (const_iterator i = other.begin(); i != other.end() - 1; i++) {
1090 copy(atSegment.begin(), atSegment.end(), back_inserter(ret));
1098 std::vector<double> ret;
1103 for (const_iterator i = begin(); i != end() - 1; i++) {
1107 if (
intersects(p1, p2, lp1, lp2, 0., &x, &y, &m)) {
1163 for (const_reverse_iterator i = rbegin(); i != rend(); i++) {
1173 return Position((beg.
y() - end.
y()) * scale, (end.
x() - beg.
x()) * scale);
1183 if (
length2D() == 0 || amount == 0) {
1187 std::vector<int> recheck;
1188 for (
int i = 0; i < static_cast<int>(size()); i++) {
1191 const Position& to = (*this)[i + 1];
1193 shape.push_back(from -
sideOffset(from, to, amount));
1194#ifdef DEBUG_MOVE2SIDE
1196 std::cout <<
" " << i <<
"a=" << shape.back() <<
"\n";
1200 }
else if (i ==
static_cast<int>(size()) - 1) {
1201 const Position& from = (*this)[i - 1];
1204 shape.push_back(to -
sideOffset(from, to, amount));
1205#ifdef DEBUG_MOVE2SIDE
1207 std::cout <<
" " << i <<
"b=" << shape.back() <<
"\n";
1212 const Position& from = (*this)[i - 1];
1214 const Position& to = (*this)[i + 1];
1217 const double extrapolateDev = fromMe[1].distanceTo2D(to);
1218 if (fabs(extrapolateDev) < POSITION_EPS) {
1220 shape.push_back(me -
sideOffset(from, to, amount));
1221#ifdef DEBUG_MOVE2SIDE
1223 std::cout <<
" " << i <<
"c=" << shape.back() <<
"\n";
1226 }
else if (fabs(extrapolateDev - 2 * me.
distanceTo2D(to)) < POSITION_EPS) {
1230 shape.push_back(fromMe2[1]);
1231#ifdef DEBUG_MOVE2SIDE
1233 std::cout <<
" " << i <<
"d=" << shape.back() <<
" " << i <<
"_from=" << from <<
" " << i <<
"_me=" << me <<
" " << i <<
"_to=" << to <<
"\n";
1243 recheck.push_back(i);
1247 shape.push_back(meNew);
1248#ifdef DEBUG_MOVE2SIDE
1250 std::cout <<
" " << i <<
"e=" << shape.back() <<
"\n";
1255 shape.back().set(shape.back().x(), shape.back().y(), me.
z());
1256 const double angle =
localAngle(from, me, to);
1257 if (fabs(angle) > NUMERICAL_EPS) {
1259 const double radius =
length / angle;
1260#ifdef DEBUG_MOVE2SIDE
1262 std::cout <<
" i=" << i <<
" a=" <<
RAD2DEG(angle) <<
" l=" <<
length <<
" r=" << radius <<
" t=" << amount * 1.8 <<
"\n";
1265 if ((radius < 0 && -radius < amount * 1.8) || fabs(
RAD2DEG(angle)) > 170) {
1266 recheck.push_back(i);
1271 if (!recheck.empty()) {
1274 for (
int i = (
int)recheck.size() - 1; i >= 0; i--) {
1275 shape.erase(shape.begin() + recheck[i]);
1291 if (size() != amount.size()) {
1293 +
") does not match number of points (" +
toString(size()) +
")");
1296 for (
int i = 0; i < static_cast<int>(size()); i++) {
1299 const Position& to = (*this)[i + 1];
1301 shape.push_back(from -
sideOffset(from, to, amount[i]));
1303 }
else if (i ==
static_cast<int>(size()) - 1) {
1304 const Position& from = (*this)[i - 1];
1307 shape.push_back(to -
sideOffset(from, to, amount[i]));
1310 const Position& from = (*this)[i - 1];
1312 const Position& to = (*this)[i + 1];
1315 const double extrapolateDev = fromMe[1].distanceTo2D(to);
1316 if (fabs(extrapolateDev) < POSITION_EPS) {
1318 shape.push_back(me -
sideOffset(from, to, amount[i]));
1319 }
else if (fabs(extrapolateDev - 2 * me.
distanceTo2D(to)) < POSITION_EPS) {
1323 shape.push_back(fromMe2[1]);
1334 shape.push_back(meNew);
1337 shape.back().set(shape.back().x(), shape.back().y(), me.
z());
1350 if ((pos + 1) < (
int)size()) {
1351 return (*
this)[pos].angleTo2D((*
this)[pos + 1]);
1359 if ((size() != 0) && ((*
this)[0] != back())) {
1360 push_back((*
this)[0]);
1367 std::vector<double> ret;
1369 for (i = begin(); i != end(); i++) {
1370 const double dist = s.
distance2D(*i, perpendicular);
1372 ret.push_back(dist);
1375 for (i = s.begin(); i != s.end(); i++) {
1376 const double dist =
distance2D(*i, perpendicular);
1378 ret.push_back(dist);
1388 return std::numeric_limits<double>::max();
1389 }
else if (size() == 1) {
1390 return front().distanceTo2D(p);
1431 if ((size() == 0) || !p.
almostSame(front())) {
1439 if (at == begin()) {
1441 }
else if (at == end()) {
1453 return (size() >= 2) && ((*this)[0] == back());
1460 for (
auto i = begin(); i != end(); i++) {
1472 int curSize = (int)size() - beginOffset - endOffset;
1474 iterator last = begin() + beginOffset;
1475 for (iterator i = last + 1; i != (end() - endOffset) && (!assertLength || curSize > 2);) {
1476 if (last->almostSame(*i, minDist)) {
1477 if (i + 1 == end() - endOffset) {
1479 if (
resample && last > begin() && (last - 1)->distanceTo(*i) >= 2 * minDist) {
1481 const double shiftBack = minDist - last->distanceTo(*i);
1483 (*last) =
positionAtOffset(*(last - 1), *last, (last - 1)->distanceTo(*last) - shiftBack);
1489 i = end() - endOffset;
1492 if (
resample && i + 1 != end() && last->distanceTo(*(i + 1)) >= 2 * minDist) {
1494 const double shiftForward = minDist - last->distanceTo(*i);
1516 return static_cast<vp>(*this) ==
static_cast<vp>(v2);
1522 return static_cast<vp>(*this) !=
static_cast<vp>(v2);
1528 WRITE_ERROR(
TL(
"Trying to subtract PositionVectors of different lengths."));
1532 auto i2 = v2.begin();
1533 while (i1 != end()) {
1542 WRITE_ERROR(
TL(
"Trying to add PositionVectors of different lengths."));
1546 auto i2 = v2.begin();
1547 while (i1 != end()) {
1555 if (size() != v2.size()) {
1558 auto i2 = v2.begin();
1559 for (
auto i1 = begin(); i1 != end(); i1++) {
1560 if (!i1->almostSame(*i2, maxDiv)) {
1573 for (const_iterator i = begin(); i != end(); i++) {
1574 if ((*i).z() != 0) {
1584 const double eps = std::numeric_limits<double>::epsilon();
1585 const double denominator = (p22.
y() - p21.
y()) * (p12.
x() - p11.
x()) - (p22.
x() - p21.
x()) * (p12.
y() - p11.
y());
1586 const double numera = (p22.
x() - p21.
x()) * (p11.
y() - p21.
y()) - (p22.
y() - p21.
y()) * (p11.
x() - p21.
x());
1587 const double numerb = (p12.
x() - p11.
x()) * (p11.
y() - p21.
y()) - (p12.
y() - p11.
y()) * (p11.
x() - p21.
x());
1589 if (fabs(numera) < eps && fabs(numerb) < eps && fabs(denominator) < eps) {
1595 if (p11.
x() != p12.
x()) {
1596 a1 = p11.
x() < p12.
x() ? p11.
x() : p12.
x();
1597 a2 = p11.
x() < p12.
x() ? p12.
x() : p11.
x();
1598 a3 = p21.
x() < p22.
x() ? p21.
x() : p22.
x();
1599 a4 = p21.
x() < p22.
x() ? p22.
x() : p21.
x();
1601 a1 = p11.
y() < p12.
y() ? p11.
y() : p12.
y();
1602 a2 = p11.
y() < p12.
y() ? p12.
y() : p11.
y();
1603 a3 = p21.
y() < p22.
y() ? p21.
y() : p22.
y();
1604 a4 = p21.
y() < p22.
y() ? p22.
y() : p21.
y();
1606 if (a1 <= a3 && a3 <= a2) {
1613 if (a3 <= a1 && a1 <= a4) {
1622 if (p11.
x() != p12.
x()) {
1623 *mu = (a - p11.
x()) / (p12.
x() - p11.
x());
1625 *y = p11.
y() + (*mu) * (p12.
y() - p11.
y());
1629 if (p12.
y() == p11.
y()) {
1632 *mu = (a - p11.
y()) / (p12.
y() - p11.
y());
1641 if (fabs(denominator) < eps) {
1645 double mua = numera / denominator;
1647 if (fabs(p12.
x() - p22.
x()) < eps && fabs(p12.
y() - p22.
y()) < eps) {
1650 const double offseta = withinDist / p11.
distanceTo2D(p12);
1651 const double offsetb = withinDist / p21.
distanceTo2D(p22);
1652 const double mub = numerb / denominator;
1653 if (mua < -offseta || mua > 1 + offseta || mub < -offsetb || mub > 1 + offsetb) {
1658 *x = p11.
x() + mua * (p12.
x() - p11.
x());
1659 *y = p11.
y() + mua * (p12.
y() - p11.
y());
1668 const double s = sin(angle);
1669 const double c = cos(angle);
1670 for (
int i = 0; i < (int)size(); i++) {
1671 const double x = (*this)[i].x();
1672 const double y = (*this)[i].y();
1673 const double z = (*this)[i].z();
1674 const double xnew = x * c - y * s;
1675 const double ynew = x * s + y * c;
1676 (*this)[i].set(xnew, ynew, z);
1696 bool changed =
true;
1697 while (changed && result.size() > 3) {
1699 for (
int i = 0; i < (int)result.size(); i++) {
1701 const Position& p2 = result[(i + 2) % result.size()];
1702 const int middleIndex = (i + 1) % result.size();
1703 const Position& p0 = result[middleIndex];
1705 const double triangleArea2 = fabs((p2.
y() - p1.
y()) * p0.
x() - (p2.
x() - p1.
x()) * p0.
y() + p2.
x() * p1.
y() - p2.
y() * p1.
x());
1707 if (distIK > NUMERICAL_EPS && triangleArea2 / distIK < NUMERICAL_EPS) {
1709 result.erase(result.begin() + middleIndex);
1729 if (!closed && (index == 0 || index == (
int)pv.size() - 1)) {
1733 const Position& a = pv[(index + (int)pv.size() - 1) % pv.size()];
1734 const Position& b = pv[(index + 1) % pv.size()];
1736 if (distAB <
MIN2(eps, NUMERICAL_EPS)) {
1742 const Position dir = (b - a) / distAB;
1743 const double projectedLength = (a - p).dotProduct(dir);
1744 if (projectedLength <= -distAB) {
1747 if (projectedLength >= 0.) {
1750 const Position distVector = (a - p) - dir * projectedLength;
1751 return distVector.
length();
1753 std::vector<double> scores;
1754 double minScore = eps + 1.;
1756 for (
int i = 0; i < (int)size(); i++) {
1757 scores.push_back(calcScore(*
this, i));
1758 if (scores.back() < minScore) {
1759 minScore = scores.back();
1763 if (minScore >= eps) {
1767 while (minScore < eps) {
1768 result.erase(result.begin() + minIndex);
1769 if (result.size() < 3) {
1772 scores.erase(scores.begin() + minIndex);
1773 const int prevIndex = (minIndex + (int)result.size() - 1) % result.size();
1774 scores[prevIndex] = calcScore(result, prevIndex);
1775 scores[minIndex % result.size()] = calcScore(result, minIndex % result.size());
1776 minScore = eps + 1.;
1777 for (
int i = 0; i < (int)result.size(); i++) {
1778 if (scores[i] < minScore) {
1779 minScore = scores[i];
1801 result.push_back(base);
1802 if (fabs(baseOffset - closestOffset) > NUMERICAL_EPS) {
1803 result.push_back(tmp[closestIndex]);
1804 if ((closestOffset < baseOffset) != before) {
1807 }
else if (before) {
1809 if (closestIndex > 0) {
1810 result.push_back(tmp[closestIndex - 1]);
1812 result.push_back(tmp[1]);
1817 if (closestIndex < (
int)size() - 1) {
1818 result.push_back(tmp[closestIndex + 1]);
1820 result.push_back(tmp[-1]);
1826 result.
add(base * -1);
1839 const double z0 = (*this)[0].z();
1841 const double dz = (*this)[1].z() - z0;
1843 if (size() > 2 && dz != 0) {
1849 if (pDist.
distanceTo2D((*
this)[iLast]) > POSITION_EPS * 20) {
1853 const double dz2 = result[iLast].z() - z0;
1855 for (
int i = 1; i < iLast; ++i) {
1856 seen += result[i].distanceTo2D(result[i - 1]);
1857 result[i].set(result[i].x(), result[i].y(), z0 + dz2 * seen / dist2);
1871 result[0].setz(zStart);
1872 result[-1].setz(zEnd);
1873 const double dz = zEnd - zStart;
1876 for (
int i = 1; i < (int)size() - 1; ++i) {
1877 seen += result[i].distanceTo2D(result[i - 1]);
1878 result[i].setz(zStart + dz * seen /
length);
1887 if (maxLength == 0) {
1891 if (
length < POSITION_EPS) {
1895 for (
double pos = 0; pos <=
length; pos += maxLength) {
1899 if (adjustEnd && !result.empty() && (result.back() != back())) {
1901 result.push_back(back());
1909 if (index < 0 || index >= (
int)size()) {
1913 for (
int i = 1; i <= index; ++i) {
1914 seen += (*this)[i].distanceTo2D((*
this)[i - 1]);
1923 for (
int i = 1; i < (int)size(); ++i) {
1924 const Position& p1 = (*this)[i - 1];
1926 const double distZ = fabs(p1.
z() - p2.
z());
1929 maxJump =
MAX2(maxJump, distZ);
1931 result =
MAX2(result, distZ / dist2D);
1940 double minZ = std::numeric_limits<double>::max();
1942 minZ =
MIN2(minZ, i.z());
1951 assert(size() < 33);
1952 static const double fac[33] = {
1953 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, 479001600.0,
1954 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, 355687428096000.0, 6402373705728000.0,
1955 121645100408832000.0, 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0,
1956 25852016738884976640000.0, 620448401733239439360000.0, 15511210043330985984000000.0,
1957 403291461126605635584000000.0, 10888869450418352160768000000.0, 304888344611713860501504000000.0,
1958 8841761993739701954543616000000.0, 265252859812191058636308480000000.0,
1959 8222838654177922817725562880000000.0, 263130836933693530167218012160000000.0
1962 const int npts = (int)size();
1964 const double step = (double) 1.0 / (numPoints - 1);
1967 for (
int i1 = 0; i1 < numPoints; i1++) {
1968 if ((1.0 - t) < 5e-6) {
1971 double x = 0., y = 0., z = 0.;
1972 for (
int i = 0; i < npts; i++) {
1973 const double ti = (i == 0) ? 1.0 : pow(t, i);
1974 const double tni = (npts == i + 1) ? 1.0 : pow(1 - t, npts - i - 1);
1975 const double basis = fac[npts - 1] / (fac[i] * fac[npts - 1 - i]) * ti * tni;
1976 x += basis * at(i).x();
1977 y += basis * at(i).y();
1978 z += basis * at(i).z();
1982 if (prev != current && !std::isnan(x) && !std::isnan(y) && !std::isnan(z)) {
1983 ret.push_back(current);
1998 const double y_min = std::min_element(begin(), end(), [](
Position p1,
Position p2) {
1999 return p1.
y() < p2.
y();
2001 const double gap = y_min > 0.0 ? 0.0 : y_min;
2003 const int last = (int)size() - 1;
2004 for (
int i = 0; i < last; i++) {
2005 const Position& firstPoint = at(i);
2006 const Position& secondPoint = at(i + 1);
2007 area += (secondPoint.
x() - firstPoint.
x()) / (secondPoint.
y() + firstPoint.
y()) / 2.0;
2009 area += (at(0).x() - at(last).x()) / (at(0).y() + at(last).y()) / 2.0;
#define WRITE_WARNINGF(...)
std::ostream & operator<<(std::ostream &os, const PositionVector &geom)
bool gDebugFlag1
global utility flags for debugging
const double INVALID_DOUBLE
invalid double
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
virtual bool partialWithin(const AbstractPoly &poly, double offset=0) const =0
Returns whether the AbstractPoly is partially within the given polygon.
virtual bool crosses(const Position &p1, const Position &p2) const =0
Returns whether the AbstractPoly crosses the given line.
virtual bool around(const Position &p, double offset=0) const =0
Returns whether the AbstractPoly the given coordinate.
A class that stores a 2D geometrical boundary.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
static double angle2D(const Position &p1, const Position &p2)
Returns the angle between two vectors on a plane The angle is from vector 1 to vector 2,...
static const double INVALID_OFFSET
a value to signify offsets outside the range of [0, Line.length()]
static double nearest_offset_on_line_to_point2D(const Position &lineStart, const Position &lineEnd, const Position &p, bool perpendicular=true)
static double legacyDegree(const double angle, const bool positive=false)
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
A point in 2D or 3D with translation and scaling methods.
double length() const
Computes the length of the given vector.
double distanceSquaredTo2D(const Position &p2) const
returns the square of the distance to another position (Only using x and y positions)
double slopeTo2D(const Position &other) const
returns the slope of the vector pointing from here to the other position (in radians between -M_PI an...
double dotProduct(const Position &pos) const
returns the dot product (scalar product) between this point and the second one
static const Position INVALID
used to indicate that a position is valid
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimensions
void sub(double dx, double dy)
Subtracts the given position from this one.
double x() const
Returns the x-position.
void add(const Position &pos)
Adds the given position to this one.
double z() const
Returns the z-position.
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
bool almostSame(const Position &p2, double maxDiv=POSITION_EPS) const
check whether the other position has a euclidean distance of less than maxDiv
double y() const
Returns the y-position.
int operator()(const Position &p1, const Position &p2) const
comparing operation for sort
double atAngle2D(const Position &p) const
computes the angle of the given vector, in the range $[0,2*\pi[$
as_poly_cw_sorter()
constructor
clase for increasing Sorter
increasing_x_y_sorter()
constructor
int operator()(const Position &p1, const Position &p2) const
comparing operation
bool isClockwiseOriented(void)
PositionVector operator-(const PositionVector &v2) const
subtracts two vectors (requires vectors of the same length)
void scaleAbsolute(double offset)
enlarges/shrinks the polygon by an absolute offset based at the centroid
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns the information whether the given polygon overlaps with this.
PositionVector added(const Position &offset) const
double isLeft(const Position &P0, const Position &P1, const Position &P2) const
get left
double beginEndAngle() const
returns the angle in radians of the line connecting the first and the last position
double getMinZ() const
return minimum z-coordinate
double length() const
Returns the length.
void move2sideCustom(std::vector< double > amount, double maxExtension=100)
move position vector to side using a custom offset for each geometry point
void sortAsPolyCWByAngle()
sort as polygon CW by angle
PositionVector simplified() const
return the same shape with intermediate colinear points removed
void rotate2D(double angle)
PositionVector()
Constructor. Creates an empty position vector.
Position getPolygonCenter() const
Returns the arithmetic of all corner points.
Position intersectionPosition2D(const Position &p1, const Position &p2, const double withinDist=0.) const
Returns the position of the intersection.
const Position & operator[](int index) const
returns the constant position at the given index, negative indices are interpreted python style
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
std::vector< Position > vp
vector of position
void push_front_noDoublePos(const Position &p)
insert in front a non double position
bool operator!=(const PositionVector &v2) const
comparing operation
PositionVector resample(double maxLength, const bool adjustEnd) const
resample shape (i.e. transform to segments, equal spacing)
void sortByIncreasingXY()
sort by increasing X-Y Positions
double rotationDegreeAtOffset(double pos) const
Returns the rotation at the given length.
bool isNAN() const
check if PositionVector is NAN
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void add(double xoff, double yoff, double zoff)
void closePolygon()
ensures that the last position equals the first
static Position sideOffset(const Position &beg, const Position &end, const double amount)
get a side position of position vector using a offset
std::vector< double > intersectsAtLengths2D(const PositionVector &other) const
For all intersections between this vector and other, return the 2D-length of the subvector from this ...
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
void prepend(const PositionVector &v, double sameThreshold=2.0)
double nearest_offset_to_point2D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D
std::vector< double > distances(const PositionVector &s, bool perpendicular=false) const
distances of all my points to s and all of s points to myself
PositionVector getOrthogonal(const Position &p, double extend, bool before, double length=1.0, double deg=90) const
return orthogonal through p (extending this vector if necessary)
int indexOfClosest(const Position &p, bool twoD=false) const
std::pair< PositionVector, PositionVector > splitAt(double where, bool use2D=false) const
Returns the two lists made when this list vector is splitted at the given point.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
bool almostSame(const PositionVector &v2, double maxDiv=POSITION_EPS) const
check if the two vectors have the same length and pairwise similar positions
bool crosses(const Position &p1, const Position &p2) const
Returns whether the AbstractPoly crosses the given line.
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
PositionVector interpolateZ(double zStart, double zEnd) const
returned vector that varies z smoothly over its length
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
double offsetAtIndex2D(int index) const
return the offset at the given index
PositionVector smoothedZFront(double dist=std::numeric_limits< double >::max()) const
returned vector that is smoothed at the front (within dist)
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
void insert_noDoublePos(const std::vector< Position >::iterator &at, const Position &p)
insert in front a non double position
double slopeDegreeAtOffset(double pos) const
Returns the slope at the given length.
bool hasElevation() const
return whether two positions differ in z-coordinate
static const PositionVector EMPTY
empty Vector
void extrapolate(const double val, const bool onlyFirst=false, const bool onlyLast=false)
extrapolate position vector
PositionVector bezier(int numPoints)
return a bezier interpolation
Position getLineCenter() const
get line center
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
double getOverlapWith(const PositionVector &poly, double zThreshold) const
Returns the maximum overlaps between this and the given polygon (when not separated by at least zThre...
PositionVector operator+(const PositionVector &v2) const
adds two vectors (requires vectors of the same length)
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
void rotateAroundFirstElement2D(double angle)
int insertAtClosest(const Position &p, bool interpolateZ)
inserts p between the two closest positions
const PositionVector simplified2(const bool closed, const double eps=NUMERICAL_EPS) const
void push_front(const Position &p)
insert in front a Position
void scaleRelative(double factor)
enlarges/shrinks the polygon by a factor based at the centroid
void push_back_noDoublePos(const Position &p)
insert in back a non double position
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false, int beginOffset=0, int endOffset=0, bool resample=false)
Removes positions if too near.
bool partialWithin(const AbstractPoly &poly, double offset=0) const
Returns the information whether this polygon lies partially within the given polygon.
double getMaxGrade(double &maxJump) const
double area() const
Returns the area (0 for non-closed)
bool isClosed() const
check if PositionVector is closed
void pop_front()
pop first Position
double nearest_offset_to_point25D(const Position &p, bool perpendicular=true) const
return the nearest offest to point 2D projected onto the 3D geometry
int removeClosest(const Position &p)
removes the point closest to p and return the removal index
static double localAngle(const Position &from, const Position &pos, const Position &to)
Position sidePositionAtAngle(double pos, double lateralOffset, double angle) const
bool intersects(const Position &p1, const Position &p2) const
Returns the information whether this list of points interesects the given line.
PositionVector reverse() const
reverse position vector
PositionVector getSubpartByIndex(int beginIndex, int count) const
get subpart of a position vector using index and a cout
Position positionAtOffset2D(double pos, double lateralOffset=0) const
Returns the position at the given length.
bool operator==(const PositionVector &v2) const
comparing operation
void sub(const Position &offset)
PositionVector getSubpart(double beginOffset, double endOffset) const
get subpart of a position vector
~PositionVector()
Destructor.
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
Position transformToVectorCoordinates(const Position &p, bool extend=false) const
return position p within the length-wise coordinate system defined by this position vector....