294 lines
7.2 KiB
C++
Executable File
294 lines
7.2 KiB
C++
Executable File
/*
|
||
* © Copyright 2014 – Urheberrechtshinweis
|
||
* Alle Rechte vorbehalten / All Rights Reserved
|
||
*
|
||
* Programmcode ist urheberrechtlich geschuetzt.
|
||
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
|
||
* Keine Verwendung ohne explizite Genehmigung.
|
||
* (vgl. § 106 ff UrhG / § 97 UrhG)
|
||
*/
|
||
|
||
#ifndef LINE2D_H
|
||
#define LINE2D_H
|
||
|
||
//#include <KLib/geo/Line.h>
|
||
#include "Point2.h"
|
||
#include "Ray2.h"
|
||
|
||
class Line2 {
|
||
|
||
public:
|
||
|
||
Point2 p1;
|
||
|
||
Point2 p2;
|
||
|
||
public:
|
||
|
||
/** empty ctor */
|
||
Line2() : p1(), p2() {;}
|
||
|
||
/** value ctor */
|
||
Line2(const Point2 p1, const Point2 p2) : p1(p1), p2(p2) {;}
|
||
|
||
/** value ctor */
|
||
Line2(const float x1, const float y1, const float x2, const float y2) : p1(x1,y1), p2(x2,y2) {;}
|
||
|
||
|
||
Line2 operator * (const float v) const {return Line2(p1*v, p2*v);}
|
||
|
||
// bool getSegmentIntersection(const Line& other) const {
|
||
// static K::Point p;
|
||
// return K::Line::getSegmentIntersection(other, p);
|
||
// }
|
||
|
||
|
||
float getAngle() const {
|
||
return std::atan2(p2.y-p1.y, p2.x-p1.x);
|
||
}
|
||
|
||
void reverse() {
|
||
std::swap(p1, p2);
|
||
}
|
||
|
||
float getLength() const {
|
||
return p1.getDistance(p2);
|
||
}
|
||
|
||
/** keep the starting point, but make the line longer by the given length */
|
||
Line2 longerAtEnd(const float l) {
|
||
Point2 dir = p2-p1;
|
||
return Line2(p1, p1+dir+dir.normalized()*l);
|
||
}
|
||
|
||
/** keep the ending point, but make the line longer by the given length */
|
||
Line2 longerAtStart(const float l) {
|
||
Point2 dir = p1-p2;
|
||
return Line2(p2, p2+dir+dir.normalized()*l);
|
||
}
|
||
|
||
/** get intersection between these two lines (unlimited length!) */
|
||
bool getLineIntersection(const Line2& other, Point2& result) const {
|
||
|
||
double bx = p2.x - p1.x;
|
||
double by = p2.y - p1.y;
|
||
|
||
double dx = other.p2.x - other.p1.x;
|
||
double dy = other.p2.y - other.p1.y;
|
||
|
||
double b_dot_d_perp = bx*dy - by*dx;
|
||
|
||
if(b_dot_d_perp == 0) {return false;}
|
||
|
||
double cx = other.p1.x - p1.x;
|
||
double cy = other.p1.y - p1.y;
|
||
double t = (cx*dy - cy*dx) / b_dot_d_perp;
|
||
|
||
result.x = p1.x + t * bx;
|
||
result.y = p1.y + t * by;
|
||
|
||
return true;
|
||
|
||
}
|
||
|
||
bool getSegmentIntersection(const Line2& other) const {
|
||
|
||
const float p0_x = p1.x, p1_x = p2.x, p2_x = other.p1.x, p3_x = other.p2.x;
|
||
const float p0_y = p1.y, p1_y = p2.y, p2_y = other.p1.y, p3_y = other.p2.y;
|
||
|
||
const float s1_x = p1_x - p0_x;
|
||
const float s1_y = p1_y - p0_y;
|
||
const float s2_x = p3_x - p2_x;
|
||
const float s2_y = p3_y - p2_y;
|
||
|
||
const float s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
const float t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
|
||
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
|
||
// Collision detected
|
||
// if (i_x != NULL)
|
||
// *i_x = p0_x + (t * s1_x);
|
||
// if (i_y != NULL)
|
||
// *i_y = p0_y + (t * s1_y);
|
||
return true;
|
||
}
|
||
|
||
return false; // No collision
|
||
|
||
|
||
|
||
// const double delta = 0.0000001;
|
||
|
||
// const double bx = p2.x - p1.x;
|
||
// const double by = p2.y - p1.y;
|
||
|
||
// const double dx = other.p2.x - other.p1.x;
|
||
// const double dy = other.p2.y - other.p1.y;
|
||
|
||
// const double b_dot_d_perp = bx*dy - by*dx;
|
||
|
||
// if (std::abs(b_dot_d_perp) == 0) {return false;}
|
||
|
||
// const double cx = other.p1.x - p1.x;
|
||
// const double cy = other.p1.y - p1.y;
|
||
|
||
// const double t = (cx * dy - cy * dx) / b_dot_d_perp;
|
||
// if(t < 0+delta || t > 1-delta) {
|
||
// return false;}
|
||
|
||
// const double u = (cx * by - cy * bx) / b_dot_d_perp;
|
||
// if(u < 0+delta || u > 1-delta) {
|
||
// return false;}
|
||
|
||
// return true;
|
||
|
||
}
|
||
|
||
bool getSegmentIntersection(const Line2& other, Point2& result) const {
|
||
|
||
const float delta = 0.000001;
|
||
|
||
const float bx = p2.x - p1.x;
|
||
const float by = p2.y - p1.y;
|
||
|
||
const float dx = other.p2.x - other.p1.x;
|
||
const float dy = other.p2.y - other.p1.y;
|
||
|
||
const float b_dot_d_perp = bx*dy - by*dx;
|
||
|
||
if(b_dot_d_perp == 0) {return false;}
|
||
|
||
const float cx = other.p1.x - p1.x;
|
||
const float cy = other.p1.y - p1.y;
|
||
|
||
const float t = (cx * dy - cy * dx) / b_dot_d_perp;
|
||
if(t < 0+delta || t > 1-delta) {
|
||
return false;}
|
||
|
||
const float u = (cx * by - cy * bx) / b_dot_d_perp;
|
||
if(u < 0+delta || u > 1-delta) {
|
||
return false;}
|
||
|
||
result.x = p1.x + t * bx;
|
||
result.y = p1.y + t * by;
|
||
|
||
return true;
|
||
|
||
}
|
||
|
||
|
||
bool getSegmentIntersectionInt(const Line2& other, Point2& result) const {
|
||
|
||
int mul = 100;
|
||
|
||
const float p0_x = std::round(p1.x*mul), p1_x = std::round(p2.x*mul), p2_x = std::round(other.p1.x*mul), p3_x = std::round(other.p2.x*mul);
|
||
const float p0_y = std::round(p1.y*mul), p1_y = std::round(p2.y*mul), p2_y = std::round(other.p1.y*mul), p3_y = std::round(other.p2.y*mul);
|
||
|
||
const float s1_x = p1_x - p0_x;
|
||
const float s1_y = p1_y - p0_y;
|
||
const float s2_x = p3_x - p2_x;
|
||
const float s2_y = p3_y - p2_y;
|
||
|
||
const float s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
const float t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
|
||
if (s >= 0 && s <= 1 && t >= 0 && t <= 1) {
|
||
result.x = (p0_x + (t * s1_x)) / mul;
|
||
result.y = (p0_y + (t * s1_y)) / mul;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
|
||
}
|
||
|
||
/** does the line intersect with the given ray? */
|
||
bool intersects(const Ray2& ray, Point2& result) const {
|
||
|
||
//https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
|
||
|
||
const float p0_x = p1.x, p1_x = p2.x;
|
||
const float p0_y = p1.y, p1_y = p2.y;
|
||
|
||
const float p2_x = ray.start.x;//, p3_x = other.p2.x;
|
||
const float p2_y = ray.start.y;//, p3_y = other.p2.y;
|
||
|
||
const float s1_x = p1_x - p0_x;
|
||
const float s1_y = p1_y - p0_y;
|
||
|
||
const float s2_x = ray.dir.x; // p3_x - p2_x;
|
||
const float s2_y = ray.dir.y; // p3_y - p2_y;
|
||
|
||
// ray_start + s * ray_dir
|
||
const float s = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
|
||
// before the ray's start?
|
||
if (s < 0) {return false;}
|
||
|
||
// line.p1 + t * (line.p2-line.p1)
|
||
const float t = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x)) / (-s2_x * s1_y + s1_x * s2_y);
|
||
|
||
// t must be between 0 and 1, otherwise we are before the line's start / after the line's end
|
||
if (t < 0 || t > 1) {return false;}
|
||
|
||
// intersection
|
||
result.x = (p0_x + (t * s1_x));
|
||
result.y = (p0_y + (t * s1_y));
|
||
return true;
|
||
|
||
}
|
||
|
||
|
||
};
|
||
|
||
|
||
static inline bool intersects(const Line2& l1, const Line2& l2, bool limit, Point2& pos, float* _u = nullptr) {
|
||
|
||
// (sx1,sy1) + (dx1, dy1)*u = (sx2, sy2) + (dx2, dy2)*v
|
||
// solve((c+d*v-a)/b = (g+h*v-e)/f, v)
|
||
// solve((a+b*u-c)/d = (e+f*u-g)/h, u)
|
||
// bf != 0
|
||
// dh != 0
|
||
// df != bh // kollinear (b/d != f/h)
|
||
|
||
const float sx1 = l1.p1.x; // a
|
||
const float sy1 = l1.p1.y; // e
|
||
|
||
const float dx1 = l1.p2.x - l1.p1.x; // b
|
||
const float dy1 = l1.p2.y - l1.p1.y; // f
|
||
|
||
const float sx2 = l2.p1.x; // c
|
||
const float sy2 = l2.p1.y; // g
|
||
|
||
const float dx2 = l2.p2.x - l2.p1.x; // d
|
||
const float dy2 = l2.p2.y - l2.p1.y; // h
|
||
|
||
// collinear?
|
||
const float a1 = dx2*dy1;
|
||
const float a2 = dx1*dy2;
|
||
if (std::abs(a1-a2) < 0.0001) {return false;}
|
||
|
||
const float v = (dy1*(sx1-sx2) + dx1*(sy2-sy1)) / (dx2*dy1 - dx1*dy2);
|
||
const float u = (dy2*(sx1-sx2) + dx2*(sy2-sy1)) / (dx2*dy1 - dx1*dy2);
|
||
|
||
//const float x = sx2 + v*dx2;
|
||
//const float y = sy2 + v*dy2;
|
||
|
||
const float x = sx1 + u*dx1;
|
||
const float y = sy1 + u*dy1;
|
||
|
||
if (!limit || (u >= 0 && v >= 0 && u <= 1 && v <= 1)) {
|
||
pos = Point2(x,y);
|
||
if (_u) {*_u = u;}
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
#endif // LINE2D_H
|