diff --git a/include/boost/polygon/detail/iterator_geometry_to_set.hpp b/include/boost/polygon/detail/iterator_geometry_to_set.hpp index ede9255b9d..2682e57471 100644 --- a/include/boost/polygon/detail/iterator_geometry_to_set.hpp +++ b/include/boost/polygon/detail/iterator_geometry_to_set.hpp @@ -253,8 +253,13 @@ public: typename polygon_with_holes_traits::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { - itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + //in this case we have no holes so we just need the iterhib == itrhie, which + //is always true if they were default initialized in the initial case or + //both point to end of the previous hole processed + //no need to explicitly reset them, and it causes an stl debug assertion to use + //the default constructed iterator this way + //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } else { ++itrhib; @@ -266,8 +271,9 @@ public: typename polygon_with_holes_traits::hole_type>(*itrhb, HIGH, orient_, !is_hole_); ++itrhb; } else { - itrhib = itrhie = iterator_geometry_to_set::hole_type>(); + //this is the same case as above + //itrhib = itrhie = iterator_geometry_to_set::hole_type>(); } } } diff --git a/include/boost/polygon/detail/minkowski.hpp b/include/boost/polygon/detail/minkowski.hpp new file mode 100644 index 0000000000..8fe9d17465 --- /dev/null +++ b/include/boost/polygon/detail/minkowski.hpp @@ -0,0 +1,125 @@ + +namespace boost { namespace polygon { namespace detail { + +template +struct minkowski_offset { + typedef point_data point; + typedef polygon_set_data polygon_set; + typedef polygon_with_holes_data polygon; + typedef std::pair edge; + + static void convolve_two_segments(std::vector& figure, const edge& a, const edge& b) { + figure.clear(); + figure.push_back(point(a.first)); + figure.push_back(point(a.first)); + figure.push_back(point(a.second)); + figure.push_back(point(a.second)); + convolve(figure[0], b.second); + convolve(figure[1], b.first); + convolve(figure[2], b.first); + convolve(figure[3], b.second); + } + + template + static void convolve_two_point_sequences(polygon_set& result, itrT1 ab, itrT1 ae, itrT2 bb, itrT2 be) { + if(ab == ae || bb == be) + return; + point first_a = *ab; + point prev_a = *ab; + std::vector vec; + polygon poly; + ++ab; + for( ; ab != ae; ++ab) { + point first_b = *bb; + point prev_b = *bb; + itrT2 tmpb = bb; + ++tmpb; + for( ; tmpb != be; ++tmpb) { + convolve_two_segments(vec, std::make_pair(prev_b, *tmpb), std::make_pair(prev_a, *ab)); + set_points(poly, vec.begin(), vec.end()); + result.insert(poly); + prev_b = *tmpb; + } + prev_a = *ab; + } + } + + template + static void convolve_point_sequence_with_polygons(polygon_set& result, itrT b, itrT e, const std::vector& polygons) { + for(std::size_t i = 0; i < polygons.size(); ++i) { + convolve_two_point_sequences(result, b, e, begin_points(polygons[i]), end_points(polygons[i])); + for(typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(polygons[i]); + itrh != end_holes(polygons[i]); ++itrh) { + convolve_two_point_sequences(result, b, e, begin_points(*itrh), end_points(*itrh)); + } + } + } + + static void convolve_two_polygon_sets(polygon_set& result, const polygon_set& a, const polygon_set& b) { + result.clear(); + std::vector a_polygons; + std::vector b_polygons; + a.get(a_polygons); + b.get(b_polygons); + for(std::size_t ai = 0; ai < a_polygons.size(); ++ai) { + convolve_point_sequence_with_polygons(result, begin_points(a_polygons[ai]), + end_points(a_polygons[ai]), b_polygons); + for(typename polygon_with_holes_traits::iterator_holes_type itrh = begin_holes(a_polygons[ai]); + itrh != end_holes(a_polygons[ai]); ++itrh) { + convolve_point_sequence_with_polygons(result, begin_points(*itrh), + end_points(*itrh), b_polygons); + } + for(std::size_t bi = 0; bi < b_polygons.size(); ++bi) { + polygon tmp_poly = a_polygons[ai]; + result.insert(convolve(tmp_poly, *(begin_points(b_polygons[bi])))); + tmp_poly = b_polygons[bi]; + result.insert(convolve(tmp_poly, *(begin_points(a_polygons[ai])))); + } + } + } +}; + +} + template + inline polygon_set_data& + polygon_set_data::resize(coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments) { + using namespace ::boost::polygon::operators; + if(!corner_fill_arc) { + if(resizing < 0) + return shrink(-resizing); + if(resizing > 0) + return bloat(resizing); + return *this; + } + if(resizing == 0) return *this; + if(empty()) return *this; + if(num_circle_segments < 3) num_circle_segments = 4; + rectangle_data rect; + extents(rect); + if(resizing < 0) { + ::boost::polygon::bloat(rect, 10); + (*this) = rect - (*this); //invert + } + //make_arc(std::vector >& return_points, + //point_data< double> start, point_data< double> end, + //point_data< double> center, double r, unsigned int num_circle_segments) + std::vector > circle; + point_data center(0.0, 0.0), start(0.0, (double)resizing); + make_arc(circle, start, start, center, std::abs((double)resizing), + num_circle_segments); + polygon_data poly; + set_points(poly, circle.begin(), circle.end()); + polygon_set_data offset_set; + offset_set += poly; + polygon_set_data result; + detail::minkowski_offset::convolve_two_polygon_sets + (result, *this, offset_set); + if(resizing < 0) { + result = result & rect;//eliminate overhang + result = result ^ rect;//invert + } + *this = result; + return *this; + } + +}} diff --git a/include/boost/polygon/detail/polygon_45_formation.hpp b/include/boost/polygon/detail/polygon_45_formation.hpp index 447b11e9dd..66e2d965d9 100644 --- a/include/boost/polygon/detail/polygon_45_formation.hpp +++ b/include/boost/polygon/detail/polygon_45_formation.hpp @@ -478,7 +478,7 @@ namespace boost { namespace polygon{ ct counts[4]; }; - typedef Vertex45CountT Vertex45Count; + typedef Vertex45CountT Vertex45Count; // inline std::ostream& operator<< (std::ostream& o, const Vertex45Count& c) { // o << c[0] << ", " << c[1] << ", "; diff --git a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp index c70bfbdf82..386ece6355 100644 --- a/include/boost/polygon/detail/polygon_arbitrary_formation.hpp +++ b/include/boost/polygon/detail/polygon_arbitrary_formation.hpp @@ -455,6 +455,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < x_unit) --x_unit; if(y < y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); @@ -464,11 +468,11 @@ namespace boost { namespace polygon{ if(!projected && !contains(rect1, result, true)) return false; if(!projected && !contains(rect2, result, true)) return false; if(projected) { - rectangle_data inf_rect((long double)(std::numeric_limits::min)(), - (long double) (std::numeric_limits::min)(), + rectangle_data inf_rect(-(long double)(std::numeric_limits::max)(), + -(long double) (std::numeric_limits::max)(), (long double)(std::numeric_limits::max)(), (long double) (std::numeric_limits::max)() ); - if(contains(inf_rect, intersection, true)) { + if(contains(inf_rect, point_data(x, y), true)) { intersection = result; return true; } else @@ -477,6 +481,7 @@ namespace boost { namespace polygon{ intersection = result; return true; } + inline bool compute_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, bool projected = false, bool round_closest = false) { if(!projected && !intersects(he1, he2)) @@ -491,6 +496,13 @@ namespace boost { namespace polygon{ } else { return lazy_success; } + return compute_exact_intersection(intersection, he1, he2, projected, round_closest); + } + + inline bool compute_exact_intersection(Point& intersection, const half_edge& he1, const half_edge& he2, + bool projected = false, bool round_closest = false) { + if(!projected && !intersects(he1, he2)) + return false; typedef rectangle_data Rectangle; Rectangle rect1, rect2; set_points(rect1, he1.first, he1.second); @@ -542,6 +554,7 @@ namespace boost { namespace polygon{ y_den = (dx1 * dy2 - dx2 * dy1); x = x_num / x_den; y = y_num / y_den; + //std::cout << x << " " << y << std::endl; //std::cout << "cross1 " << dy1 << " " << dx2 << " " << dy1 * dx2 << std::endl; //std::cout << "cross2 " << dy2 << " " << dx1 << " " << dy2 * dx1 << std::endl; //Unit exp_x = compute_x_intercept(x11, x21, y11, y21, dy1, dy2, dx1, dx2); @@ -555,6 +568,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); @@ -564,14 +581,9 @@ namespace boost { namespace polygon{ if(!contains(rect1, result, true)) return false; if(!contains(rect2, result, true)) return false; if(projected) { - rectangle_data inf_rect((long double)(std::numeric_limits::min)(), - (long double) (std::numeric_limits::min)(), - (long double)(std::numeric_limits::max)(), - (long double) (std::numeric_limits::max)() ); - if(contains(inf_rect, intersection, true)) { - intersection = result; - return true; - } else + high_precision b1 = (high_precision) (std::numeric_limits::min)(); + high_precision b2 = (high_precision) (std::numeric_limits::max)(); + if(x > b2 || y > b2 || x < b1 || y < b1) return false; } intersection = result; @@ -641,6 +653,10 @@ namespace boost { namespace polygon{ //truncate downward if it went up due to negative number if(x < (high_precision)x_unit) --x_unit; if(y < (high_precision)y_unit) --y_unit; + if(is_horizontal(he1)) + y_unit = he1.first.y(); + if(is_horizontal(he2)) + y_unit = he2.first.y(); //if(x != exp_x || y != exp_y) // std::cout << exp_x << " " << exp_y << " " << x << " " << y << std::endl; //Unit y1 = evalAtXforY(exp_x, he1.first, he1.second); diff --git a/include/boost/polygon/gmp_override.hpp b/include/boost/polygon/gmp_override.hpp index 9c79073a45..342cd3f2c8 100644 --- a/include/boost/polygon/gmp_override.hpp +++ b/include/boost/polygon/gmp_override.hpp @@ -125,5 +125,5 @@ namespace boost { namespace polygon { } } - +//== #endif diff --git a/include/boost/polygon/isotropy.hpp b/include/boost/polygon/isotropy.hpp index e52dd7b92d..c7cda49a4f 100644 --- a/include/boost/polygon/isotropy.hpp +++ b/include/boost/polygon/isotropy.hpp @@ -198,6 +198,16 @@ namespace boost { namespace polygon{ typedef double coordinate_distance; }; + template <> + struct coordinate_traits { + typedef long double coordinate_type; + typedef long double area_type; + typedef long double manhattan_area_type; + typedef long double unsigned_area_type; + typedef long double coordinate_difference; + typedef long double coordinate_distance; + }; + template struct scaling_policy { template @@ -222,6 +232,8 @@ namespace boost { namespace polygon{ struct geometry_concept { typedef coordinate_concept type; }; template <> struct geometry_concept { typedef coordinate_concept type; }; + template <> + struct geometry_concept { typedef coordinate_concept type; }; #ifndef BOOST_POLYGON_NO_DEPS struct gtl_no : mpl::bool_ {}; diff --git a/include/boost/polygon/polygon_90_set_data.hpp b/include/boost/polygon/polygon_90_set_data.hpp index 7d9206a7f0..6712c9425b 100644 --- a/include/boost/polygon/polygon_90_set_data.hpp +++ b/include/boost/polygon/polygon_90_set_data.hpp @@ -244,37 +244,47 @@ namespace boost { namespace polygon{ // get the scanline orientation of the polygon set inline orientation_2d orient() const { return orient_; } - polygon_90_set_data& operator-=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator^=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator&=(const polygon_90_set_data& that) { - sort(); - that.sort(); - value_type data; - std::swap(data, data_); - applyBooleanBinaryOp(data.begin(), data.end(), - that.begin(), that.end(), boolean_op::BinaryCount()); - return *this; - } - polygon_90_set_data& operator|=(const polygon_90_set_data& that) { - insert(that); - return *this; - } + // Start BM + // The problem: If we have two polygon sets with two different scanline orientations: + // I tried changing the orientation of one to coincide with other (If not, resulting boolean operation + // produces spurious results). + // First I tried copying polygon data from one of the sets into another set with corrected orientation + // using one of the copy constructor that takes in orientation (see somewhere above in this file) --> copy constructor throws error + // Then I tried another approach:(see below). This approach also fails to produce the desired results when test case is run. + // Here is the part that beats me: If I comment out the whole section, I can do all the operations (^=, -=, &= )these commented out + // operations perform. So then why do we need them?. Hence, I commented out this whole section. + // End BM + // polygon_90_set_data& operator-=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator^=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator&=(const polygon_90_set_data& that) { + // sort(); + // that.sort(); + // value_type data; + // std::swap(data, data_); + // applyBooleanBinaryOp(data.begin(), data.end(), + // that.begin(), that.end(), boolean_op::BinaryCount()); + // return *this; + // } + // polygon_90_set_data& operator|=(const polygon_90_set_data& that) { + // insert(that); + // return *this; + // } void clean() const { sort(); @@ -439,7 +449,7 @@ namespace boost { namespace polygon{ static bool remove_colinear_pts(std::vector >& poly) { bool found_colinear = true; - while(found_colinear) { + while(found_colinear && poly.size() >= 4) { found_colinear = false; typename std::vector >::iterator itr = poly.begin(); itr += poly.size() - 1; //get last element position @@ -504,9 +514,9 @@ namespace boost { namespace polygon{ //polygon_45_data testpoly(*itrh); if(resize_poly_down((*itrh).coords_, west_bloating, east_bloating, south_bloating, north_bloating)) { iterator_geometry_to_set > > - begin_input(view_as(*itrh), LOW, orient_, true, true), - end_input(view_as(*itrh), HIGH, orient_, true, true); - insert(begin_input, end_input, orient_); + begin_input2(view_as(*itrh), LOW, orient_, true, true), + end_input2(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > @@ -569,9 +579,9 @@ namespace boost { namespace polygon{ //polygon_45_data testpoly(*itrh); resize_poly_up((*itrh).coords_, -west_shrinking, -east_shrinking, -south_shrinking, -north_shrinking); iterator_geometry_to_set > > - begin_input(view_as(*itrh), LOW, orient_, true, true), - end_input(view_as(*itrh), HIGH, orient_, true, true); - insert(begin_input, end_input, orient_); + begin_input2(view_as(*itrh), LOW, orient_, true, true), + end_input2(view_as(*itrh), HIGH, orient_, true, true); + insert(begin_input2, end_input2, orient_); //polygon_90_set_data pstesthole; //pstesthole.insert(rect); //iterator_geometry_to_set > > @@ -638,8 +648,7 @@ namespace boost { namespace polygon{ return shrink(0, shrinking, 0, 0); if(dir == SOUTH) return shrink(0, 0, shrinking, 0); - if(dir == NORTH) - return shrink(0, 0, 0, shrinking); + return shrink(0, 0, 0, shrinking); } polygon_90_set_data& @@ -650,8 +659,7 @@ namespace boost { namespace polygon{ return bloat(0, shrinking, 0, 0); if(dir == SOUTH) return bloat(0, 0, shrinking, 0); - if(dir == NORTH) - return bloat(0, 0, 0, shrinking); + return bloat(0, 0, 0, shrinking); } polygon_90_set_data& diff --git a/include/boost/polygon/polygon_set_data.hpp b/include/boost/polygon/polygon_set_data.hpp index e00affd299..c1a3f5758d 100644 --- a/include/boost/polygon/polygon_set_data.hpp +++ b/include/boost/polygon/polygon_set_data.hpp @@ -1,6 +1,6 @@ /* Copyright 2008 Intel Corporation - + Use, modification and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). @@ -22,7 +22,7 @@ namespace boost { namespace polygon { template static inline T round_down(double val) { T rounded_val = (T)(val); - if(val < (double)rounded_val) + if(val < (double)rounded_val) --rounded_val; return rounded_val; } @@ -57,11 +57,11 @@ namespace boost { namespace polygon { } // copy constructor - inline polygon_set_data(const polygon_set_data& that) : + inline polygon_set_data(const polygon_set_data& that) : data_(that.data_), dirty_(that.dirty_), unsorted_(that.unsorted_), is_45_(that.is_45_) {} // copy constructor - template + template inline polygon_set_data(const polygon_set_view& that); // destructor @@ -150,10 +150,10 @@ namespace boost { namespace polygon { insert(polygon_object, is_hole, polygon_concept()); } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_concept()); - for(typename polygon_with_holes_traits::iterator_holes_type itr = + for(typename polygon_with_holes_traits::iterator_holes_type itr = begin_holes(polygon_with_holes_object); itr != end_holes(polygon_with_holes_object); ++itr) { insert(*itr, !is_hole, polygon_concept()); @@ -161,12 +161,12 @@ namespace boost { namespace polygon { } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_45_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } template - inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, + inline void insert(const polygon_with_holes_type& polygon_with_holes_object, bool is_hole, polygon_90_with_holes_concept ) { insert(polygon_with_holes_object, is_hole, polygon_with_holes_concept()); } @@ -212,7 +212,7 @@ namespace boost { namespace polygon { first_point = previous_point = current_point; } else { if(previous_point != current_point) { - element_type elem(edge_type(previous_point, current_point), + element_type elem(edge_type(previous_point, current_point), ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); insert_clean(elem); } @@ -222,7 +222,7 @@ namespace boost { namespace polygon { current_point = first_point; if(!first_iteration) { if(previous_point != current_point) { - element_type elem(edge_type(previous_point, current_point), + element_type elem(edge_type(previous_point, current_point), ( previous_point.get(HORIZONTAL) == current_point.get(HORIZONTAL) ? -1 : 1) * multiplier); insert_clean(elem); } @@ -270,14 +270,14 @@ namespace boost { namespace polygon { } } - // equivalence operator + // equivalence operator inline bool operator==(const polygon_set_data& p) const { clean(); p.clean(); return data_ == p.data_; } - // inequivalence operator + // inequivalence operator inline bool operator!=(const polygon_set_data& p) const { return !((*this) == p); } @@ -335,7 +335,7 @@ namespace boost { namespace polygon { } void set(const value_type& value) { - data_ = value; + data_ = value; dirty_ = true; unsorted_ = true; } @@ -359,27 +359,10 @@ namespace boost { namespace polygon { } inline polygon_set_data& - resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0) { - if(!corner_fill_arc) { - if(resizing < 0) - return shrink(-resizing); - if(resizing > 0) - return bloat(resizing); - return *this; - } - if(resizing == 0) return *this; - std::list > pl; - get(pl); - clear(); - for(typename std::list >::iterator itr = pl.begin(); itr != pl.end(); ++itr) { - insert_with_resize(*itr, resizing, corner_fill_arc, num_circle_segments); - } - clean(); - return *this; - } + resize(coordinate_type resizing, bool corner_fill_arc = false, unsigned int num_circle_segments=0); template - inline polygon_set_data& + inline polygon_set_data& transform(const transform_type& tr) { std::vector > polys; get(polys); @@ -393,7 +376,7 @@ namespace boost { namespace polygon { return *this; } - inline polygon_set_data& + inline polygon_set_data& scale_up(typename coordinate_traits::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { ::boost::polygon::scale_up((*itr).first.first, factor); @@ -401,8 +384,8 @@ namespace boost { namespace polygon { } return *this; } - - inline polygon_set_data& + + inline polygon_set_data& scale_down(typename coordinate_traits::unsigned_area_type factor) { for(typename value_type::iterator itr = data_.begin(); itr != data_.end(); ++itr) { ::boost::polygon::scale_down((*itr).first.first, factor); @@ -412,9 +395,9 @@ namespace boost { namespace polygon { dirty_ = true; return *this; } - + template - inline polygon_set_data& scale(polygon_set_data& polygon_set, + inline polygon_set_data& scale(polygon_set_data& polygon_set, const scaling_type& scaling) { for(typename value_type::iterator itr = begin(); itr != end(); ++itr) { ::boost::polygon::scale((*itr).first.first, scaling); @@ -425,37 +408,53 @@ namespace boost { namespace polygon { return *this; } - static inline void compute_offset_edge(point_data& pt1, point_data& pt2, - const point_data& prev_pt, - const point_data& current_pt, - coordinate_type distance, int multiplier) { - coordinate_type dx = current_pt.x() - prev_pt.x(); - coordinate_type dy = current_pt.y() - prev_pt.y(); - double ddx = (double)dx; - double ddy = (double)dy; - double edge_length = std::sqrt(ddx*ddx + ddy*ddy); - double dnx = dy; - double dny = -dx; - dnx = dnx * (double)distance / edge_length; - dny = dny * (double)distance / edge_length; - dnx = std::floor(dnx+0.5); - dny = std::floor(dny+0.5); - pt1.x(prev_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); - pt2.x(current_pt.x() + (coordinate_type)dnx * (coordinate_type)multiplier); - pt1.y(prev_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); - pt2.y(current_pt.y() + (coordinate_type)dny * (coordinate_type)multiplier); + static inline void compute_offset_edge(point_data& pt1, point_data& pt2, + const point_data& prev_pt, + const point_data& current_pt, + long double distance, int multiplier) { + long double dx = current_pt.x() - prev_pt.x(); + long double dy = current_pt.y() - prev_pt.y(); + long double edge_length = std::sqrt(dx*dx + dy*dy); + long double dnx = dy; + long double dny = -dx; + dnx = dnx * (long double)distance / edge_length; + dny = dny * (long double)distance / edge_length; + pt1.x(prev_pt.x() + (long double)dnx * (long double)multiplier); + pt2.x(current_pt.x() + (long double)dnx * (long double)multiplier); + pt1.y(prev_pt.y() + (long double)dny * (long double)multiplier); + pt2.y(current_pt.y() + (long double)dny * (long double)multiplier); } static inline void modify_pt(point_data& pt, const point_data& prev_pt, const point_data& current_pt, const point_data& next_pt, coordinate_type distance, coordinate_type multiplier) { - std::pair, point_data > he1(prev_pt, current_pt), he2(current_pt, next_pt); + std::pair, point_data > he1, he2; + he1.first.x((long double)(prev_pt.x())); + he1.first.y((long double)(prev_pt.y())); + he1.second.x((long double)(current_pt.x())); + he1.second.y((long double)(current_pt.y())); + he2.first.x((long double)(current_pt.x())); + he2.first.y((long double)(current_pt.y())); + he2.second.x((long double)(next_pt.x())); + he2.second.y((long double)(next_pt.y())); compute_offset_edge(he1.first, he1.second, prev_pt, current_pt, distance, multiplier); compute_offset_edge(he2.first, he2.second, current_pt, next_pt, distance, multiplier); - typename scanline_base::compute_intersection_pack pack; - if(!pack.compute_lazy_intersection(pt, he1, he2, true, true)) { - pt = he1.second; //colinear offset edges use shared point + typename scanline_base::compute_intersection_pack pack; + point_data rpt; + point_data bisectorpt((he1.second.x()+he2.first.x())/2, + (he1.second.y()+he2.first.y())/2); + point_data orig_pt((long double)pt.x(), (long double)pt.y()); + if(euclidean_distance(bisectorpt, orig_pt) < distance/2) { + if(!pack.compute_lazy_intersection(rpt, he1, he2, true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } + } else { + if(!pack.compute_lazy_intersection(rpt, he1, std::pair, point_data >(orig_pt, bisectorpt), true, false)) { + rpt = he1.second; //colinear offset edges use shared point + } } + pt.x((coordinate_type)(std::floor(rpt.x()+0.5))); + pt.y((coordinate_type)(std::floor(rpt.y()+0.5))); } static void resize_poly_up(std::vector >& poly, coordinate_type distance, coordinate_type multiplier) { @@ -566,8 +565,8 @@ namespace boost { namespace polygon { } template - inline polygon_set_data& - insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_with_holes_concept tag) { insert_with_resize_dispatch(poly, resizing, corner_fill_arc, num_circle_segments, hole, polygon_concept()); for(typename polygon_with_holes_traits::iterator_holes_type itr = @@ -579,14 +578,14 @@ namespace boost { namespace polygon { } template - inline polygon_set_data& - insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, + inline polygon_set_data& + insert_with_resize_dispatch(const geometry_type& poly, coordinate_type resizing, bool corner_fill_arc, unsigned int num_circle_segments, bool hole, polygon_concept tag) { if (resizing==0) return *this; - + // one dimensional used to store CCW/CW flag //direction_1d wdir = winding(poly); // LOW==CLOCKWISE just faster to type @@ -615,7 +614,7 @@ namespace boost { namespace polygon { // for all corners polygon_set_data sizingSet; - bool sizing_sign = resizing>0; + bool sizing_sign = resizing<0; bool prev_concave = true; point_data prev_point; //int iCtr=0; @@ -631,7 +630,7 @@ namespace boost { namespace polygon { point_data normal2( third->y()-second->y(), second->x()-third->x()); double direction = normal1.x()*normal2.y()- normal2.x()*normal1.y(); bool convex = direction>0; - + bool treat_as_concave = !convex; if(sizing_sign) treat_as_concave = convex; @@ -644,12 +643,12 @@ namespace boost { namespace polygon { if (prev_concave) //TODO missing round_down() curr_prev = point_data(first->x()+v.x(),first->y()+v.y()); - else + else curr_prev = prev_point; // around concave corners - insert rectangle // if previous corner is concave it's point info may be ignored - if ( treat_as_concave) { + if ( treat_as_concave) { std::vector > pts; pts.push_back(point_data(second->x()+v.x(),second->y()+v.y())); @@ -670,13 +669,13 @@ namespace boost { namespace polygon { direction_1d winding; winding = convex?COUNTERCLOCKWISE:CLOCKWISE; if (make_resizing_vertex_list(pts, curr_prev, prev_concave, *first, *second, *third, resizing - , num_circle_segments, corner_fill_arc)) + , num_circle_segments, corner_fill_arc)) { if (first_pts.size()) { for (unsigned int i=0; i tmp; //insert original shape @@ -722,7 +721,7 @@ namespace boost { namespace polygon { inline polygon_set_data& - interact(const polygon_set_data& that); + interact(const polygon_set_data& that); inline bool downcast(polygon_45_set_data& result) const { if(!is_45_) return false; @@ -811,7 +810,7 @@ namespace boost { namespace polygon { // } template - inline int make_resizing_vertex_list(std::vector > >& return_points, + inline int make_resizing_vertex_list(std::vector > >& return_points, point_data& curr_prev, bool ignore_prev_point, point_data< T> start, point_data middle, point_data< T> end, double sizing_distance, unsigned int num_circle_segments, bool corner_fill_arc) { @@ -844,7 +843,7 @@ namespace boost { namespace polygon { int num = make_arc(return_points[return_points.size()-1],mid1_offset,mid2_offset,dmid,sizing_distance,num_circle_segments); curr_prev = round_down(mid2_offset); return num; - + } std::pair,point_data > he1(start_offset,mid1_offset); @@ -882,21 +881,21 @@ namespace boost { namespace polygon { // returnPoints will start with the first point after start // returnPoints vector may be empty template - inline int make_arc(std::vector >& return_points, + inline int make_arc(std::vector >& return_points, point_data< double> start, point_data< double> end, point_data< double> center, double r, unsigned int num_circle_segments) { const double our_pi=3.1415926535897932384626433832795028841971; - // derive start and end angles + // derive start and end angles double ps = atan2(start.y()-center.y(), start.x()-center.x()); double pe = atan2(end.y()-center.y(), end.x()-center.x()); - if (ps < 0.0) + if (ps < 0.0) ps += 2.0 * our_pi; - if (pe <= 0.0) + if (pe <= 0.0) pe += 2.0 * our_pi; - if (ps >= 2.0 * our_pi) + if (ps >= 2.0 * our_pi) ps -= 2.0 * our_pi; - while (pe <= ps) + while (pe <= ps) pe += 2.0 * our_pi; double delta_angle = (2.0 * our_pi) / (double)num_circle_segments; if ( start==end) // full circle? @@ -942,12 +941,12 @@ namespace boost { namespace polygon { inline connectivity_extraction() : ce_(), nodeCount_(0) {} inline connectivity_extraction(const connectivity_extraction& that) : ce_(that.ce_), nodeCount_(that.nodeCount_) {} - inline connectivity_extraction& operator=(const connectivity_extraction& that) { - ce_ = that.ce_; + inline connectivity_extraction& operator=(const connectivity_extraction& that) { + ce_ = that.ce_; nodeCount_ = that.nodeCount_; {} return *this; } - + //insert a polygon set graph node, the value returned is the id of the graph node inline unsigned int insert(const polygon_set_data& ps) { ps.clean(); @@ -960,7 +959,7 @@ namespace boost { namespace polygon { ps.insert(geoObj); return insert(ps); } - + //extract connectivity and store the edges in the graph //graph must be indexable by graph node id and the indexed value must be a std::set of //graph node id @@ -996,5 +995,6 @@ namespace boost { namespace polygon { #include "detail/polygon_set_view.hpp" #include "polygon_set_concept.hpp" +#include "detail/minkowski.hpp" #endif diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 43e4abd6e8..313d3c43a1 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -29,6 +29,7 @@ ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) : m_NetCode = -1; // Net number for fast comparisons m_CornerSelection = -1; m_IsFilled = false; // fill status : true when the zone is filled + m_FillMode = 0; // How to fill areas: 0 = use filled polygons, != 0 fill with segments utility = 0; // flags used in polygon calculations utility2 = 0; // flags used in polygon calculations m_Poly = new CPolyLine(); // Outlines @@ -903,6 +904,8 @@ bool ZONE_CONTAINER::HitTestFilledArea( const wxPoint& aRefPos ) inside = true; break; } + // Prepare test of next area which starts after the current indexend (if exists) + indexstart = indexend+1; } } return inside; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 1db68ab8f6..79d05f9da9 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -41,7 +41,7 @@ public: int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection int m_ZoneClearance; // clearance value int m_ZoneMinThickness; // Min thickness value in filled areas - int m_FillMode; // How to fillingareas: 0 = use polygonal areas , != 0 fill with segments + int m_FillMode; // How to fill areas: 0 = use filled polygons, != 0 fill with segments int m_ArcToSegmentsCount; // number of segments to convert a circle to a polygon // (uses ARC_APPROX_SEGMENTS_COUNT_LOW_DEF or ARC_APPROX_SEGMENTS_COUNT_HIGHT_DEF) int m_PadOption; // diff --git a/pcbnew/class_zone_setting.cpp b/pcbnew/class_zone_setting.cpp index 5e8bb4ce86..3639a8ba8b 100644 --- a/pcbnew/class_zone_setting.cpp +++ b/pcbnew/class_zone_setting.cpp @@ -24,7 +24,7 @@ ZONE_SETTING::ZONE_SETTING( void ) { - m_FillMode = 1; // Mode for filling zone : 1 use segments, 0 use polygons + m_FillMode = 0; // Mode for filling zone : 1 use segments, 0 use polygons m_ZoneClearance = 200; // Clearance value m_ZoneMinThickness = 100; // Min thickness value in filled areas m_NetcodeSelection = 0; // Net code selection for the current zone diff --git a/pcbnew/dialog_copper_zones.cpp b/pcbnew/dialog_copper_zones.cpp index f27b9f7c12..56da7d2536 100644 --- a/pcbnew/dialog_copper_zones.cpp +++ b/pcbnew/dialog_copper_zones.cpp @@ -19,9 +19,10 @@ #include "dialog_copper_zones.h" -wxString dialog_copper_zone::m_netNameShowFilter( wxT( "*" ) ); /* the filter to show nets (default * "*"). - * static to keep this pattern for an entire pcbnew session - */ +/* the filter to show nets (default * "*"). + * static to keep this pattern for an entire pcbnew session + */ +wxString dialog_copper_zone::m_netNameShowFilter( wxT( "*" ) ); /************************************************************************************************/ dialog_copper_zone::dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* zone_setting ) : @@ -31,8 +32,10 @@ dialog_copper_zone::dialog_copper_zone( WinEDA_PcbFrame* parent, ZONE_SETTING* z m_Parent = parent; m_Config = wxGetApp().m_EDA_Config; m_Zone_Setting = zone_setting; - m_NetSorting = 1; // 0 = alphabetic sort, 1 = pad count sort, and filtering net names - m_OnExitCode = ZONE_ABORT; + m_NetSortingByPadCount = true; /* false = alphabetic sort. + * true = pad count sort. + */ + m_OnExitCode = ZONE_ABORT; SetReturnCode( ZONE_ABORT ); // Will be changed on buttons click @@ -156,7 +159,7 @@ void dialog_copper_zone::initDialog() else m_NetDisplayOption->SetSelection( 1 ); - m_ShowNetNameFilter->SetValue(m_netNameShowFilter); + m_ShowNetNameFilter->SetValue( m_netNameShowFilter ); initListNetsParams(); // Build list of nets: @@ -392,7 +395,7 @@ void dialog_copper_zone::OnPadsInZoneClick( wxCommandEvent& event ) } -/** init m_NetSorting and m_NetFiltering values +/** init m_NetSortingByPadCount and m_NetFiltering values * according to m_NetDisplayOption selection */ void dialog_copper_zone::initListNetsParams() @@ -400,22 +403,22 @@ void dialog_copper_zone::initListNetsParams() switch( m_NetDisplayOption->GetSelection() ) { case 0: - m_NetSorting = true; + m_NetSortingByPadCount = false; m_NetFiltering = false; break; case 1: - m_NetSorting = false; + m_NetSortingByPadCount = true; m_NetFiltering = false; break; case 2: - m_NetSorting = true; + m_NetSortingByPadCount = false; m_NetFiltering = true; break; case 3: - m_NetSorting = false; + m_NetSortingByPadCount = true; m_NetFiltering = true; break; } @@ -429,6 +432,7 @@ void dialog_copper_zone::initListNetsParams() void dialog_copper_zone::OnRunFiltersButtonClick( wxCommandEvent& event ) { m_netNameShowFilter = m_ShowNetNameFilter->GetValue(); + // Ensure filtered option for nets: if( m_NetDisplayOption->GetSelection() == 0 ) m_NetDisplayOption->SetSelection( 2 ); @@ -443,8 +447,7 @@ void dialog_copper_zone::buildAvailableListOfNets() { wxArrayString listNetName; - m_Parent->GetBoard()->ReturnSortedNetnamesList( - listNetName, m_NetSorting == 0 ? false : true ); + m_Parent->GetBoard()->ReturnSortedNetnamesList( listNetName, m_NetSortingByPadCount ); if( m_NetFiltering ) { diff --git a/pcbnew/dialog_copper_zones.h b/pcbnew/dialog_copper_zones.h index 7bc7f28ebc..c6bdb5e9f9 100644 --- a/pcbnew/dialog_copper_zones.h +++ b/pcbnew/dialog_copper_zones.h @@ -18,7 +18,9 @@ private: */ ZONE_SETTING* m_Zone_Setting; - long m_NetSorting; + bool m_NetSortingByPadCount; /* false = alphabetic sort. + * true = pad count sort. + */ long m_NetFiltering; int m_LayerId[LAYER_COUNT]; // Handle the real layer number from layer name position in m_LayerSelectionCtrl static wxString m_netNameShowFilter; /* the filter to show nets (default * "*"). diff --git a/pcbnew/zones_convert_brd_items_to_polygons_with_Kbool.cpp b/pcbnew/zones_convert_brd_items_to_polygons_with_Kbool.cpp index 1959ba9736..42f3fee2a2 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons_with_Kbool.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons_with_Kbool.cpp @@ -486,7 +486,6 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) booleng = new Bool_Engine(); ArmBoolEng( booleng, true ); cornerBufferPolysToSubstract.clear(); - // Test thermal stubs connections and add polygons to remove unconnected stubs. for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { @@ -535,62 +534,60 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) // translate point ptTest[i] += pad->ReturnShapePos(); - bool inside = HitTestFilledArea( ptTest[i] ); + if( HitTestFilledArea( ptTest[i] ) ) + continue; - if( inside == false ) + // polygon buffer + std::vector corners_buffer; + + // polygons are rectangles with width of copper bridge value + // contour line width has to be taken into calculation to avoid "thermal stub bleed" + const int iDTRC = + ( m_ThermalReliefCopperBridgeValue - m_ZoneMinThickness ) / 2; + + switch( i ) { - // polygon buffer - std::vector corners_buffer; + case 0: + corners_buffer.push_back( wxPoint( -iDTRC, dy ) ); + corners_buffer.push_back( wxPoint( +iDTRC, dy ) ); + corners_buffer.push_back( wxPoint( +iDTRC, iDTRC ) ); + corners_buffer.push_back( wxPoint( -iDTRC, iDTRC ) ); + break; - // polygons are rectangles with width of copper bridge value - // contour line width has to be taken into calculation to avoid "thermal stub bleed" - const int iDTRC = - ( m_ThermalReliefCopperBridgeValue - m_ZoneMinThickness ) / 2; + case 1: + corners_buffer.push_back( wxPoint( -iDTRC, -dy ) ); + corners_buffer.push_back( wxPoint( +iDTRC, -dy ) ); + corners_buffer.push_back( wxPoint( +iDTRC, -iDTRC ) ); + corners_buffer.push_back( wxPoint( -iDTRC, -iDTRC ) ); + break; - switch( i ) - { - case 0: - corners_buffer.push_back( wxPoint( -iDTRC, dy ) ); - corners_buffer.push_back( wxPoint( +iDTRC, dy ) ); - corners_buffer.push_back( wxPoint( +iDTRC, iDTRC ) ); - corners_buffer.push_back( wxPoint( -iDTRC, iDTRC ) ); - break; + case 2: + corners_buffer.push_back( wxPoint( dx, -iDTRC ) ); + corners_buffer.push_back( wxPoint( dx, iDTRC ) ); + corners_buffer.push_back( wxPoint( +iDTRC, iDTRC ) ); + corners_buffer.push_back( wxPoint( +iDTRC, -iDTRC ) ); + break; - case 1: - corners_buffer.push_back( wxPoint( -iDTRC, -dy ) ); - corners_buffer.push_back( wxPoint( +iDTRC, -dy ) ); - corners_buffer.push_back( wxPoint( +iDTRC, -iDTRC ) ); - corners_buffer.push_back( wxPoint( -iDTRC, -iDTRC ) ); - break; - - case 2: - corners_buffer.push_back( wxPoint( dx, -iDTRC ) ); - corners_buffer.push_back( wxPoint( dx, iDTRC ) ); - corners_buffer.push_back( wxPoint( +iDTRC, iDTRC ) ); - corners_buffer.push_back( wxPoint( +iDTRC, -iDTRC ) ); - break; - - case 3: - corners_buffer.push_back( wxPoint( -dx, -iDTRC ) ); - corners_buffer.push_back( wxPoint( -dx, iDTRC ) ); - corners_buffer.push_back( wxPoint( -iDTRC, iDTRC ) ); - corners_buffer.push_back( wxPoint( -iDTRC, -iDTRC ) ); - break; - } + case 3: + corners_buffer.push_back( wxPoint( -dx, -iDTRC ) ); + corners_buffer.push_back( wxPoint( -dx, iDTRC ) ); + corners_buffer.push_back( wxPoint( -iDTRC, iDTRC ) ); + corners_buffer.push_back( wxPoint( -iDTRC, -iDTRC ) ); + break; + } - // add computed polygon to list - for( unsigned ic = 0; ic < corners_buffer.size(); ic++ ) - { - wxPoint cpos = corners_buffer[ic]; - RotatePoint( &cpos, fAngle ); // Rotate according to module orientation - cpos += pad->ReturnShapePos(); // Shift origin to position - CPolyPt corner; - corner.x = cpos.x; - corner.y = cpos.y; - corner.end_contour = ( ic < (corners_buffer.size() - 1) ) ? 0 : 1; - cornerBufferPolysToSubstract.push_back( corner ); - } + // add computed polygon to list + for( unsigned ic = 0; ic < corners_buffer.size(); ic++ ) + { + wxPoint cpos = corners_buffer[ic]; + RotatePoint( &cpos, fAngle ); // Rotate according to module orientation + cpos += pad->ReturnShapePos(); // Shift origin to position + CPolyPt corner; + corner.x = cpos.x; + corner.y = cpos.y; + corner.end_contour = ( ic < (corners_buffer.size() - 1) ) ? 0 : 1; + cornerBufferPolysToSubstract.push_back( corner ); } } } diff --git a/polygon/polygon_test_point_inside.cpp b/polygon/polygon_test_point_inside.cpp index 8fd75803d7..846b9fee64 100644 --- a/polygon/polygon_test_point_inside.cpp +++ b/polygon/polygon_test_point_inside.cpp @@ -83,8 +83,8 @@ bool TestPointInsidePolygon( std::vector aPolysList, // with the horizontal line at the new refy position // the line slope = seg_endY/seg_endX; // and the x pos relative to the new origin is intersec_x = refy/slope - // Note: because horizontal segments are skipped, 1/slope exists (seg_end_y never == O) - double intersec_x = newrefy * seg_endX / seg_endY; + // Note: because horizontal segments are skipped, 1/slope exists (seg_endY never == O) + double intersec_x = (newrefy * seg_endX) / seg_endY; if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from refx to infinite count++; } @@ -101,7 +101,6 @@ bool TestPointInsidePolygon( wxPoint *aPolysList, int aCount,wxPoint aRefPoint ) // count intersection points to right of (refx,refy). If odd number, point (refx,refy) is inside polyline int ics, ice; int count = 0; - // find all intersection points of line with polyline sides for( ics = 0, ice = aCount-1; ics < aCount; ice = ics++ ) { @@ -138,8 +137,8 @@ bool TestPointInsidePolygon( wxPoint *aPolysList, int aCount,wxPoint aRefPoint ) // with the horizontal line at the new refy position // the line slope = seg_endY/seg_endX; // and the x pos relative to the new origin is intersec_x = refy/slope - // Note: because horizontal segments are skipped, 1/slope exists (seg_end_y never == O) - double intersec_x = newrefy * seg_endX / seg_endY; + // Note: because horizontal segments are skipped, 1/slope exists (seg_endY never == O) + double intersec_x = (newrefy * seg_endX) / seg_endY; if( newrefx < intersec_x ) // Intersection found with the semi-infinite line from refx to infinite count++; }