Ticket #6063: boost_polygon_bug6063_fix3.patch
File boost_polygon_bug6063_fix3.patch, 10.9 KB (added by , 11 years ago) |
---|
-
detail/minkowski.hpp
diff -dur orig_polygon/detail/minkowski.hpp polygon/detail/minkowski.hpp
old new 82 82 } 83 83 template<typename T> 84 84 inline polygon_set_data<T>& 85 polygon_set_data<T>::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments) { 85 polygon_set_data<T>::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, 86 double minUnroundedAngleDegrees) { 86 87 using namespace ::boost::polygon::operators; 87 if(!corner_fill_arc) { 88 if(resizing == 0) return *this; 89 if(empty()) return *this; 90 if(!corner_fill_arc || minUnroundedAngleDegrees<=0.0) { 88 91 if(resizing < 0) 89 92 return shrink(-resizing); 90 if(resizing > 0)93 else 91 94 return bloat(resizing); 92 return *this;93 95 } 94 if(resizing == 0) return *this; 95 if(empty()) return *this; 96 96 97 if(num_circle_segments < 3) num_circle_segments = 4; 97 98 rectangle_data<coordinate_type> rect; 98 99 extents(rect); … … 100 101 ::boost::polygon::bloat(rect, 10); 101 102 (*this) = rect - (*this); //invert 102 103 } 103 //make_arc(std::vector<point_data< T> >& return_points, 104 //point_data< double> start, point_data< double> end, 105 //point_data< double> center, double r, unsigned int num_circle_segments) 104 105 // scale arc up so that minimum radius corresponds to 'resizing', 106 // for bug ticket #6063. 107 const double our_pi=3.1415926535897932384626433832795028841971; 108 double arcRadScaling = 1.0/cos(our_pi/double(num_circle_segments)); 109 double arcRadius = double(std::abs(resizing))*arcRadScaling; 110 111 if(minUnroundedAngleDegrees < 180.0) 112 { 113 // Don't round corners less than given angle (in radians). 114 // We do this by setting the minimum radius of the 'circle' to correspond to 115 // the distance to the 'elbow' created by normal offset of a corner with the given angle. 116 // e.g. an 90-degree corner with an offset of 1 will generate an elbow-corner at distance sqrt(2), 117 // so if \param minUnroundedAngleDegrees=90, we set the circle radius to offset*sqrt(2)*arcRadScaling. 118 // This will of course offset non-corners more than the given resizing, but the extra area 119 // gets chopped off by the intersection with normal_offset_result, below. 120 double elbowDist = double(std::abs(resizing))/sin(minUnroundedAngleDegrees*our_pi/180.0/2.0); 121 arcRadius = elbowDist*arcRadScaling; 122 } 123 124 // Note: By setting round_away_from_center=true, we make a 'circle polygon' here that is actually the result of 125 // calling round_away<coordinate_type>(pt, center) on the vertices of a circle polygon. 126 // Previously (see bug ticket #6063) we were using round_down instead of round_away, with the result that 127 // the elbowDist and arcRadScaling above were sometimes insufficient to avoid rounding corners 128 // with angle >= minUnroundedAngleDegrees, due to integer precision. 129 bool round_away_from_center = true; 130 106 131 std::vector<point_data<coordinate_type> > circle; 107 point_data<double> center(0.0, 0.0), start(0.0, (double)resizing); 108 make_arc(circle, start, start, center, std::abs((double)resizing), 109 num_circle_segments); 132 point_data<double> center(0.0, 0.0), start(0.0, arcRadius); 133 make_arc(circle, start, start, center, arcRadius, num_circle_segments, round_away_from_center); 110 134 polygon_data<coordinate_type> poly; 111 135 set_points(poly, circle.begin(), circle.end()); 112 136 polygon_set_data<coordinate_type> offset_set; … … 114 138 polygon_set_data<coordinate_type> result; 115 139 detail::minkowski_offset<coordinate_type>::convolve_two_polygon_sets 116 140 (result, *this, offset_set); 141 142 // Intersect with result of 'normal' (non-minkowski-sum) offset, 143 // to remove offsets larger than the given 'resizing' when not near corners. 144 // Also for bug ticket #6063 145 polygon_set_data<coordinate_type> normal_offset_result(*this); 146 normal_offset_result.bloat(std::abs(resizing)); 147 result = result & normal_offset_result; 148 117 149 if(resizing < 0) { 118 150 result = result & rect;//eliminate overhang 119 151 result = result ^ rect;//invert 120 152 } 153 121 154 *this = result; 122 155 return *this; 123 156 } -
polygon_45_set_data.hpp
diff -dur orig_polygon/polygon_45_set_data.hpp polygon/polygon_45_set_data.hpp
old new 1455 1455 1456 1456 template <typename cT, typename iT> 1457 1457 void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) { 1458 typedef typename iT::value_type Point; 1458 //typedef typename iT::value_type Point; DBF per patch at https://svn.boost.org/trac/boost/ticket/6051 1459 typedef typename std::iterator_traits<iT>::value_type Point; 1459 1460 typedef typename point_traits<Point>::coordinate_type Unit; 1460 1461 typedef typename coordinate_traits<Unit>::area_type area_type; 1461 1462 Point pt1, pt2, pt3; -
polygon_set_data.hpp
diff -dur orig_polygon/polygon_set_data.hpp polygon/polygon_set_data.hpp
old new 27 27 return rounded_val; 28 28 } 29 29 template <typename T> 30 static inline point_data<T> round_down( point_data<double>v) {30 static inline point_data<T> round_down(const point_data<double> &v) { 31 31 return point_data<T>(round_down<T>(v.x()),round_down<T>(v.y())); 32 32 } 33 33 34 // utility function to round coordinate types away from another value. 35 // intended really for integer type T (does not make sense for float) 36 template <typename T> 37 static inline T round_away(double val, double center) { 38 T rounded_val = (T)(val); 39 if(val <= center) 40 { 41 // round down 42 if(val < (double)rounded_val) 43 --rounded_val; 44 } 45 else 46 { 47 // round up 48 if(val > (double)rounded_val) 49 ++rounded_val; 50 } 51 return rounded_val; 52 } 53 template <typename T> 54 static inline point_data<T> round_away(const point_data<double> &v, const point_data<double> ¢er) { 55 return point_data<T>(round_away<T>(v.x(),center.x()), round_away<T>(v.y(),center.y())); 56 } 34 57 35 58 36 59 //foward declare view … … 359 382 } 360 383 361 384 inline polygon_set_data& 362 resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); 385 resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0, 386 double minUnroundedAngleDegrees=180.0); 363 387 364 388 template <typename transform_type> 365 389 inline polygon_set_data& … … 840 864 return_points_back.push_back(curr_prev); 841 865 point_data<double> dmid(middle.x(),middle.y()); 842 866 return_points.push_back(return_points1); 843 int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); 867 // TODO: not sure what value to use here 868 bool round_away_from_center=false; 869 int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments,round_away_from_center); 844 870 curr_prev = round_down<T>(mid2_offset); 845 871 return num; 846 872 … … 874 900 875 901 } 876 902 877 // this routine should take in start and end point s.t. end point is CCW from start 878 // it sould make a pie slice polygon that is an intersection of that arc 879 // with an ngon segments approximation of the circle centered at center with radius r 880 // point start is gauaranteed to be on the segmentation 903 // This routine should take in start and end point s.t. end point is CCW from start. 904 // It should make a pie slice polygon that is an intersection of that arc 905 // with an ngon segments approximation of the circle centered at center with radius r. 906 // Point start is guaranteed to be on the segmentation, unless a full circle is created. 907 // If round_away_from_center is true, points will be rounded to the nearest type T values "away" from the center; 908 // otherwise, they will be rounded down via round_down(). (new for bug ticket #6063) 909 // TODO: do we need a version that rounds values "toward" the center? 881 910 // returnPoints will start with the first point after start 882 911 // returnPoints vector may be empty 883 912 template <typename T> 884 913 inline int make_arc(std::vector<point_data< T> >& return_points, 885 914 point_data< double> start, point_data< double> end, 886 point_data< double> center, double r, unsigned int num_circle_segments) { 915 point_data< double> center, double r, unsigned int num_circle_segments, 916 bool round_away_from_center) { 887 917 const double our_pi=3.1415926535897932384626433832795028841971; 888 918 889 919 // derive start and end angles … … 898 928 while (pe <= ps) 899 929 pe += 2.0 * our_pi; 900 930 double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; 931 932 std::vector< point_data<double> > tmp_points; 901 933 if ( start==end) // full circle? 902 934 { 903 935 ps = delta_angle*0.5; … … 908 940 start = point_data<double>(x,y); 909 941 end = start; 910 942 } 911 return_points.push_back(round_down<T>(center)); 912 return_points.push_back(round_down<T>(start)); 943 else 944 { 945 tmp_points.push_back(center); 946 } 947 tmp_points.push_back(start); 913 948 unsigned int i=0; 914 949 double curr_angle = ps+delta_angle; 915 950 while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { 916 951 i++; 917 952 double x = center.x() + r * cos( curr_angle); 918 953 double y = center.y() + r * sin( curr_angle); 919 return_points.push_back( round_down<T>((point_data<double>(x,y))));954 tmp_points.push_back(point_data<double>(x,y)); 920 955 curr_angle+=delta_angle; 921 956 } 922 return_points.push_back(round_down<T>(end)); 957 tmp_points.push_back(end); 958 959 for(int i=0; i<tmp_points.size(); i++) 960 return_points.push_back(round_away_from_center ?round_away<T>(tmp_points[i], center) :round_down<T>(tmp_points[i])); 961 923 962 return return_points.size(); 924 963 } 925 964 -
polygon_traits.hpp
diff -dur orig_polygon/polygon_traits.hpp polygon/polygon_traits.hpp
old new 1036 1036 1037 1037 template <typename iT> 1038 1038 bool point_sequence_is_45(iT itr, iT itr_end) { 1039 typedef typename iT::value_type Point; 1039 // typedef typename iT::value_type Point; DBF per patch at https://svn.boost.org/trac/boost/ticket/6051 1040 typedef typename std::iterator_traits<iT>::value_type Point; 1040 1041 typedef typename point_traits<Point>::coordinate_type Unit; 1041 1042 if(itr == itr_end) return true; 1042 1043 Point firstPt = *itr;