psimpl 7
|
00001 /* ***** BEGIN LICENSE BLOCK ***** 00002 * Version: MPL 1.1 00003 * 00004 * The contents of this file are subject to the Mozilla Public License Version 00005 * 1.1 (the "License"); you may not use this file except in compliance with 00006 * the License. You may obtain a copy of the License at 00007 * http://www.mozilla.org/MPL/ 00008 * 00009 * Software distributed under the License is distributed on an "AS IS" basis, 00010 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 00011 * for the specific language governing rights and limitations under the 00012 * License. 00013 * 00014 * The Original Code is 00015 * 'psimpl - generic n-dimensional polyline simplification'. 00016 * 00017 * The Initial Developer of the Original Code is 00018 * Elmar de Koning. 00019 * Portions created by the Initial Developer are Copyright (C) 2010-2011 00020 * the Initial Developer. All Rights Reserved. 00021 * 00022 * Contributor(s): 00023 * 00024 * ***** END LICENSE BLOCK ***** */ 00025 00026 /* 00027 psimpl - generic n-dimensional polyline simplification 00028 Copyright (C) 2010-2011 Elmar de Koning, edekoning@gmail.com 00029 00030 This file is part of psimpl, and is hosted at SourceForge: 00031 http://sourceforge.net/projects/psimpl/ 00032 */ 00033 00092 #ifndef PSIMPL_GENERIC 00093 #define PSIMPL_GENERIC 00094 00095 00096 #include <queue> 00097 #include <stack> 00098 #include <numeric> 00099 #include <algorithm> 00100 #include <cmath> 00101 00102 00106 namespace psimpl 00107 { 00111 namespace util 00112 { 00118 template <typename T> 00119 class scoped_array 00120 { 00121 public: 00122 scoped_array (unsigned n) { 00123 array = new T [n]; 00124 } 00125 00126 ~scoped_array () { 00127 delete [] array; 00128 } 00129 00130 T& operator [] (int offset) { 00131 return array [offset]; 00132 } 00133 00134 const T& operator [] (int offset) const { 00135 return array [offset]; 00136 } 00137 00138 T* get () const { 00139 return array; 00140 } 00141 00142 void swap (scoped_array& b) { 00143 T* tmp = b.array; 00144 b.array = array; 00145 array = tmp; 00146 } 00147 00148 private: 00149 scoped_array (const scoped_array&); 00150 scoped_array& operator= (const scoped_array&); 00151 00152 private: 00153 T* array; 00154 }; 00155 00156 template <typename T> inline void swap (scoped_array <T>& a, scoped_array <T>& b) { 00157 a.swap (b); 00158 } 00159 } 00160 00164 namespace math 00165 { 00169 struct Statistics 00170 { 00171 Statistics () : 00172 max (0), 00173 sum (0), 00174 mean (0), 00175 std (0) 00176 {} 00177 00178 double max; 00179 double sum; 00180 double mean; 00181 double std; 00182 }; 00183 00191 template <unsigned DIM, class InputIterator> 00192 inline bool equal ( 00193 InputIterator p1, 00194 InputIterator p2) 00195 { 00196 for (unsigned d = 0; d < DIM; ++d) { 00197 if (*p1 != *p2) { 00198 return false; 00199 } 00200 ++p1; 00201 ++p2; 00202 } 00203 return true; 00204 } 00205 00214 template <unsigned DIM, class InputIterator, class OutputIterator> 00215 inline OutputIterator make_vector ( 00216 InputIterator p1, 00217 InputIterator p2, 00218 OutputIterator result) 00219 { 00220 for (unsigned d = 0; d < DIM; ++d) { 00221 *result = *p2 - *p1; 00222 ++result; 00223 ++p1; 00224 ++p2; 00225 } 00226 return result; 00227 } 00228 00236 template <unsigned DIM, class InputIterator> 00237 inline typename std::iterator_traits <InputIterator>::value_type dot ( 00238 InputIterator v1, 00239 InputIterator v2) 00240 { 00241 typename std::iterator_traits <InputIterator>::value_type result = 0; 00242 for (unsigned d = 0; d < DIM; ++d) { 00243 result += (*v1) * (*v2); 00244 ++v1; 00245 ++v2; 00246 } 00247 return result; 00248 } 00249 00259 template <unsigned DIM, class InputIterator, class OutputIterator> 00260 inline OutputIterator interpolate ( 00261 InputIterator p1, 00262 InputIterator p2, 00263 float fraction, 00264 OutputIterator result) 00265 { 00266 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00267 00268 for (unsigned d = 0; d < DIM; ++d) { 00269 *result = *p1 + static_cast <value_type> (fraction * (*p2 - *p1)); 00270 ++result; 00271 ++p1; 00272 ++p2; 00273 } 00274 return result; 00275 } 00276 00284 template <unsigned DIM, class InputIterator1, class InputIterator2> 00285 inline typename std::iterator_traits <InputIterator1>::value_type point_distance2 ( 00286 InputIterator1 p1, 00287 InputIterator2 p2) 00288 { 00289 typename std::iterator_traits <InputIterator1>::value_type result = 0; 00290 for (unsigned d = 0; d < DIM; ++d) { 00291 result += (*p1 - *p2) * (*p1 - *p2); 00292 ++p1; 00293 ++p2; 00294 } 00295 return result; 00296 } 00297 00306 template <unsigned DIM, class InputIterator> 00307 inline typename std::iterator_traits <InputIterator>::value_type line_distance2 ( 00308 InputIterator l1, 00309 InputIterator l2, 00310 InputIterator p) 00311 { 00312 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00313 00314 value_type v [DIM]; // vector l1 --> l2 00315 value_type w [DIM]; // vector l1 --> p 00316 00317 make_vector <DIM> (l1, l2, v); 00318 make_vector <DIM> (l1, p, w); 00319 00320 value_type cv = dot <DIM> (v, v); // squared length of v 00321 value_type cw = dot <DIM> (w, v); // project w onto v 00322 00323 // avoid problems with divisions when value_type is an integer type 00324 float fraction = cv == 0 ? 0 : static_cast <float> (cw) / static_cast <float> (cv); 00325 00326 value_type proj [DIM]; // p projected onto line (l1, l2) 00327 interpolate <DIM> (l1, l2, fraction, proj); 00328 00329 return point_distance2 <DIM> (p, proj); 00330 } 00331 00340 template <unsigned DIM, class InputIterator> 00341 inline typename std::iterator_traits <InputIterator>::value_type segment_distance2 ( 00342 InputIterator s1, 00343 InputIterator s2, 00344 InputIterator p) 00345 { 00346 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00347 00348 value_type v [DIM]; // vector s1 --> s2 00349 value_type w [DIM]; // vector s1 --> p 00350 00351 make_vector <DIM> (s1, s2, v); 00352 make_vector <DIM> (s1, p, w); 00353 00354 value_type cw = dot <DIM> (w, v); // project w onto v 00355 if (cw <= 0) { 00356 // projection of w lies to the left of s1 00357 return point_distance2 <DIM> (p, s1); 00358 } 00359 00360 value_type cv = dot <DIM> (v, v); // squared length of v 00361 if (cv <= cw) { 00362 // projection of w lies to the right of s2 00363 return point_distance2 <DIM> (p, s2); 00364 } 00365 00366 // avoid problems with divisions when value_type is an integer type 00367 float fraction = cv == 0 ? 0 : static_cast <float> (cw) / static_cast <float> (cv); 00368 00369 value_type proj [DIM]; // p projected onto segement (s1, s2) 00370 interpolate <DIM> (s1, s2, fraction, proj); 00371 00372 return point_distance2 <DIM> (p, proj); 00373 } 00374 00383 template <unsigned DIM, class InputIterator> 00384 inline typename std::iterator_traits <InputIterator>::value_type ray_distance2 ( 00385 InputIterator r1, 00386 InputIterator r2, 00387 InputIterator p) 00388 { 00389 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00390 00391 value_type v [DIM]; // vector r1 --> r2 00392 value_type w [DIM]; // vector r1 --> p 00393 00394 make_vector <DIM> (r1, r2, v); 00395 make_vector <DIM> (r1, p, w); 00396 00397 value_type cv = dot <DIM> (v, v); // squared length of v 00398 value_type cw = dot <DIM> (w, v); // project w onto v 00399 00400 if (cw <= 0) { 00401 // projection of w lies to the left of r1 (not on the ray) 00402 return point_distance2 <DIM> (p, r1); 00403 } 00404 00405 // avoid problems with divisions when value_type is an integer type 00406 float fraction = cv == 0 ? 0 : static_cast <float> (cw) / static_cast <float> (cv); 00407 00408 value_type proj [DIM]; // p projected onto ray (r1, r2) 00409 interpolate <DIM> (r1, r2, fraction, proj); 00410 00411 return point_distance2 <DIM> (p, proj); 00412 } 00413 00421 template <class InputIterator> 00422 inline Statistics compute_statistics ( 00423 InputIterator first, 00424 InputIterator last) 00425 { 00426 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00427 typedef typename std::iterator_traits <InputIterator>::difference_type diff_type; 00428 00429 Statistics stats; 00430 00431 diff_type count = std::distance (first, last); 00432 if (count == 0) { 00433 return stats; 00434 } 00435 00436 value_type init = 0; 00437 stats.max = static_cast <double> (*std::max_element (first, last)); 00438 stats.sum = static_cast <double> (std::accumulate (first, last, init)); 00439 stats.mean = stats.sum / count; 00440 std::transform (first, last, first, std::bind2nd (std::minus <value_type> (), stats.mean)); 00441 stats.std = std::sqrt (static_cast <double> (std::inner_product (first, last, first, init)) / count); 00442 return stats; 00443 } 00444 } 00445 00453 template <unsigned DIM, class InputIterator, class OutputIterator> 00454 class PolylineSimplification 00455 { 00456 typedef typename std::iterator_traits <InputIterator>::difference_type diff_type; 00457 typedef typename std::iterator_traits <InputIterator>::value_type value_type; 00458 typedef typename std::iterator_traits <const value_type*>::difference_type ptr_diff_type; 00459 00460 public: 00492 OutputIterator NthPoint ( 00493 InputIterator first, 00494 InputIterator last, 00495 unsigned n, 00496 OutputIterator result) 00497 { 00498 diff_type coordCount = std::distance (first, last); 00499 diff_type pointCount = DIM // protect against zero DIM 00500 ? coordCount / DIM 00501 : 0; 00502 00503 // validate input and check if simplification required 00504 if (coordCount % DIM || pointCount < 3 || n < 2) { 00505 return std::copy (first, last, result); 00506 } 00507 00508 unsigned remaining = pointCount - 1; // the number of points remaining after key 00509 InputIterator key = first; // indicates the current key 00510 00511 // the first point is always part of the simplification 00512 CopyKey (key, result); 00513 00514 // copy each nth point 00515 while (Forward (key, n, remaining)) { 00516 CopyKey (key, result); 00517 } 00518 00519 return result; 00520 } 00521 00554 OutputIterator RadialDistance ( 00555 InputIterator first, 00556 InputIterator last, 00557 value_type tol, 00558 OutputIterator result) 00559 { 00560 diff_type coordCount = std::distance (first, last); 00561 diff_type pointCount = DIM // protect against zero DIM 00562 ? coordCount / DIM 00563 : 0; 00564 value_type tol2 = tol * tol; // squared distance tolerance 00565 00566 // validate input and check if simplification required 00567 if (coordCount % DIM || pointCount < 3 || tol2 == 0) { 00568 return std::copy (first, last, result); 00569 } 00570 00571 InputIterator current = first; // indicates the current key 00572 InputIterator next = first; // used to find the next key 00573 00574 // the first point is always part of the simplification 00575 CopyKeyAdvance (next, result); 00576 00577 // Skip first and last point, because they are always part of the simplification 00578 for (diff_type index = 1; index < pointCount - 1; ++index) { 00579 if (math::point_distance2 <DIM> (current, next) < tol2) { 00580 Advance (next); 00581 continue; 00582 } 00583 current = next; 00584 CopyKeyAdvance (next, result); 00585 } 00586 // the last point is always part of the simplification 00587 CopyKeyAdvance (next, result); 00588 00589 return result; 00590 } 00591 00608 OutputIterator PerpendicularDistance ( 00609 InputIterator first, 00610 InputIterator last, 00611 value_type tol, 00612 unsigned repeat, 00613 OutputIterator result) 00614 { 00615 if (repeat == 1) { 00616 // single pass 00617 return PerpendicularDistance (first, last, tol, result); 00618 } 00619 // only validate repeat; other input is validated by simplify_perpendicular_distance 00620 if (repeat < 1) { 00621 return std::copy (first, last, result); 00622 } 00623 diff_type coordCount = std::distance (first, last); 00624 00625 // first pass: [first, last) --> temporary array 'tempPoly' 00626 util::scoped_array <value_type> tempPoly (coordCount); 00627 PolylineSimplification <DIM, InputIterator, value_type*> psimpl_to_array; 00628 diff_type tempCoordCount = std::distance (tempPoly.get (), 00629 psimpl_to_array.PerpendicularDistance (first, last, tol, tempPoly.get ())); 00630 00631 // check if simplification did not improved 00632 if (coordCount == tempCoordCount) { 00633 return std::copy (tempPoly.get (), tempPoly.get () + coordCount, result); 00634 } 00635 std::swap (coordCount, tempCoordCount); 00636 --repeat; 00637 00638 // intermediate passes: temporary array 'tempPoly' --> temporary array 'tempResult' 00639 if (1 < repeat) { 00640 util::scoped_array <value_type> tempResult (coordCount); 00641 PolylineSimplification <DIM, value_type*, value_type*> psimpl_arrays; 00642 00643 while (--repeat) { 00644 tempCoordCount = std::distance (tempResult.get (), 00645 psimpl_arrays.PerpendicularDistance ( 00646 tempPoly.get (), tempPoly.get () + coordCount, tol, tempResult.get ())); 00647 00648 // check if simplification did not improved 00649 if (coordCount == tempCoordCount) { 00650 return std::copy (tempPoly.get (), tempPoly.get () + coordCount, result); 00651 } 00652 util::swap (tempPoly, tempResult); 00653 std::swap (coordCount, tempCoordCount); 00654 } 00655 } 00656 00657 // final pass: temporary array 'tempPoly' --> result 00658 PolylineSimplification <DIM, value_type*, OutputIterator> psimpl_from_array; 00659 return psimpl_from_array.PerpendicularDistance ( 00660 tempPoly.get (), tempPoly.get () + coordCount, tol, result); 00661 } 00662 00697 OutputIterator PerpendicularDistance ( 00698 InputIterator first, 00699 InputIterator last, 00700 value_type tol, 00701 OutputIterator result) 00702 { 00703 diff_type coordCount = std::distance (first, last); 00704 diff_type pointCount = DIM // protect against zero DIM 00705 ? coordCount / DIM 00706 : 0; 00707 value_type tol2 = tol * tol; // squared distance tolerance 00708 00709 // validate input and check if simplification required 00710 if (coordCount % DIM || pointCount < 3 || tol2 == 0) { 00711 return std::copy (first, last, result); 00712 } 00713 00714 InputIterator p0 = first; 00715 InputIterator p1 = AdvanceCopy(p0); 00716 InputIterator p2 = AdvanceCopy(p1); 00717 00718 // the first point is always part of the simplification 00719 CopyKey (p0, result); 00720 00721 while (p2 != last) { 00722 // test p1 against line segment S(p0, p2) 00723 if (math::segment_distance2 <DIM> (p0, p2, p1) < tol2) { 00724 CopyKey (p2, result); 00725 // move up by two points 00726 p0 = p2; 00727 Advance (p1, 2); 00728 if (p1 == last) { 00729 // protect against advancing p2 beyond last 00730 break; 00731 } 00732 Advance (p2, 2); 00733 } 00734 else { 00735 CopyKey (p1, result); 00736 // move up by one point 00737 p0 = p1; 00738 p1 = p2; 00739 Advance (p2); 00740 } 00741 } 00742 // make sure the last point is part of the simplification 00743 if (p1 != last) { 00744 CopyKey (p1, result); 00745 } 00746 return result; 00747 } 00748 00783 OutputIterator ReumannWitkam ( 00784 InputIterator first, 00785 InputIterator last, 00786 value_type tol, 00787 OutputIterator result) 00788 { 00789 diff_type coordCount = std::distance (first, last); 00790 diff_type pointCount = DIM // protect against zero DIM 00791 ? coordCount / DIM 00792 : 0; 00793 value_type tol2 = tol * tol; // squared distance tolerance 00794 00795 // validate input and check if simplification required 00796 if (coordCount % DIM || pointCount < 3 || tol2 == 0) { 00797 return std::copy (first, last, result); 00798 } 00799 00800 // define the line L(p0, p1) 00801 InputIterator p0 = first; // indicates the current key 00802 InputIterator p1 = AdvanceCopy (first); // indicates the next point after p0 00803 00804 // keep track of two test points 00805 InputIterator pi = p1; // the previous test point 00806 InputIterator pj = p1; // the current test point (pi+1) 00807 00808 // the first point is always part of the simplification 00809 CopyKey (p0, result); 00810 00811 // check each point pj against L(p0, p1) 00812 for (diff_type j = 2; j < pointCount; ++j) { 00813 pi = pj; 00814 Advance (pj); 00815 00816 if (math::line_distance2 <DIM> (p0, p1, pj) < tol2) { 00817 continue; 00818 } 00819 // found the next key at pi 00820 CopyKey (pi, result); 00821 // define new line L(pi, pj) 00822 p0 = pi; 00823 p1 = pj; 00824 } 00825 // the last point is always part of the simplification 00826 CopyKey (pj, result); 00827 00828 return result; 00829 } 00830 00872 OutputIterator Opheim ( 00873 InputIterator first, 00874 InputIterator last, 00875 value_type min_tol, 00876 value_type max_tol, 00877 OutputIterator result) 00878 { 00879 diff_type coordCount = std::distance (first, last); 00880 diff_type pointCount = DIM // protect against zero DIM 00881 ? coordCount / DIM 00882 : 0; 00883 value_type min_tol2 = min_tol * min_tol; // squared minimum distance tolerance 00884 value_type max_tol2 = max_tol * max_tol; // squared maximum distance tolerance 00885 00886 // validate input and check if simplification required 00887 if (coordCount % DIM || pointCount < 3 || min_tol2 == 0 || max_tol2 == 0) { 00888 return std::copy (first, last, result); 00889 } 00890 00891 // define the ray R(r0, r1) 00892 InputIterator r0 = first; // indicates the current key and start of the ray 00893 InputIterator r1 = first; // indicates a point on the ray 00894 bool rayDefined = false; 00895 00896 // keep track of two test points 00897 InputIterator pi = r0; // the previous test point 00898 InputIterator pj = // the current test point (pi+1) 00899 AdvanceCopy (pi); 00900 00901 // the first point is always part of the simplification 00902 CopyKey (r0, result); 00903 00904 for (diff_type j = 2; j < pointCount; ++j) { 00905 pi = pj; 00906 Advance (pj); 00907 00908 if (!rayDefined) { 00909 // discard each point within minimum tolerance 00910 if (math::point_distance2 <DIM> (r0, pj) < min_tol2) { 00911 continue; 00912 } 00913 // the last point within minimum tolerance pi defines the ray R(r0, r1) 00914 r1 = pi; 00915 rayDefined = true; 00916 } 00917 00918 // check each point pj against R(r0, r1) 00919 if (math::point_distance2 <DIM> (r0, pj) < max_tol2 && 00920 math::ray_distance2 <DIM> (r0, r1, pj) < min_tol2) 00921 { 00922 continue; 00923 } 00924 // found the next key at pi 00925 CopyKey (pi, result); 00926 // define new ray R(pi, pj) 00927 r0 = pi; 00928 rayDefined = false; 00929 } 00930 // the last point is always part of the simplification 00931 CopyKey (pj, result); 00932 00933 return result; 00934 } 00935 00978 OutputIterator Lang ( 00979 InputIterator first, 00980 InputIterator last, 00981 value_type tol, 00982 unsigned look_ahead, 00983 OutputIterator result) 00984 { 00985 diff_type coordCount = std::distance (first, last); 00986 diff_type pointCount = DIM // protect against zero DIM 00987 ? coordCount / DIM 00988 : 0; 00989 value_type tol2 = tol * tol; // squared minimum distance tolerance 00990 00991 // validate input and check if simplification required 00992 if (coordCount % DIM || pointCount < 3 || look_ahead < 2 || tol2 == 0) { 00993 return std::copy (first, last, result); 00994 } 00995 00996 InputIterator current = first; // indicates the current key 00997 InputIterator next = first; // used to find the next key 00998 00999 unsigned remaining = pointCount - 1; // the number of points remaining after current 01000 unsigned moved = Forward (next, look_ahead, remaining); 01001 01002 // the first point is always part of the simplification 01003 CopyKey (current, result); 01004 01005 while (moved) { 01006 value_type d2 = 0; 01007 InputIterator p = AdvanceCopy (current); 01008 01009 while (p != next) { 01010 d2 = std::max (d2, math::segment_distance2 <DIM> (current, next, p)); 01011 if (tol2 < d2) { 01012 break; 01013 } 01014 Advance (p); 01015 } 01016 if (d2 < tol2) { 01017 current = next; 01018 CopyKey (current, result); 01019 moved = Forward (next, look_ahead, remaining); 01020 } 01021 else { 01022 Backward (next, remaining); 01023 } 01024 } 01025 return result; 01026 } 01027 01070 OutputIterator DouglasPeucker ( 01071 InputIterator first, 01072 InputIterator last, 01073 value_type tol, 01074 OutputIterator result) 01075 { 01076 diff_type coordCount = std::distance (first, last); 01077 diff_type pointCount = DIM // protect against zero DIM 01078 ? coordCount / DIM 01079 : 0; 01080 // validate input and check if simplification required 01081 if (coordCount % DIM || pointCount < 3 || tol == 0) { 01082 return std::copy (first, last, result); 01083 } 01084 // radial distance routine as preprocessing 01085 util::scoped_array <value_type> reduced (coordCount); // radial distance results 01086 PolylineSimplification <DIM, InputIterator, value_type*> psimpl_to_array; 01087 ptr_diff_type reducedCoordCount = std::distance (reduced.get (), 01088 psimpl_to_array.RadialDistance (first, last, tol, reduced.get ())); 01089 ptr_diff_type reducedPointCount = reducedCoordCount / DIM; 01090 01091 // douglas-peucker approximation 01092 util::scoped_array <unsigned char> keys (pointCount); // douglas-peucker results 01093 DPHelper::Approximate (reduced.get (), reducedCoordCount, tol, keys.get ()); 01094 01095 // copy all keys 01096 const value_type* current = reduced.get (); 01097 for (ptr_diff_type p=0; p<reducedPointCount; ++p, current += DIM) { 01098 if (keys [p]) { 01099 for (unsigned d = 0; d < DIM; ++d) { 01100 *result = current [d]; 01101 ++result; 01102 } 01103 } 01104 } 01105 return result; 01106 } 01107 01147 OutputIterator DouglasPeuckerN ( 01148 InputIterator first, 01149 InputIterator last, 01150 unsigned count, 01151 OutputIterator result) 01152 { 01153 diff_type coordCount = std::distance (first, last); 01154 diff_type pointCount = DIM // protect against zero DIM 01155 ? coordCount / DIM 01156 : 0; 01157 // validate input and check if simplification required 01158 if (coordCount % DIM || pointCount <= static_cast <diff_type> (count) || count < 2) { 01159 return std::copy (first, last, result); 01160 } 01161 01162 // copy coords 01163 util::scoped_array <value_type> coords (coordCount); 01164 for (ptr_diff_type c=0; c<coordCount; ++c) { 01165 coords [c] = *first; 01166 ++first; 01167 } 01168 01169 // douglas-peucker approximation 01170 util::scoped_array <unsigned char> keys (pointCount); 01171 DPHelper::ApproximateN (coords.get (), coordCount, count, keys.get ()); 01172 01173 // copy keys 01174 const value_type* current = coords.get (); 01175 for (ptr_diff_type p=0; p<pointCount; ++p, current += DIM) { 01176 if (keys [p]) { 01177 for (unsigned d = 0; d < DIM; ++d) { 01178 *result = current [d]; 01179 ++result; 01180 } 01181 } 01182 } 01183 return result; 01184 } 01185 01224 OutputIterator ComputePositionalErrors2 ( 01225 InputIterator original_first, 01226 InputIterator original_last, 01227 InputIterator simplified_first, 01228 InputIterator simplified_last, 01229 OutputIterator result, 01230 bool* valid=0) 01231 { 01232 diff_type original_coordCount = std::distance (original_first, original_last); 01233 diff_type original_pointCount = DIM // protect against zero DIM 01234 ? original_coordCount / DIM 01235 : 0; 01236 01237 diff_type simplified_coordCount = std::distance (simplified_first, simplified_last); 01238 diff_type simplified_pointCount = DIM // protect against zero DIM 01239 ? simplified_coordCount / DIM 01240 : 0; 01241 01242 // validate input 01243 if (original_coordCount % DIM || original_pointCount < 2 || 01244 simplified_coordCount % DIM || simplified_pointCount < 2 || 01245 original_pointCount < simplified_pointCount || 01246 !math::equal <DIM> (original_first, simplified_first)) 01247 { 01248 if (valid) { 01249 *valid = false; 01250 } 01251 return result; 01252 } 01253 01254 // define (simplified) line segment S(simplified_prev, simplified_first) 01255 InputIterator simplified_prev = simplified_first; 01256 std::advance (simplified_first, DIM); 01257 01258 // process each simplified line segment 01259 while (simplified_first != simplified_last) { 01260 // process each original point until it equals the end of the line segment 01261 while (original_first != original_last && 01262 !math::equal <DIM> (original_first, simplified_first)) 01263 { 01264 *result = math::segment_distance2 <DIM> (simplified_prev, simplified_first, 01265 original_first); 01266 ++result; 01267 std::advance (original_first, DIM); 01268 } 01269 // update line segment S 01270 simplified_prev = simplified_first; 01271 std::advance (simplified_first, DIM); 01272 } 01273 // check if last original point matched 01274 if (original_first != original_last) { 01275 *result = 0; 01276 ++result; 01277 } 01278 01279 if (valid) { 01280 *valid = original_first != original_last; 01281 } 01282 return result; 01283 } 01284 01317 math::Statistics ComputePositionalErrorStatistics ( 01318 InputIterator original_first, 01319 InputIterator original_last, 01320 InputIterator simplified_first, 01321 InputIterator simplified_last, 01322 bool* valid=0) 01323 { 01324 diff_type pointCount = std::distance (original_first, original_last) / DIM; 01325 util::scoped_array <double> errors (pointCount); 01326 PolylineSimplification <DIM, InputIterator, double*> ps; 01327 01328 diff_type errorCount = 01329 std::distance ( 01330 errors.get (), 01331 ps.ComputePositionalErrors2 (original_first, original_last, 01332 simplified_first, simplified_last, 01333 errors.get (), valid)); 01334 01335 std::transform (errors.get (), errors.get () + errorCount, 01336 errors.get (), 01337 std::ptr_fun <double, double> (std::sqrt)); 01338 01339 return math::compute_statistics (errors.get (), errors.get () + errorCount); 01340 } 01341 01342 private: 01351 inline void CopyKeyAdvance ( 01352 InputIterator& key, 01353 OutputIterator& result) 01354 { 01355 for (unsigned d = 0; d < DIM; ++d) { 01356 *result = *key; 01357 ++result; 01358 ++key; 01359 } 01360 } 01361 01370 inline void CopyKey ( 01371 InputIterator key, 01372 OutputIterator& result) 01373 { 01374 CopyKeyAdvance (key, result); 01375 } 01376 01385 inline void Advance ( 01386 InputIterator& it, 01387 diff_type n = 1) 01388 { 01389 std::advance (it, n * static_cast <diff_type> (DIM)); 01390 } 01391 01401 inline InputIterator AdvanceCopy ( 01402 InputIterator it, 01403 diff_type n = 1) 01404 { 01405 Advance (it, n); 01406 return it; 01407 } 01408 01422 inline unsigned Forward ( 01423 InputIterator& it, 01424 unsigned n, 01425 unsigned& remaining) 01426 { 01427 n = std::min (n, remaining); 01428 Advance (it, n); 01429 remaining -= n; 01430 return n; 01431 } 01432 01441 inline void Backward ( 01442 InputIterator& it, 01443 unsigned& remaining) 01444 { 01445 Advance (it, -1); 01446 ++remaining; 01447 } 01448 01449 private: 01457 class DPHelper 01458 { 01460 struct SubPoly { 01461 SubPoly (ptr_diff_type first=0, ptr_diff_type last=0) : 01462 first (first), last (last) {} 01463 01464 ptr_diff_type first; 01465 ptr_diff_type last; 01466 }; 01467 01469 struct KeyInfo { 01470 KeyInfo (ptr_diff_type index=0, value_type dist2=0) : 01471 index (index), dist2 (dist2) {} 01472 01473 ptr_diff_type index; 01474 value_type dist2; 01475 }; 01476 01478 struct SubPolyAlt { 01479 SubPolyAlt (ptr_diff_type first=0, ptr_diff_type last=0) : 01480 first (first), last (last) {} 01481 01482 ptr_diff_type first; 01483 ptr_diff_type last; 01484 KeyInfo keyInfo; 01485 01486 bool operator< (const SubPolyAlt& other) const { 01487 return keyInfo.dist2 < other.keyInfo.dist2; 01488 } 01489 }; 01490 01491 public: 01500 static void Approximate ( 01501 const value_type* coords, 01502 ptr_diff_type coordCount, 01503 value_type tol, 01504 unsigned char* keys) 01505 { 01506 value_type tol2 = tol * tol; // squared distance tolerance 01507 ptr_diff_type pointCount = coordCount / DIM; 01508 // zero out keys 01509 std::fill_n (keys, pointCount, 0); 01510 keys [0] = 1; // the first point is always a key 01511 keys [pointCount - 1] = 1; // the last point is always a key 01512 01513 typedef std::stack <SubPoly> Stack; 01514 Stack stack; // LIFO job-queue containing sub-polylines 01515 01516 SubPoly subPoly (0, coordCount-DIM); 01517 stack.push (subPoly); // add complete poly 01518 01519 while (!stack.empty ()) { 01520 subPoly = stack.top (); // take a sub poly 01521 stack.pop (); // and find its key 01522 KeyInfo keyInfo = FindKey (coords, subPoly.first, subPoly.last); 01523 if (keyInfo.index && tol2 < keyInfo.dist2) { 01524 // store the key if valid 01525 keys [keyInfo.index / DIM] = 1; 01526 // split the polyline at the key and recurse 01527 stack.push (SubPoly (keyInfo.index, subPoly.last)); 01528 stack.push (SubPoly (subPoly.first, keyInfo.index)); 01529 } 01530 } 01531 } 01532 01541 static void ApproximateN ( 01542 const value_type* coords, 01543 ptr_diff_type coordCount, 01544 unsigned countTol, 01545 unsigned char* keys) 01546 { 01547 ptr_diff_type pointCount = coordCount / DIM; 01548 // zero out keys 01549 std::fill_n (keys, pointCount, 0); 01550 keys [0] = 1; // the first point is always a key 01551 keys [pointCount - 1] = 1; // the last point is always a key 01552 unsigned keyCount = 2; 01553 01554 if (countTol == 2) { 01555 return; 01556 } 01557 01558 typedef std::priority_queue <SubPolyAlt> PriorityQueue; 01559 PriorityQueue queue; // sorted (max dist2) job queue containing sub-polylines 01560 01561 SubPolyAlt subPoly (0, coordCount-DIM); 01562 subPoly.keyInfo = FindKey (coords, subPoly.first, subPoly.last); 01563 queue.push (subPoly); // add complete poly 01564 01565 while (!queue.empty ()) { 01566 subPoly = queue.top (); // take a sub poly 01567 queue.pop (); 01568 // store the key 01569 keys [subPoly.keyInfo.index / DIM] = 1; 01570 // check point count tolerance 01571 keyCount++; 01572 if (keyCount == countTol) { 01573 break; 01574 } 01575 // split the polyline at the key and recurse 01576 SubPolyAlt left (subPoly.first, subPoly.keyInfo.index); 01577 left.keyInfo = FindKey (coords, left.first, left.last); 01578 if (left.keyInfo.index) { 01579 queue.push (left); 01580 } 01581 SubPolyAlt right (subPoly.keyInfo.index, subPoly.last); 01582 right.keyInfo = FindKey (coords, right.first, right.last); 01583 if (right.keyInfo.index) { 01584 queue.push (right); 01585 } 01586 } 01587 } 01588 01589 private: 01602 static KeyInfo FindKey ( 01603 const value_type* coords, 01604 ptr_diff_type first, 01605 ptr_diff_type last) 01606 { 01607 KeyInfo keyInfo; 01608 01609 for (ptr_diff_type current = first + DIM; current < last; current += DIM) { 01610 value_type d2 = math::segment_distance2 <DIM> (coords + first, coords + last, 01611 coords + current); 01612 if (d2 < keyInfo.dist2) { 01613 continue; 01614 } 01615 // update maximum squared distance and the point it belongs to 01616 keyInfo.index = current; 01617 keyInfo.dist2 = d2; 01618 } 01619 return keyInfo; 01620 } 01621 }; 01622 }; 01623 01636 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01637 OutputIterator simplify_nth_point ( 01638 ForwardIterator first, 01639 ForwardIterator last, 01640 unsigned n, 01641 OutputIterator result) 01642 { 01643 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01644 return ps.NthPoint (first, last, n, result); 01645 } 01646 01659 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01660 OutputIterator simplify_radial_distance ( 01661 ForwardIterator first, 01662 ForwardIterator last, 01663 typename std::iterator_traits <ForwardIterator>::value_type tol, 01664 OutputIterator result) 01665 { 01666 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01667 return ps.RadialDistance (first, last, tol, result); 01668 } 01669 01683 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01684 OutputIterator simplify_perpendicular_distance ( 01685 ForwardIterator first, 01686 ForwardIterator last, 01687 typename std::iterator_traits <ForwardIterator>::value_type tol, 01688 unsigned repeat, 01689 OutputIterator result) 01690 { 01691 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01692 return ps.PerpendicularDistance (first, last, tol, repeat, result); 01693 } 01694 01707 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01708 OutputIterator simplify_perpendicular_distance ( 01709 ForwardIterator first, 01710 ForwardIterator last, 01711 typename std::iterator_traits <ForwardIterator>::value_type tol, 01712 OutputIterator result) 01713 { 01714 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01715 return ps.PerpendicularDistance (first, last, tol, result); 01716 } 01717 01730 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01731 OutputIterator simplify_reumann_witkam ( 01732 ForwardIterator first, 01733 ForwardIterator last, 01734 typename std::iterator_traits <ForwardIterator>::value_type tol, 01735 OutputIterator result) 01736 { 01737 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01738 return ps.ReumannWitkam (first, last, tol, result); 01739 } 01740 01754 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01755 OutputIterator simplify_opheim ( 01756 ForwardIterator first, 01757 ForwardIterator last, 01758 typename std::iterator_traits <ForwardIterator>::value_type min_tol, 01759 typename std::iterator_traits <ForwardIterator>::value_type max_tol, 01760 OutputIterator result) 01761 { 01762 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01763 return ps.Opheim (first, last, min_tol, max_tol, result); 01764 } 01765 01779 template <unsigned DIM, class BidirectionalIterator, class OutputIterator> 01780 OutputIterator simplify_lang ( 01781 BidirectionalIterator first, 01782 BidirectionalIterator last, 01783 typename std::iterator_traits <BidirectionalIterator>::value_type tol, 01784 unsigned look_ahead, 01785 OutputIterator result) 01786 { 01787 PolylineSimplification <DIM, BidirectionalIterator, OutputIterator> ps; 01788 return ps.Lang (first, last, tol, look_ahead, result); 01789 } 01790 01803 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01804 OutputIterator simplify_douglas_peucker ( 01805 ForwardIterator first, 01806 ForwardIterator last, 01807 typename std::iterator_traits <ForwardIterator>::value_type tol, 01808 OutputIterator result) 01809 { 01810 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01811 return ps.DouglasPeucker (first, last, tol, result); 01812 } 01813 01826 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01827 OutputIterator simplify_douglas_peucker_n ( 01828 ForwardIterator first, 01829 ForwardIterator last, 01830 unsigned count, 01831 OutputIterator result) 01832 { 01833 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01834 return ps.DouglasPeuckerN (first, last, count, result); 01835 } 01836 01851 template <unsigned DIM, class ForwardIterator, class OutputIterator> 01852 OutputIterator compute_positional_errors2 ( 01853 ForwardIterator original_first, 01854 ForwardIterator original_last, 01855 ForwardIterator simplified_first, 01856 ForwardIterator simplified_last, 01857 OutputIterator result, 01858 bool* valid=0) 01859 { 01860 PolylineSimplification <DIM, ForwardIterator, OutputIterator> ps; 01861 return ps.ComputePositionalErrors2 (original_first, original_last, simplified_first, simplified_last, result, valid); 01862 } 01863 01877 template <unsigned DIM, class ForwardIterator> 01878 math::Statistics compute_positional_error_statistics ( 01879 ForwardIterator original_first, 01880 ForwardIterator original_last, 01881 ForwardIterator simplified_first, 01882 ForwardIterator simplified_last, 01883 bool* valid=0) 01884 { 01885 PolylineSimplification <DIM, ForwardIterator, ForwardIterator> ps; 01886 return ps.ComputePositionalErrorStatistics (original_first, original_last, simplified_first, simplified_last, valid); 01887 } 01888 } 01889 01890 #endif // PSIMPL_GENERIC