36 #ifndef VIGRA_POLYGON_HXX
37 #define VIGRA_POLYGON_HXX
45 #include "tinyvector.hxx"
46 #include "array_vector.hxx"
47 #include "gaussians.hxx"
48 #include "splines.hxx"
49 #include "linear_solve.hxx"
55 template <
class Po
int >
56 bool pointYXOrdering(Point
const & p1, Point
const & p2)
58 return (p1[1]<p2[1]) || (p1[1] == p2[1] && p1[0] < p2[0]);
61 template <
class Po
int >
62 bool orderedClockwise(
const Point &O,
const Point &A,
const Point &B)
64 return (A[0] - O[0]) * (B[1] - O[1]) - (A[1] - O[1]) * (B[0] - O[0]) <= 0;
77 template<
class POINT=TinyVector<
double, 2> >
85 typedef typename Base::value_type value_type;
86 typedef typename Base::reference reference;
87 typedef typename Base::const_reference const_reference;
88 typedef typename Base::pointer pointer;
89 typedef typename Base::const_pointer const_pointer;
90 typedef typename Base::iterator iterator;
91 typedef typename Base::const_iterator const_iterator;
92 typedef typename Base::reverse_iterator reverse_iterator;
93 typedef typename Base::const_reverse_iterator const_reverse_iterator;
94 typedef typename Base::size_type size_type;
95 typedef typename Base::difference_type difference_type;
96 typedef typename POINT::value_type coordinate_type;
115 partialAreaValid_(
false)
121 partialAreaValid_(
false)
124 template <
class InputIterator>
125 Polygon(InputIterator b, InputIterator e)
128 partialAreaValid_(
false)
133 invalidateProperties();
137 void invalidateProperties()
139 lengthValid_ =
false;
140 partialAreaValid_ =
false;
143 double length()
const
148 for(
unsigned int i = 1; i <
size(); ++i)
149 length_ += ((*
this)[i] - (*this)[i-1]).magnitude();
155 double partialArea()
const
157 if(!partialAreaValid_)
160 for(
unsigned int i = 1; i <
size(); ++i)
161 partialArea_ += ((*
this)[i][0]*(*this)[i-1][1] -
162 (*this)[i][1]*(*this)[i-1][0]);
164 partialAreaValid_ =
true;
171 vigra_precondition(
closed(),
172 "Polygon::area() requires polygon to be closed!");
173 return abs(partialArea());
179 return size() <= 1 || back() == front();
189 if(index <
size() - 1)
190 return (1.0 - offset) * (*this)[index] + offset * (*this)[index+1];
192 return (*
this)[index];
204 bool contains(const_reference point, coordinate_type tolerance)
const;
206 bool contains(const_reference point)
const
208 return contains(point, 2.0*NumericTraits<coordinate_type>::epsilon());
211 void push_back(const_reference v)
216 length_ += (v - back()).magnitude();
217 if(partialAreaValid_)
218 partialArea_ += 0.5*(v[0]*back()[1] - v[1]*back()[0]);
223 void push_back_unsafe(const_reference v)
228 void extend(
const Polygon &other)
233 const_iterator otherBegin(other.begin());
244 length_ += (other.front() -
Base::back()).magnitude();
245 if(partialAreaValid_)
246 partialArea_ += (other.front()[0]*
Base::back()[1] -
251 length_ += other.length();
252 if(partialAreaValid_)
253 partialArea_ += other.partialArea();
254 Base::insert(
Base::end(), otherBegin, other.end());
257 void setPoint(
unsigned int pos, const_reference x)
259 invalidateProperties();
264 void setPointUnsafe(
unsigned int pos, const_reference x)
277 const_reference operator[](
unsigned int pos)
const
282 const_reference front()
const
287 const_reference back()
const
294 invalidateProperties();
300 invalidateProperties();
304 reverse_iterator rbegin()
306 invalidateProperties();
310 reverse_iterator rend()
312 invalidateProperties();
316 void erase(iterator pos)
318 invalidateProperties();
322 void erase(iterator pos, iterator end)
324 invalidateProperties();
325 Base::erase(pos, end);
328 iterator insert(iterator pos, const_reference x)
330 invalidateProperties();
331 return Base::insert(pos, x);
334 template <
class InputIterator>
335 iterator insert(iterator pos, InputIterator i, InputIterator end)
337 invalidateProperties();
338 return Base::insert(pos, i, end);
341 Polygon split(
unsigned int pos)
348 else if(pos <
size())
350 result.insert(result.begin(), begin() + pos, end());
351 erase(begin() + pos, end());
356 template <
class Sequence>
357 void arcLengthList(Sequence & arcLengths)
const
360 arcLengths.push_back(0.0);
361 for(
unsigned int i = 1; i <
size(); ++i)
363 length += ((*this)[i] - (*this)[i-1]).magnitude();
364 arcLengths.push_back(length);
381 vigra_precondition(this->
size() > 0,
382 "Polygon:.arcLengthQuantile(): polygon is empty.");
383 if(quantile == 0.0 || this->
size() == 1)
386 return this->
size() - 1.0;
387 vigra_precondition(0.0 < quantile && quantile < 1.0,
388 "Polygon:.arcLengthQuantile(): quantile must be between 0 and 1.");
390 arcLength.reserve(this->
size());
391 arcLengthList(arcLength);
392 double length = quantile*arcLength.
back();
394 for(; k<this->
size(); ++k)
395 if(arcLength[k] >= length)
398 return k + (length - arcLength[k]) / (arcLength[k+1] - arcLength[k]);
404 std::swap(length_, rhs.length_);
405 std::swap(lengthValid_, rhs.lengthValid_);
406 std::swap(partialArea_, rhs.partialArea_);
407 std::swap(partialAreaValid_, rhs.partialAreaValid_);
413 if(partialAreaValid_)
414 partialArea_ = -partialArea_;
417 POINT nearestPoint(const_reference p)
const;
419 Polygon & operator+=(POINT
const & offset)
422 partialAreaValid_ =
false;
423 for(
unsigned int i = 0; i <
size(); ++i)
424 Base::operator[](i) += offset;
428 Polygon & operator-=(POINT
const & offset)
431 partialAreaValid_ =
false;
432 for(
unsigned int i = 0; i <
size(); ++i)
433 Base::operator[](i) -= offset;
437 Polygon & operator*=(
double scale)
439 partialArea_ *=
sq(scale);
441 for(
unsigned int i = 0; i <
size(); ++i)
442 Base::operator[](i) *= scale;
446 Polygon & operator/=(
double scale)
448 partialArea_ /=
sq(scale);
450 for(
unsigned int i = 0; i <
size(); ++i)
451 Base::operator[](i) /= scale;
455 bool operator==(Polygon
const & rhs)
const
457 if(
size() != rhs.size())
459 for(size_type k=0; k<
size(); ++k)
460 if((*
this)[k] != rhs[k])
465 bool operator!=(Polygon
const & rhs)
const
467 return !((*this) == rhs);
472 mutable double length_;
473 mutable bool lengthValid_;
474 mutable double partialArea_;
475 mutable bool partialAreaValid_;
478 template <
class POINT>
479 POINT Polygon<POINT>::nearestPoint(const_reference p)
const
481 double dist = NumericTraits<double>::max();
483 for(
unsigned int k=1; k<size(); ++k)
485 POINT dp = (*this)[k] - (*this)[k-1];
486 POINT dc = p - (*this)[k-1];
487 double t =
dot(dp, dc);
492 double d =
norm((*
this)[k]-p);
501 double d =
norm((*
this)[k-1]-p);
510 POINT pp = (*this)[k-1] + t*dp;
511 double d =
norm(pp-p);
522 template <
class POINT>
525 coordinate_type tolerance)
const
528 vigra_precondition(closed(),
529 "Polygon::contains() requires polygon to be closed!");
537 for(
int k=0; k<n; ++k)
539 ((Base&)p)[k][1] = 0.0;
542 bool drop_next_start_point =
false;
543 int first_point_maybe_dropped = -1;
544 for(
int k=0; k<n-1; ++k)
546 Point
const & p1 = p[k];
547 Point
const & p2 = p[k+1];
552 double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
568 if(drop_next_start_point)
571 drop_next_start_point =
false;
573 if(first_point_maybe_dropped == -1)
575 if(y == 0.0 && p1[0] - p1[1]*t < 0.0)
576 first_point_maybe_dropped = 1;
578 first_point_maybe_dropped = 0;
580 if(y*dy <= 0.0 && yend*dy > 0.0)
582 double x = p1[0] - p1[1]*t;
588 else if(p2[1] == 0.0)
591 bool convex = detail::orderedClockwise(p1, p2, p[j]);
594 double x = p2[0] - p2[1]*t;
600 for(; j != k+1; j = (j+1)%n)
602 double bend = dy*(p[j][1] - yend);
609 if((convex && bend > 0.0) || (!convex && bend < 0.0))
610 drop_next_start_point =
true;
616 if(drop_next_start_point && first_point_maybe_dropped == 1)
619 return (result % 2) != 0;
622 template <
class POINT>
626 for(
unsigned int i = 0; i < p.
size(); ++i)
628 result.setPointUnsafe(i,
round(p[i]));
633 template <
class POINT>
634 inline Polygon<TinyVector<std::ptrdiff_t, 2> >
roundi(Polygon<POINT>
const & p)
636 Polygon<TinyVector<std::ptrdiff_t, 2> > result(p.size());
637 for(
unsigned int i = 0; i < p.size(); ++i)
639 result.setPointUnsafe(i,
roundi(p[i]));
644 template <
class POINT>
645 inline Polygon<POINT>
646 operator+(Polygon<POINT>
const & p, POINT
const & offset)
648 return Polygon<POINT>(p) += offset;
651 template <
class POINT>
652 inline Polygon<POINT>
653 operator+(POINT
const & offset, Polygon<POINT>
const & p)
655 return Polygon<POINT>(p) += offset;
658 template <
class POINT>
659 inline Polygon<POINT>
662 Polygon<POINT> result(p.size());
663 for(
unsigned int i = 0; i < p.size(); ++i)
664 result.setPointUnsafe(i, -p[i]);
668 template <
class POINT>
669 inline Polygon<POINT>
670 operator-(Polygon<POINT>
const & p, POINT
const & offset)
672 return Polygon<POINT>(p) -= offset;
675 template <
class POINT>
676 inline Polygon<POINT>
677 operator*(Polygon<POINT>
const & p,
double scale)
679 return Polygon<POINT>(p) *= scale;
682 template <
class POINT>
683 inline Polygon<POINT>
684 operator*(
double scale, Polygon<POINT>
const & p)
686 return Polygon<POINT>(p) *= scale;
690 template <
class POINT>
691 inline Polygon<POINT>
692 operator/(Polygon<POINT>
const & p,
double scale)
694 return Polygon<POINT>(p) /= scale;
697 template <
class POINT>
698 inline Polygon<POINT>
701 Polygon<POINT> result(p.size());
702 for(
unsigned int i = 0; i < p.size(); ++i)
704 result.setPointUnsafe(i, POINT(p[i][1], p[i][0]));
709 template <
class POINT>
710 inline Polygon<POINT>
711 reverse(Polygon<POINT>
const & p)
713 Polygon<POINT> result(p);
718 template<
class Po
int>
719 Point centroid(
const Polygon<Point> &polygon)
721 vigra_precondition(polygon.closed(),
722 "centroid() expects a closed polygon");
724 TinyVector<double, 2> result;
725 for(
unsigned int i = 1; i < polygon.size(); ++i)
727 double pa = (polygon[i-1][0]*polygon[i][1] -
728 polygon[i-1][1]*polygon[i][0]);
730 result += (polygon[i-1] + polygon[i])*pa;
732 return result / (3.0*a);
764 template<
class T,
class S,
class Po
intArray>
767 Shape2
const & anchor_point,
768 PointArray & contour_points)
770 typedef typename PointArray::value_type Point;
772 Shape2 step[4] = { Shape2(0, -1), Shape2(1, 0), Shape2(0, 1), Shape2(-1, 0) };
773 Point contour_offsets[4] = { Point(-0.5, 0), Point(0, -0.5), Point(0.5, 0), Point(0, 0.5) };
775 T foreground = label_image[anchor_point];
780 for(direction = 3; direction >= 0; --direction)
782 position = anchor_point + step[(direction + 1) % 4];
783 if(!label_image.
isInside(position) || label_image[position] != foreground)
787 vigra_precondition(direction >= 0,
788 "extractContour(): the anchor point must be at the region border.");
790 int initial_direction = direction;
791 Shape2 initial_position = position;
796 contour_points.push_back(position + contour_offsets[direction]);
798 Shape2 next_position = position + step[direction];
800 if(label_image.
isInside(next_position) &&
801 label_image[next_position] == foreground)
804 direction = (direction + 1) % 4;
808 position = next_position;
809 int next_direction = (direction + 3) % 4;
810 next_position += step[next_direction];
811 if(!label_image.
isInside(next_position) ||
812 label_image[next_position] != foreground)
815 direction = next_direction;
816 position = next_position;
820 while (position != initial_position || direction != initial_direction);
822 contour_points.push_back(contour_points.front());
837 template<
class Po
intArray1,
class Po
intArray2>
838 void convexHull(
const PointArray1 &points, PointArray2 & convex_hull)
840 vigra_precondition(points.size() >= 2,
841 "convexHull(): at least two input points are needed.");
842 vigra_precondition(points[0].size() == 2,
843 "convexHull(): 2-dimensional points required.");
845 typedef typename PointArray1::value_type Point;
847 typename PointArray1::const_iterator begin = points.begin();
848 if(points.front() == points.back())
851 std::sort(ordered.begin(), ordered.end(), detail::pointYXOrdering<Point>);
855 int n = ordered.
size(), k=0;
858 for (
int i = 0; i < n; i++)
860 while (k >= 2 && detail::orderedClockwise(H[k-2], H[k-1], ordered[i]))
865 H.push_back(ordered[i]);
870 for (
int i = n-2, t = k+1; i >= 0; i--)
872 while (k >= t && detail::orderedClockwise(H[k-2], H[k-1], ordered[i]))
877 H.push_back(ordered[i]);
881 for(
int i=k-1; i>=0; --i)
882 convex_hull.push_back(H[i]);
899 template<
class Po
int,
class Array>
900 void createScanIntervals(Polygon<Point>
const &p, Array & result)
902 bool drop_next_start_point =
false;
904 for(
int k=0; k<n-1; ++k)
906 Point
const & p1 = p[k];
907 Point
const & p2 = p[k+1];
912 double t = (p2[0] - p1[0]) / (p2[1] - p1[1]);
928 if(drop_next_start_point)
931 drop_next_start_point =
false;
933 for(; (y-yend)*dy < 0.0; y += dy)
935 double x = p1[0] + (y - p1[1])*t;
936 result.push_back(Point(x,y));
941 bool convex = detail::orderedClockwise(p1, p2, p[j]);
944 result.push_back(p2);
946 for(; j != k+1; j = (j+1)%n)
948 double bend = dy*(p[j][1] - yend);
955 if((convex && bend > 0.0) || (!convex && bend < 0.0))
956 drop_next_start_point =
true;
962 if(drop_next_start_point)
963 result.erase(result.begin());
965 vigra_invariant((result.size() & 1) == 0,
966 "createScanIntervals(): internal error - should return an even number of points.");
967 sort(result.begin(), result.end(), pointYXOrdering<Point>);
973 template<
class Po
int,
class FUNCTOR>
975 inspectPolygon(Polygon<Point>
const &p,
978 vigra_precondition(p.closed(),
979 "inspectPolygon(): polygon must be closed (i.e. first point == last point).");
981 std::vector<Point> scan_intervals;
982 detail::createScanIntervals(p, scan_intervals);
984 for(
unsigned int k=0; k < scan_intervals.size(); k+=2)
989 for(; p[0] < xend; ++p[0])
1004 template<
class Po
int,
class T,
class S,
class Value>
1009 vigra_precondition(p.
closed(),
1010 "fillPolygon(): polygon must be closed (i.e. first point == last point).");
1012 std::vector<Point> scan_intervals;
1013 detail::createScanIntervals(p, scan_intervals);
1015 for(
unsigned int k=0; k < scan_intervals.size(); k+=2)
1020 vigra_invariant(y == scan_intervals[k+1][1],
1021 "fillPolygon(): internal error - scan interval should have same y value.");
1025 if(y >= output_image.
shape(1))
1029 if(xend > output_image.
shape(0))
1030 xend = output_image.
shape(0);
1032 for(; x < xend; ++x)
1033 output_image(x,y) = value;
1043 template<
bool useMaxStep,
class Po
intIterator,
class TargetArray>
1044 void simplifyPolygonHelper(
1045 const PointIterator &polyBegin,
const PointIterator &polyEnd,
1046 TargetArray &simple,
double epsilon,
1047 double maxStep2 = vigra::NumericTraits<double>::max())
1049 if(polyEnd - polyBegin <= 2)
1052 PointIterator splitPos(polyEnd), lastPoint(polyEnd);
1055 double maxDist = epsilon;
1058 typename TargetArray::value_type
1059 straight(*lastPoint - *polyBegin);
1060 double straightLength2 = straight.squaredMagnitude();
1063 if(straightLength2 > 1e-16)
1065 typename TargetArray::value_type
1066 normal(straight[1], -straight[0]);
1071 PointIterator it(polyBegin);
1072 for(++it; it != lastPoint; ++it)
1074 double dist = fabs(
dot(*it - *polyBegin, normal));
1085 PointIterator it(polyBegin);
1086 for(++it; it != lastPoint; ++it)
1088 double dist = (*it - *polyBegin).magnitude();
1097 if(useMaxStep && (straightLength2 > maxStep2) && (splitPos == polyEnd))
1099 PointIterator it(polyBegin);
1101 double bestD2D = std::fabs((*it - *polyBegin).squaredMagnitude()
1102 - (*it - *lastPoint).squaredMagnitude());
1104 for(++it; it != lastPoint; ++it)
1106 double dist2Diff = std::fabs((*it - *polyBegin).squaredMagnitude()
1107 - (*it - *lastPoint).squaredMagnitude());
1108 if(dist2Diff < bestD2D)
1110 bestD2D = dist2Diff;
1116 if(splitPos != polyEnd)
1118 simplifyPolygonHelper<useMaxStep>(
1119 polyBegin, splitPos + 1, simple, epsilon, maxStep2);
1120 simple.push_back(*splitPos);
1121 simplifyPolygonHelper<useMaxStep>(
1122 splitPos, polyEnd, simple, epsilon, maxStep2);
1126 template<
class Po
intArray>
1127 void simplifyPolygon(
1128 const PointArray &poly, PointArray &simple,
double epsilon)
1130 simple.push_back(poly[0]);
1131 simplifyPolygonHelper<false>(poly.begin(), poly.end(), simple, epsilon);
1132 simple.push_back(poly[poly.size()-1]);
1135 template<
class Po
intArray>
1136 void simplifyPolygon(
1137 const PointArray &poly, PointArray &simple,
double epsilon,
double maxStep)
1139 simple.push_back(poly[0]);
1140 simplifyPolygonHelper<true>(poly.begin(), poly.end(),
1141 simple, epsilon, maxStep*maxStep);
1142 simple.push_back(poly[poly.size()-1]);
1149 template <
class Po
int>
1150 Point digitalLineIntersection(TinyVector<double, 3>
const & l1, TinyVector<double, 3>
const & l2)
1152 double d = l1[0]*l2[1] - l1[1]*l2[0];
1153 return Point((l1[1]*l2[2] - l1[2]*l2[1]) / d, (l1[2]*l2[0] - l1[0]*l2[2]) / d);
1158 template<
class Po
intArray>
1159 void simplifyPolygonDigitalLine(
1160 const PointArray &poly, PointArray &simple,
int connectivity)
1162 typedef typename PointArray::value_type Point;
1164 int size = poly.size();
1171 vigra_precondition(connectivity == 4 || connectivity == 8,
1172 "simplifyPolygonDigitalLine(): connectivity must be 4 or 8.");
1174 bool isOpenPolygon = poly[size-1] != poly[0];
1176 ArrayVector<TinyVector<double, 3> > lines;
1181 double a = l2[1] - l1[1],
1183 c = -a*l2[0] - b*l2[1];
1184 for(
int k=2; k < size; ++k)
1186 double ab = (connectivity == 4)
1187 ? std::fabs(a) + std::fabs(b)
1188 : std::max(std::fabs(a), std::fabs(b));
1189 double d = a*poly[k][0] + b*poly[k][1] + c;
1190 if(d < -1.0 || d > ab)
1193 c = (c - a*r2[0] - b*r2[1]) / 2.0;
1194 lines.push_back(TinyVector<double, 3>(a, b, c));
1202 c = -a*l2[0] - b*l2[1];
1212 c = -a*l2[0] - b*l2[1];
1215 else if(d >= ab - 1.0)
1223 c = -a*l2[0] - b*l2[1];
1228 c = (c - a*r2[0] - b*r2[1]) / 2.0;
1229 lines.push_back(TinyVector<double, 3>(a, b, c));
1230 int segments = lines.size();
1233 simple.push_back(poly[0]);
1235 simple.push_back(detail::digitalLineIntersection<Point>(lines[0], lines[segments-1]));
1237 for(
int k=1; k<segments; ++k)
1238 simple.push_back(detail::digitalLineIntersection<Point>(lines[k-1], lines[k]));
1241 simple.push_back(poly[size-1]);
1243 simple.push_back(detail::digitalLineIntersection<Point>(lines[0], lines[segments-1]));
1248 template<
class Po
intArray>
1249 void resamplePolygon(
1250 const PointArray &poly, PointArray &simple,
double desiredPointDistance)
1252 typedef typename PointArray::value_type Point;
1254 int size = poly.size();
1255 bool isOpenPolygon = !poly.closed();
1257 ArrayVector<double> arcLength;
1258 poly.arcLengthList(arcLength);
1259 int segmentCount = int(
std::ceil(arcLength[size-1] / desiredPointDistance));
1260 if(segmentCount < 2)
1262 simple.push_back(poly[0]);
1266 double dist = (p - poly[0]).magnitude();
1267 for(
int k=2; k < size-1; ++k)
1269 double d = (poly[k] - poly[0]).magnitude();
1276 simple.push_back(p);
1278 simple.push_back(poly[size-1]);
1282 for(
int k=0; k<size; ++k)
1283 arcLength[k] *= segmentCount / arcLength[size-1];
1285 ArrayVector<Point> integrals(segmentCount+1, Point(0.0, 0.0));
1289 for(
int k=1; k<size; ++k)
1291 double d = arcLength[k];
1292 while(d >= l && l <= segmentCount)
1295 double dt = t2 - t1;
1296 Point p2 = poly.interpolate(k-1, (l - arcLength[k-1]) / (d - arcLength[k-1]));
1297 Point sum1 = 0.5 * dt * (p1 + p2);
1298 Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
1299 integrals[l-1] += sum1 - sumt;
1300 integrals[l] += sumt;
1301 if(isOpenPolygon && l==1)
1303 integrals[0] += poly[0] - integrals[1];
1308 if(isOpenPolygon && l==segmentCount)
1310 integrals[segmentCount] += integrals[segmentCount-1];
1313 if(d < l && l <= segmentCount)
1315 double t2 = std::fmod(d, 1.0);
1316 double dt = t2 - t1;
1318 Point sum1 = 0.5 * dt * (p1 + p2);
1319 Point sumt = dt / 6.0 * (p1*(2.0*t1+t2) + p2*(t1+2.0*t2));
1320 integrals[l-1] += sum1 - sumt;
1321 integrals[l] += sumt;
1329 integrals[segmentCount] += poly[size-1] - integrals[segmentCount-1];
1330 integrals[1] -= integrals[0] / 6.0;
1331 integrals[segmentCount-1] -= integrals[segmentCount] / 6.0;
1333 ArrayVector<double> g(segmentCount);
1334 double b = 2.0 / 3.0;
1335 simple.push_back(poly[0]);
1336 simple.push_back(integrals[1] / b);
1337 for(
int k=2; k<segmentCount; ++k)
1339 g[k] = 1.0 / 6.0 / b;
1340 b = 2.0 / 3.0 - g[k] / 6.0;
1341 simple.push_back((integrals[k] - simple[k-1] / 6.0) / b);
1343 for(
int k = segmentCount-2; k >= 1; --k)
1345 simple[k] -= g[k+1] * simple[k+1];
1348 simple.push_back(poly[size-1]);
1352 integrals[0] += integrals[segmentCount];
1354 int initializationSteps = std::min(segmentCount, 5);
1355 ArrayVector<Point> p(segmentCount+2*initializationSteps);
1356 double b = 0.6220084679281461,
1357 g = 0.26794919243112275;
1358 p[0] = integrals[0] / b;
1360 for(
int k=1; k<segmentCount+2*initializationSteps; ++k)
1362 p[k] = (integrals[k % segmentCount] - p[k-1] / 6.0) / b;
1364 for(
int k = segmentCount+2*initializationSteps-2; k >= initializationSteps; --k)
1369 for(
int k=segmentCount; k<segmentCount+initializationSteps; ++k)
1370 simple.push_back(p[k]);
1371 for(
int k=initializationSteps; k<=segmentCount; ++k)
1372 simple.push_back(p[k]);
1378 template<
class Po
intArray>
1379 void resamplePolygonLinearInterpolation(
1380 const PointArray &poly, PointArray &simple,
double desiredPointDistance)
1382 int size = poly.size();
1389 ArrayVector<double> arcLengths;
1390 poly.arcLengthList(arcLengths);
1392 int steps = int(
std::ceil(arcLengths[size-1] / desiredPointDistance));
1393 double newStep = arcLengths[size-1] / steps;
1395 simple.push_back(poly[0]);
1397 for(
int k=1; k<steps; ++k)
1399 double currentArcLength = k*newStep;
1400 for(; l < size; ++l)
1402 if(arcLengths[l] >= currentArcLength)
1405 double o = (arcLengths[l] - currentArcLength) / (arcLengths[l] - arcLengths[l-1]);
1406 simple.push_back(o*poly[l-1] + (1.0-o)*poly[l]);
1408 simple.push_back(poly[size-1]);
1413 template<
class Po
intArray>
1414 void resamplePolygonExponentialFilter(
1415 const PointArray &poly, PointArray &simple,
double scale,
double desiredPointDistance)
1417 int size = poly.size();
1424 bool isOpenPolygon = !poly.closed();
1426 typedef typename PointArray::value_type Point;
1427 ArrayVector<Point> pforward(size), pbackward(size);
1428 ArrayVector<double> wforward(size), wbackward(size), weights(size-1);
1429 for(
int k=0; k < size - 1; ++k)
1430 weights[k] =
std::exp(-(poly[k] - poly[k+1]).magnitude()/scale);
1435 for(
int k=1; k < size; ++k)
1437 p = poly[k] + weights[k-1]*p;
1438 w = 1.0 + weights[k-1]*w;
1445 for(
int k=size-2; k>=0; --k)
1447 p = poly[k] + weights[k]*p;
1448 w = 1.0 + weights[k]*w;
1450 pbackward[size-1] = p;
1451 wbackward[size-1] = w;
1456 std::swap(wbackward[size-1], wforward[0]);
1457 std::swap(pbackward[size-1], pforward[0]);
1458 pforward[0] = 2.0*wforward[0]*poly[0] - pforward[0];
1459 pbackward[size-1] = 2.0*wbackward[size-1]*poly[size-1] - pbackward[size-1];
1463 for(
int k=1; k < size; ++k)
1465 pforward[k] = poly[k] + weights[k-1]*pforward[k-1];
1466 wforward[k] = 1.0 + weights[k-1]*wforward[k-1];
1468 for(
int k=size-2; k >= 0; --k)
1470 pbackward[k] = poly[k] + weights[k]*pbackward[k+1];
1471 wbackward[k] = 1.0 + weights[k]*wbackward[k+1];
1475 p = (pforward[0]+weights[0]*pbackward[1]) / (wforward[0] + weights[0]*wbackward[1]);
1476 simple.push_back(p);
1478 Point pend = isOpenPolygon
1479 ? (weights[size-2]*pforward[size-2]+pbackward[size-1]) /
1480 (weights[size-2]*wforward[size-2] + wbackward[size-1])
1483 ArrayVector<double> arcLength;
1484 double length = 0.0;
1485 arcLength.push_back(length);
1486 for(
int k=1; k<size-1; ++k)
1488 Point pc = (pforward[k]+weights[k]*pbackward[k+1]) / (wforward[k] + weights[k]*wbackward[k+1]);
1489 length += (pc - p).magnitude();
1490 arcLength.push_back(length);
1493 length += (p-pend).magnitude();
1494 arcLength.push_back(length);
1499 int steps = int(
std::floor(arcLength[size-1] / desiredPointDistance+0.5));
1500 double newStep = arcLength[size-1] / steps;
1503 for(
int k=1; k < steps; ++k)
1505 double currentArcLength = k*newStep;
1506 for(; l < size; ++l)
1508 if(arcLength[l] >= currentArcLength)
1511 double w = weights[l-1];
1512 double o = (arcLength[l] - currentArcLength) / (arcLength[l] - arcLength[l-1]);
1513 double wl = std::pow(w, 1.0-o);
1514 double wr = std::pow(w, o);
1515 simple.push_back((wl*pforward[l-1]+wr*pbackward[l]) / (wl*wforward[l-1] + wr*wbackward[l]));
1517 simple.push_back(pend);
1524 template<
class ArcLengthList,
class Po
intList>
1525 typename PointList::value_type
1526 singleGaussianConvolvePolygonReflective(
1527 const ArcLengthList &arcLengthList,
1528 const PointList &pointList,
1529 int i,
double arcLengthPos,
1530 const Gaussian<double> &g)
1532 typedef typename PointList::value_type ValueType;
1534 ValueType
sum(vigra::NumericTraits<ValueType>::zero());
1537 int size = arcLengthList.size(),
1538 lastIndex = size - 1;
1539 double reflectLength = 2.0*arcLengthList[lastIndex];
1541 ValueType reflectPoint = 2.0*pointList[lastIndex];
1542 for(
int j = i;
true; ++j)
1544 int k = (j > lastIndex)
1547 double pos = arcLengthList[k];
1548 ValueType point = pointList[k];
1551 pos = reflectLength - pos;
1552 point = reflectPoint - point;
1554 double diff = pos - arcLengthPos;
1555 if(diff > g.radius())
1562 reflectPoint = 2.0*pointList[0];
1563 for(
int j = i - 1;
true; --j)
1566 double pos = arcLengthList[k];
1567 ValueType point = pointList[k];
1571 point = reflectPoint - point;
1573 double diff = pos - arcLengthPos;
1574 if(diff < -g.radius())
1584 template<
class ArcLengthList,
class Po
intList>
1585 typename PointList::value_type
1586 singleGaussianConvolvePolygonCyclic(
1587 const ArcLengthList &arcLengthList,
1588 const PointList &pointList,
1589 int i,
double arcLengthPos,
1590 const Gaussian<double> &g)
1592 typedef typename PointList::value_type ValueType;
1594 ValueType
sum(vigra::NumericTraits<ValueType>::zero());
1597 int size = arcLengthList.size() - 1,
1598 lastIndex = size - 1;
1599 double totalLength = arcLengthList[size];
1601 for(
int j = i;
true; ++j)
1604 double pos = j > lastIndex
1605 ? arcLengthList[k] + totalLength
1607 ValueType point = pointList[k];
1608 double diff = pos - arcLengthPos;
1609 if(diff > g.radius())
1616 for(
int j = i - 1;
true; --j)
1618 int k = (j + size) % size;
1620 ? arcLengthList[k] - totalLength
1622 ValueType point = pointList[k];
1623 double diff = pos - arcLengthPos;
1624 if(diff < -g.radius())
1636 template<
class Po
intArray>
1637 void resamplePolygonGaussianFilter(
1638 const PointArray &poly, PointArray &simple,
double scale,
double desiredPointDistance)
1640 int size = poly.size();
1647 ArrayVector<double> arcLengths;
1648 poly.arcLengthList(arcLengths);
1650 Gaussian<double> g(scale);
1652 vigra_precondition(arcLengths[size-1] > g.radius(),
1653 "resamplePolygonGaussianFilter(): Filter longer than polygon.");
1655 bool isOpenPolygon = !poly.closed();
1657 int steps = int(
std::ceil(arcLengths[size-1] / desiredPointDistance));
1658 double newStep = arcLengths[size-1] / steps;
1661 for(
int k=0; k<steps; ++k)
1663 double currentArcLength = k*newStep;
1664 for(; l < size; ++l)
1666 if(arcLengths[l] >= currentArcLength)
1670 simple.push_back(detail::singleGaussianConvolvePolygonReflective(arcLengths, poly, l, currentArcLength, g));
1672 simple.push_back(detail::singleGaussianConvolvePolygonCyclic(arcLengths, poly, l, currentArcLength, g));
1675 simple.push_back(detail::singleGaussianConvolvePolygonReflective(arcLengths, poly, size-1, arcLengths[size-1], g));
1677 simple.push_back(simple[0]);
1684 template<
class Po
int>
1685 Point spline3Integral(Point
const & p1, Point
const & p2,
double t1,
double t2)
1687 StaticPolynomial<5, double> p[2];
1688 p[0][0] = p[1][0] = 0.0;
1691 return (t1 - t2) / 120.0 *
1692 (p1 * (-80.0 + t1*(80.0 + 2.0*t2*(t2 - 10.0) + t1*(3.0*t2 - 30.0 + 4.0*t1)) + t2*(40.0 + t2*(t2 - 10.0))) +
1693 p2 * (-80.0 + t1*(40.0 + t2*(3.0*t2 - 20.0) + t1*(2.0*t2 - 10.0 + t1)) + t2*(80.0 + t2*(4.0*t2 - 30.0))));
1697 return (t2 - t1) / 120.0 *
1698 (p1 * (40.0 + t1*(2.0*t2*(3.0*t2 - 10.0) + t1*(9.0*t2 - 30.0 + 12.0*t1)) + t2*t2*(3.0*t2 - 10.0)) +
1699 p2 * (40.0 + t1*(t2*(9.0*t2 - 20.0) + t1*(6.0*t2 - 10.0 + 3.0*t1)) + t2*t2*(12.0*t2 - 30.0)));
1703 template<
class ArcLengthList,
class Po
intList>
1704 typename PointList::value_type
1705 singleSpline3ConvolvePolygon(
1706 const ArcLengthList &arcLengthList,
1707 const PointList &pointList,
1708 int left,
int center,
int right)
1710 typedef typename PointList::value_type ValueType;
1712 ValueType
sum(vigra::NumericTraits<ValueType>::zero());
1713 double arcLengthPos = arcLengthList[center];
1714 for(
int j = center + 1; j <= right; ++j)
1716 double t1 = arcLengthList[j-1] - arcLengthPos,
1717 t2 = arcLengthList[j] - arcLengthPos;
1718 sum += spline3Integral(pointList[j-1], pointList[j], t1, t2);
1720 for(
int j = center - 1; j >= left; --j)
1722 double t1 = arcLengthPos - arcLengthList[j+1],
1723 t2 = arcLengthPos - arcLengthList[j];
1724 sum -= spline3Integral(-pointList[j+1], -pointList[j], t1, t2);
1732 template<
class Po
intArray>
1733 void polygonSplineControlPoints(
1734 const PointArray &poly, PointArray &splinePoints,
int segmentCount)
1736 typedef typename PointArray::value_type Point;
1738 int size = poly.size();
1739 vigra_precondition(size >= 4,
1740 "polygonSplineControlPoints(): Polygon must have at least 4 points.");
1742 bool isOpenPolygon = !poly.closed();
1744 ArrayVector<double> arcLength;
1745 poly.arcLengthList(arcLength);
1746 double totalLength = segmentCount / arcLength[size-1];
1747 for(
int k=0; k<size; ++k)
1748 arcLength[k] *= totalLength;
1750 PointArray augmentedPoly;
1751 augmentedPoly.push_back(poly[0]);
1753 ArrayVector<double> augmentedArcLength;
1754 augmentedArcLength.push_back(0.0);
1756 ArrayVector<int> splineIndices(segmentCount + 1);
1757 splineIndices[0] = 0;
1759 for(
int k=1; k<size-1; ++k)
1761 double d = arcLength[k];
1764 augmentedPoly.push_back(poly.interpolate(k-1, (l - arcLength[k-1]) / (d - arcLength[k-1])));
1765 augmentedArcLength.push_back(l);
1766 splineIndices[l] = augmentedPoly.size()-1;
1769 augmentedPoly.push_back(poly[k]);
1770 augmentedArcLength.push_back(d);
1773 splineIndices[l] = augmentedPoly.size()-1;
1777 augmentedPoly.push_back(poly[size-1]);
1778 augmentedArcLength.push_back(segmentCount);
1779 splineIndices[segmentCount] = augmentedPoly.size()-1;
1780 size = augmentedPoly.size();
1782 ArrayVector<Point> integrals(segmentCount+1);
1785 integrals[0] = augmentedPoly[0];
1786 PointArray reflectedPoly;
1787 Point reflectPoint = 2.0*poly[0];
1788 ArrayVector<double> reflectedArcLength;
1789 for(
int k=-splineIndices[1]; k <= splineIndices[3]; ++k)
1793 reflectedPoly.push_back(reflectPoint - augmentedPoly[-k]);
1794 reflectedArcLength.push_back(-augmentedArcLength[-k]);
1798 reflectedPoly.push_back(augmentedPoly[k]);
1799 reflectedArcLength.push_back(augmentedArcLength[k]);
1802 integrals[1] = detail::singleSpline3ConvolvePolygon(reflectedArcLength, reflectedPoly,
1803 0, 2*splineIndices[1], splineIndices[1] + splineIndices[3]);
1805 reflectPoint = 2.0*augmentedPoly[size-1];
1806 for(
int k=size-2; k>=splineIndices[segmentCount-1]; --k)
1808 augmentedPoly.push_back(reflectPoint - augmentedPoly[k]);
1809 augmentedArcLength.push_back(2.0*segmentCount - augmentedArcLength[k]);
1811 integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
1812 splineIndices[segmentCount-3], splineIndices[segmentCount-1],
1813 2*splineIndices[segmentCount] - splineIndices[segmentCount-1]);
1814 integrals[segmentCount] = augmentedPoly[size-1];
1818 PointArray wrappedPoly;
1819 ArrayVector<double> wrappedArcLength;
1820 for(
int k=splineIndices[segmentCount-1]; k < splineIndices[segmentCount]; ++k)
1822 wrappedPoly.push_back(augmentedPoly[k]);
1823 wrappedArcLength.push_back(augmentedArcLength[k] - segmentCount);
1825 int indexShift = wrappedPoly.size();
1826 for(
int k=0; k <= splineIndices[3]; ++k)
1828 wrappedPoly.push_back(augmentedPoly[k]);
1829 wrappedArcLength.push_back(augmentedArcLength[k]);
1831 integrals[1] = detail::singleSpline3ConvolvePolygon(wrappedArcLength, wrappedPoly,
1832 0, splineIndices[1] + indexShift, splineIndices[3] + indexShift);
1834 for(
int k=1; k <= splineIndices[2]; ++k)
1836 augmentedPoly.push_back(augmentedPoly[k]);
1837 augmentedArcLength.push_back(segmentCount + augmentedArcLength[k]);
1839 integrals[segmentCount-1] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
1840 splineIndices[segmentCount-3], splineIndices[segmentCount-1],
1841 splineIndices[segmentCount] + splineIndices[1]);
1842 integrals[0] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
1843 splineIndices[segmentCount-2], splineIndices[segmentCount],
1844 splineIndices[segmentCount] + splineIndices[2]);
1847 for(
int k=2; k <= segmentCount-2; ++k)
1848 integrals[k] = detail::singleSpline3ConvolvePolygon(augmentedArcLength, augmentedPoly,
1849 splineIndices[k-2], splineIndices[k], splineIndices[k+2]);
1851 BSpline<7, double> spline7;
1854 int solutionSize = segmentCount + 1;
1855 Matrix<double> m(solutionSize, solutionSize),
1856 rhs(solutionSize, 2),
1857 solution(solutionSize, 2);
1858 for(
int k=0; k<solutionSize; ++k)
1860 for(
int l=-3; l<=3; ++l)
1864 m(k, 0) += 2.0*spline7(l);
1865 m(k,
abs(k+l)) -= spline7(l);
1867 else if(k + l >= solutionSize)
1869 m(k, solutionSize - 1) += 2.0*spline7(l);
1870 m(k, 2*solutionSize - k - l - 2) -= spline7(l);
1873 m(k,k+l) += spline7(l);
1875 rhs(k, 0) = integrals[k][0];
1876 rhs(k, 1) = integrals[k][1];
1881 for(
int k=0; k<solutionSize; ++k)
1883 splinePoints.push_back(Point(solution(k,0), solution(k,1)));
1885 splinePoints.push_back(2.0*splinePoints[solutionSize-1] - splinePoints[solutionSize-2]);
1886 splinePoints.insert(splinePoints.begin(), 2.0*splinePoints[0] - splinePoints[1]);
1890 int solutionSize = segmentCount;
1891 Matrix<double> m(solutionSize, solutionSize),
1892 rhs(solutionSize, 2),
1893 solution(solutionSize, 2);
1894 for(
int k=0; k<solutionSize; ++k)
1896 for(
int l=-3; l<=3; ++l)
1897 m(k, (k+l+solutionSize) % solutionSize) = spline7(l);
1898 rhs(k, 0) = integrals[k][0];
1899 rhs(k, 1) = integrals[k][1];
1903 for(
int k=0; k<solutionSize; ++k)
1905 splinePoints.push_back(Point(solution(k,0), solution(k,1)));
1907 splinePoints.push_back(splinePoints[0]);
1920 ostream & operator<<(ostream & s, vigra::Polygon<T>
const & a)
1922 for(std::size_t k=0; k<a.size()-1; ++k)
reference back()
Definition: array_vector.hxx:321
PromoteTraits< V1, V2 >::Promote dot(RGBValue< V1, RIDX1, GIDX1, BIDX1 > const &r1, RGBValue< V2, RIDX2, GIDX2, BIDX2 > const &r2)
dot product
Definition: rgbvalue.hxx:906
void transpose(const MultiArrayView< 2, T, C1 > &v, MultiArrayView< 2, T, C2 > &r)
Definition: matrix.hxx:965
Int32 roundi(FixedPoint16< IntBits, OverflowHandling > v)
rounding to the nearest integer.
Definition: fixedpoint.hxx:1775
Diff2D operator-(Diff2D const &a, Diff2D const &b)
Definition: diff2d.hxx:711
double arcLengthQuantile(double quantile) const
Definition: polygon.hxx:379
void extractContour(MultiArrayView< 2, T, S > const &label_image, Shape2 const &anchor_point, PointArray &contour_points)
Create a polygon from the interpixel contour of a labeled region.
Definition: polygon.hxx:766
const difference_type & shape() const
Definition: multi_array.hxx:1648
bool empty() const
Definition: array_vector.hxx:351
linalg::TemporaryMatrix< T > exp(MultiArrayView< 2, T, C > const &v)
const_iterator begin() const
Definition: array_vector.hxx:223
FFTWComplex< R >::SquaredNormType squaredNorm(const FFTWComplex< R > &a)
squared norm (= squared magnitude)
Definition: fftw3.hxx:1044
int round(FixedPoint< IntBits, FracBits > v)
rounding to the nearest integer.
Definition: fixedpoint.hxx:683
reverse_iterator rend()
Definition: array_vector.hxx:279
Diff2D operator+(Diff2D const &a, Diff2D const &b)
Definition: diff2d.hxx:739
const_reverse_iterator crend() const
Definition: array_vector.hxx:300
Point interpolate(unsigned int index, double offset) const
Definition: polygon.hxx:187
std::ptrdiff_t MultiArrayIndex
Definition: multi_fwd.hxx:60
const_reverse_iterator crbegin() const
Definition: array_vector.hxx:293
Definition: polygon.hxx:78
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
reference operator[](difference_type i)
Definition: array_vector.hxx:335
Definition: array_vector.hxx:58
NumericTraits< T >::Promote sq(T t)
The square function.
Definition: mathutil.hxx:382
reference front()
Definition: array_vector.hxx:307
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
bool isInside(difference_type const &p) const
Definition: multi_array.hxx:1717
bool contains(const_reference point, coordinate_type tolerance) const
Definition: polygon.hxx:524
bool closeAtTolerance(T1 l, T2 r, typename PromoteTraits< T1, T2 >::Promote epsilon)
Tolerance based floating-point equality.
Definition: mathutil.hxx:1638
const_iterator cend() const
Definition: array_vector.hxx:258
const_iterator cbegin() const
Definition: array_vector.hxx:251
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
Base class for, and view to, vigra::MultiArray.
Definition: multi_array.hxx:704
reverse_iterator rbegin()
Definition: array_vector.hxx:265
const_iterator end() const
Definition: array_vector.hxx:237
size_type size() const
Definition: array_vector.hxx:358
void convexHull(const PointArray1 &points, PointArray2 &convex_hull)
Compute convex hull of a 2D polygon.
Definition: polygon.hxx:838
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up.
Definition: fixedpoint.hxx:675
void fillPolygon(Polygon< Point > const &p, MultiArrayView< 2, T, S > &output_image, Value value)
Render closed polygon p into the image output_image.
Definition: polygon.hxx:1005
int floor(FixedPoint< IntBits, FracBits > v)
rounding down.
Definition: fixedpoint.hxx:667
bool closed() const
Returns true iff the last and first points are equal or the polygon is empty.
Definition: polygon.hxx:177
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616