This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/geo/Line2.h
2018-10-25 11:50:12 +02:00

294 lines
7.2 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © 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