bool gde::geom::algorithm::do_intersects_v2(const gde::geom::core::line_segment& s1, const gde::geom::core::line_segment& s2) { double a = (s2.p1.x - s1.p1.x) * (s1.p2.y - s1.p1.y) - (s2.p1.y - s1.p1.y) * (s1.p2.x - s1.p1.x); double b = (s2.p2.x - s1.p1.x) * (s1.p2.y - s1.p1.y) - (s2.p2.y - s1.p1.y) * (s1.p2.x - s1.p1.x); // if the endpoints of the second segment lie on the opposite if((a != 0.0) && (b != 0.0) && same_signs(a, b)) return false; double c = (s1.p1.x - s2.p1.x) * (s2.p2.y - s2.p1.y) - (s1.p1.y - s2.p1.y) * (s2.p2.x - s2.p1.x); double d = (s1.p2.x - s2.p1.x) * (s2.p2.y - s2.p1.y) - (s1.p2.y - s2.p1.y) * (s2.p2.x - s2.p1.x); // if the endpoints of the first segment lie on the opposite if((c != 0.0) && (d != 0.0) && same_signs(c, d)) return false; // are the segments collinear? double det = a - b; if(det == 0.0) return do_collinear_segments_intersects(s1, s2); // the segments intersect return true; }
bool gde::geom::algorithm::do_intersects_v1(const gde::geom::core::line_segment& s1, const gde::geom::core::line_segment& s2) { // compute general line equation for segment s1 double a1 = s1.p2.y - s1.p1.y; double b1 = s1.p1.x - s1.p2.x; double c1 = (s1.p2.x * s1.p1.y) - (s1.p1.x * s1.p2.y); double r3 = a1 * s2.p1.x + b1 * s2.p1.y + c1; double r4 = a1 * s2.p2.x + b1 * s2.p2.y + c1; // if both points from segment s2 are to the sime side of line defined by segment s1, // we are sure s2 can not intersects s1 if((r3 != 0.0) && (r4 != 0.0) && same_signs(r3, r4)) return false; // compute general line equation for segment s2 double a2 = s2.p2.y - s2.p1.y; double b2 = s2.p1.x - s2.p2.x; double c2 = (s2.p2.x * s2.p1.y) - (s2.p1.x * s2.p2.y); double r1 = a2 * s1.p1.x + b2 * s1.p1.y + c2; double r2 = a2 * s1.p2.x + b2 * s1.p2.y + c2; // if both points from segment s1 are to the sime side of line defined by segment s2, // we are sure s1 can not intersects s2 if((r1 != 0.0) && (r2 != 0.0) && same_signs(r1, r2)) return false; // ok: we know tha segments may overlap or cross at a single point! return true; }
// Unlike with a % b, the result always has the same sign as the divisor. constexpr int modulus(int a, int b) { int result = a % b; if (result && !same_signs(result, b)) result += b; return result; }
// Returns the result of the integer division rounded up / towards +∞. constexpr int div_ceil(int a, int b) { // +1 if a / b > 0 int result = a / b; if (a % b) result += same_signs(a, b); return result; }
// Returns the result of the integer division rounded down / towards -∞. constexpr int div_floor(int a, int b) { // -1 if a / b < 0 int result = a / b; if (a % b) result -= !same_signs(a, b); return result; }
// Returns the result of the division rounded towards infinity/away from zero. constexpr int div_towards_infinity(int a, int b) { // +1 if a / b > 0 // -1 if a / b < 0 int result = a / b; if (a % b) result += same_signs(a, b) ? 1 : -1; return result; }
gde::geom::algorithm::segment_relation_type gde::geom::algorithm::compute_intesection_v2(const gde::geom::core::line_segment& s1, const gde::geom::core::line_segment& s2, gde::geom::core::point& first, gde::geom::core::point& second) { double a = (s2.p1.x - s1.p1.x) * (s1.p2.y - s1.p1.y) - (s2.p1.y - s1.p1.y) * (s1.p2.x - s1.p1.x); double b = (s2.p2.x - s1.p1.x) * (s1.p2.y - s1.p1.y) - (s2.p2.y - s1.p1.y) * (s1.p2.x - s1.p1.x); // if the endpoints of the second segment lie on the opposite if((a != 0.0) && (b != 0.0) && same_signs(a, b)) return DISJOINT; double c = (s1.p1.x - s2.p1.x) * (s2.p2.y - s2.p1.y) - (s1.p1.y - s2.p1.y) * (s2.p2.x - s2.p1.x); double d = (s1.p2.x - s2.p1.x) * (s2.p2.y - s2.p1.y) - (s1.p2.y - s2.p1.y) * (s2.p2.x - s2.p1.x); // if the endpoints of the first segment lie on the opposite if((c != 0.0) && (d != 0.0) && same_signs(c, d)) return DISJOINT; double det = a - b; if(det == 0.0) // are the segments collinear? { if(do_collinear_segments_intersects(s1, s2) == false) return DISJOINT; // and we know they intersects: let's order the segments and find out intersection(s) const gde::geom::core::point* pts[4]; pts[0] = &s1.p1; pts[1] = &s1.p2; pts[2] = &s2.p1; pts[3] = &s2.p2; std::sort(pts, pts + 4, point_cmp); // at least they will share one point first = *pts[1]; // and if segments touch in a single point they are equal if((pts[1]->x == pts[2]->x) && (pts[1]->y == pts[2]->y)) return TOUCH; // otherwise, the middle points are the intesections second = *pts[2]; return OVERLAP; } // ok: they are not collinear! double tdet = -c; // the denominator of the parameter must be positive if(det < 0.0) { det = -det; tdet = -tdet; } // compute intersection point double alpha = tdet / det; first.x = s1.p1.x + alpha * (s1.p2.x - s1.p1.x); first.y = s1.p1.y + alpha * (s1.p2.y - s1.p1.y); return CROSS; }
gde::geom::algorithm::segment_relation_type gde::geom::algorithm::compute_intesection_v1(const gde::geom::core::line_segment& s1, const gde::geom::core::line_segment& s2, gde::geom::core::point& first, gde::geom::core::point& second) { double a1 = s1.p2.y - s1.p1.y; double b1 = s1.p1.x - s1.p2.x; double c1 = (s1.p2.x * s1.p1.y) - (s1.p1.x * s1.p2.y); double r3 = a1 * s2.p1.x + b1 * s2.p1.y + c1; double r4 = a1 * s2.p2.x + b1 * s2.p2.y + c1; // if both points from segment s2 are to the sime side of line defined by segment s1, // we are sure s2 can not intersects s1 if((r3 != 0.0) && (r4 != 0.0) && same_signs(r3, r4)) return DISJOINT; // compute general line equation for segment s2 double a2 = s2.p2.y - s2.p1.y; double b2 = s2.p1.x - s2.p2.x; double c2 = (s2.p2.x * s2.p1.y) - (s2.p1.x * s2.p2.y); double r1 = a2 * s1.p1.x + b2 * s1.p1.y + c2; double r2 = a2 * s1.p2.x + b2 * s1.p2.y + c2; // if both points from segment s1 are to the sime side of line defined by segment s2, // we are sure s1 can not intersects s2 if((r1 != 0.0) && (r2 != 0.0) && same_signs(r1, r2)) return DISJOINT; // setting the denominator double denom = a1 * b2 - a2 * c1; if(denom == 0.0) // are they collinear? { if(do_collinear_segments_intersects(s1, s2) == false) return DISJOINT; // and we know they intersects: let's order the segments and find out intersection(s) const gde::geom::core::point* pts[4]; pts[0] = &s1.p1; pts[1] = &s1.p2; pts[2] = &s2.p1; pts[3] = &s2.p2; std::sort(pts, pts + 4, point_cmp); // at least they will share one point first = *pts[1]; // and if segments touch in a single point they are equal if((pts[1]->x == pts[2]->x) && (pts[1]->y == pts[2]->y)) return TOUCH; // otherwise, the middle points are the intesections second = *pts[2]; return OVERLAP; } // ok: they are not collinear! double offset = denom < 0.0 ? - denom / 2.0 : denom / 2.0; // setting the numerator // compute intersection point double num_alpha = b1 * c2 - b2 * c1; first.x = (num_alpha < 0.0 ? num_alpha - offset : num_alpha + offset) / denom; double num_beta = a2 * c1 - a1 * c2; first.y = (num_beta < 0.0 ? num_beta - offset : num_beta + offset) / denom; return CROSS; }
/// \{ template<class T> inline bool opposite_signs(const T & a, const T & b) { return not same_signs(a, b); }