Ticket #6063: boost_polygon_bug6063_diffForBoost1_49_0.patch

File boost_polygon_bug6063_diffForBoost1_49_0.patch, 9.6 KB (added by dbfaken@…, 10 years ago)

Patch for boost v1.49.0

  • detail/minkowski.hpp

    diff -dur orig_polygon/detail/minkowski.hpp polygon/detail/minkowski.hpp
    old new  
    8282}
    8383  template<typename T>
    8484  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) {
    8687    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) {
    8891      if(resizing < 0)
    8992        return shrink(-resizing);
    90       if(resizing > 0)
     93      else
    9194        return bloat(resizing);
    9295      return *this;
    9396    }
    94     if(resizing == 0) return *this;
    95     if(empty()) return *this;
     97
    9698    if(num_circle_segments < 3) num_circle_segments = 4;
    9799    rectangle_data<coordinate_type> rect;
    98100    extents(rect);
     
    100102      ::boost::polygon::bloat(rect, 10);
    101103      (*this) = rect - (*this); //invert
    102104    }
    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
    106131    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
    110135    polygon_data<coordinate_type> poly;
    111136    set_points(poly, circle.begin(), circle.end());
    112137    polygon_set_data<coordinate_type> offset_set;
     
    114139    polygon_set_data<coordinate_type> result;
    115140    detail::minkowski_offset<coordinate_type>::convolve_two_polygon_sets
    116141      (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
    117150    if(resizing < 0) {
    118151      result = result & rect;//eliminate overhang
    119152      result = result ^ rect;//invert
    120153    }
     154
    121155    *this = result;
    122156    return *this;
    123157  }
  • polygon_set_data.hpp

    diff -dur orig_polygon/polygon_set_data.hpp polygon/polygon_set_data.hpp
    old new  
    2727     return rounded_val;
    2828  }
    2929  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) {
    3131     return point_data<T>(round_down<T>(v.x()),round_down<T>(v.y()));
    3232  }
    3333
    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> &center) {
     55     return point_data<T>(round_away<T>(v.x(),center.x()), round_away<T>(v.y(),center.y()));
     56  }
    3557
    3658  //foward declare view
    3759  template <typename ltype, typename rtype, int op_type> class polygon_set_view;
     
    359381    }
    360382
    361383    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);
    363386
    364387    template <typename transform_type>
    365388    inline polygon_set_data&
     
    840863         return_points_back.push_back(curr_prev);
    841864         point_data<double> dmid(middle.x(),middle.y());
    842865         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);
    844871         curr_prev = round_down<T>(mid2_offset);
    845872         return num;
    846873         
     
    874901
    875902  }
    876903
    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?
    881911  // returnPoints will start with the first point after start
    882912  // returnPoints vector  may be empty
    883913  template <typename  T>
    884914  inline int  make_arc(std::vector<point_data< T> >& return_points, 
    885915                       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) {
    887918      const double our_pi=3.1415926535897932384626433832795028841971;
    888919
    889920      // derive start and end angles
     
    898929      while (pe <= ps) 
    899930         pe += 2.0 * our_pi;
    900931      double delta_angle = (2.0 * our_pi) / (double)num_circle_segments;
     932
     933      std::vector< point_data<double> > tmp_points;
    901934      if ( start==end) // full circle?
    902935      {
    903936          ps = delta_angle*0.5;
     
    908941          start = point_data<double>(x,y);
    909942          end = start;
    910943      }
    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);
    913949      unsigned int i=0;
    914950      double curr_angle = ps+delta_angle;
    915951      while( curr_angle < pe - 0.01 && i < 2 * num_circle_segments) {
    916952         i++;
    917953         double x = center.x() + r * cos( curr_angle);
    918954         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));
    920956         curr_angle+=delta_angle;
    921957      }
    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
    923963      return return_points.size();
    924964  }
    925965