Ticket #6063: boost_polygon_bug6063_diffForBoost1_49_0.patch
File boost_polygon_bug6063_diffForBoost1_49_0.patch, 9.6 KB (added by , 10 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 min_unrounded_angle_degrees) { 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 || min_unrounded_angle_degrees<=0.0) { 88 91 if(resizing < 0) 89 92 return shrink(-resizing); 90 if(resizing > 0)93 else 91 94 return bloat(resizing); 92 95 return *this; 93 96 } 94 if(resizing == 0) return *this; 95 if(empty()) return *this; 97 96 98 if(num_circle_segments < 3) num_circle_segments = 4; 97 99 rectangle_data<coordinate_type> rect; 98 100 extents(rect); … … 100 102 ::boost::polygon::bloat(rect, 10); 101 103 (*this) = rect - (*this); //invert 102 104 } 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) 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(min_unrounded_angle_degrees < 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 min_unrounded_angle_degrees=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(min_unrounded_angle_degrees*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 >= min_unrounded_angle_degrees, 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); 134 110 135 polygon_data<coordinate_type> poly; 111 136 set_points(poly, circle.begin(), circle.end()); 112 137 polygon_set_data<coordinate_type> offset_set; … … 114 139 polygon_set_data<coordinate_type> result; 115 140 detail::minkowski_offset<coordinate_type>::convolve_two_polygon_sets 116 141 (result, *this, offset_set); 142 143 // Intersect with result of 'normal' (non-minkowski-sum) offset, 144 // to remove offsets larger than the given 'resizing' when not near corners. 145 // Also for bug ticket #6063 146 polygon_set_data<coordinate_type> normal_offset_result(*this); 147 normal_offset_result.bloat(std::abs(resizing)); 148 result = result & normal_offset_result; 149 117 150 if(resizing < 0) { 118 151 result = result & rect;//eliminate overhang 119 152 result = result ^ rect;//invert 120 153 } 154 121 155 *this = result; 122 156 return *this; 123 157 } -
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 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 } 35 57 36 58 //foward declare view 37 59 template <typename ltype, typename rtype, int op_type> class polygon_set_view; … … 359 381 } 360 382 361 383 inline polygon_set_data& 362 resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); 384 resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0, 385 double min_unrounded_angle_degrees=180.0); 363 386 364 387 template <typename transform_type> 365 388 inline polygon_set_data& … … 840 863 return_points_back.push_back(curr_prev); 841 864 point_data<double> dmid(middle.x(),middle.y()); 842 865 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); 866 867 // NOTE: perhaps this should be an additional parameter 868 bool round_away_from_center=false; 869 870 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 871 curr_prev = round_down<T>(mid2_offset); 845 872 return num; 846 873 … … 874 901 875 902 } 876 903 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 904 // This routine should take in start and end point s.t. end point is CCW from start. 905 // It should make a pie slice polygon that is an intersection of that arc 906 // with an ngon segments approximation of the circle centered at center with radius r. 907 // Point start is guaranteed to be on the segmentation, unless a full circle is created. 908 // If round_away_from_center is true, points will be rounded to the nearest type T values "away" from the center; 909 // otherwise, they will be rounded down via round_down(). (new for bug ticket #6063) 910 // TODO: do we need a version that rounds values "toward" the center? 881 911 // returnPoints will start with the first point after start 882 912 // returnPoints vector may be empty 883 913 template <typename T> 884 914 inline int make_arc(std::vector<point_data< T> >& return_points, 885 915 point_data< double> start, point_data< double> end, 886 point_data< double> center, double r, unsigned int num_circle_segments) { 916 point_data< double> center, double r, unsigned int num_circle_segments, 917 bool round_away_from_center) { 887 918 const double our_pi=3.1415926535897932384626433832795028841971; 888 919 889 920 // derive start and end angles … … 898 929 while (pe <= ps) 899 930 pe += 2.0 * our_pi; 900 931 double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; 932 933 std::vector< point_data<double> > tmp_points; 901 934 if ( start==end) // full circle? 902 935 { 903 936 ps = delta_angle*0.5; … … 908 941 start = point_data<double>(x,y); 909 942 end = start; 910 943 } 911 return_points.push_back(round_down<T>(center)); 912 return_points.push_back(round_down<T>(start)); 944 else 945 { 946 tmp_points.push_back(center); 947 } 948 tmp_points.push_back(start); 913 949 unsigned int i=0; 914 950 double curr_angle = ps+delta_angle; 915 951 while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) { 916 952 i++; 917 953 double x = center.x() + r * cos( curr_angle); 918 954 double y = center.y() + r * sin( curr_angle); 919 return_points.push_back( round_down<T>((point_data<double>(x,y))));955 tmp_points.push_back(point_data<double>(x,y)); 920 956 curr_angle+=delta_angle; 921 957 } 922 return_points.push_back(round_down<T>(end)); 958 tmp_points.push_back(end); 959 960 for(int i=0; i<tmp_points.size(); i++) 961 return_points.push_back(round_away_from_center ?round_away<T>(tmp_points[i], center) :round_down<T>(tmp_points[i])); 962 923 963 return return_points.size(); 924 964 } 925 965