11#ifndef JAU_MATH_GEOM_GEOM2F_HPP_
12#define JAU_MATH_GEOM_GEOM2F_HPP_
23 using namespace jau::math;
43 return (b.
x - a.
x) * (c.
y - a.
y) - (b.
y - a.
y) * (c.
x - a.
x);
50 const double area =
tri_area(a, b, c);
64 constexpr const float eps = std::numeric_limits<float>::epsilon();
65 const Vec2f r = p2 - p;
66 const Vec2f s = q2 - q;
67 const float rxs = r.
cross(s);
71 const Vec2f q_p = q - p;
72 const float qpxr = q_p.
cross(r);
78 const float qp_dot_r = q_p.
dot(r);
79 const float pq_dot_s = p_q.
dot(s);
82 if ( ( eps <= qp_dot_r && qp_dot_r - r.
dot(r) <= eps ) ||
83 ( eps <= pq_dot_s && pq_dot_s - s.
dot(s) <= eps ) )
105 const Vec2f q_p = q - p;
106 const float qpxr = q_p.
cross(r);
112 const float t = q_p.
cross(s) / rxs;
115 const float u = qpxr / rxs;
118 if ( (eps <= t && t - 1 <= eps) && (eps <= u && u - 1 <= eps) )
122 *result = p + (t * r);
166 :
p0( p0_ ),
p1( p1_ ) {}
182 constexpr float length() const noexcept {
190 return (
p1 -
p0).angle();
198 const Vec2f b = o.p1 - o.p0;
204 const float a_move =
angle();
210 std::string
toString() const noexcept
override {
return "L[" +
p0.toString() +
", " +
p1.toString() +
"]"; }
220 bool is_on_line(
const Point2f& p2)
const noexcept {
224 const float perpDotProduct = (p0.
x - p2.x) * (p1.
y - p2.y) - (p0.
y - p2.y) * (p1.
x - p2.x);
228 bool is_on_line2(
const Point2f& p2)
const noexcept {
229 if ( p2.x <= std::max(p0.
x, p1.
x) && p2.x >= std::min (p0.
x, p1.
x) &&
230 p2.y <= std::max(p0.
y, p2.y) && p2.y >= std::min (p0.
y, p1.
y) )
243 if ( !( (
p0.x <= p2.x && p2.x <=
p1.x ) || (
p1.x <= p2.x && p2.x <=
p0.x ) ) ) {
247 if ( !( (
p0.y <= p2.y && p2.y <=
p1.y ) || (
p1.y <= p2.y && p2.y <=
p0.y ) ) ) {
251 return is_on_line(p2);
286 const float l2 =
p1.dist_sq(
p0);
287 if( l2 < std::numeric_limits<float>::epsilon() ) {
296 const float t = std::max(0.0f, std::min(1.0f, pv.
dot(wv) / l2));
298 return p.dist(projection);
305 const Vec2f aabb_center = (
box.bl +
box.tr) * 0.5f;
306 const Vec2f lseg_center =
p0 + d;
307 const Vec2f c = lseg_center - aabb_center;
308 const Vec2f ad(std::abs(d.
x), std::abs(d.
y));
309 if (std::abs(c.
x) > e.
x + ad.
x) {
312 if (std::abs(c.
y) > e.
y + ad.
y) {
323 if (std::abs(d.
x * c.
y - d.
y * c.
x) > e.
x * ad.
y + e.
y * ad.
x + std::numeric_limits<float>::epsilon()) {
335 cross_normal = (
p1 -
p0).normal_ccw().normalize();
336 const Vec2f v_in = cross_point - in.p0;
337 reflect_out = v_in - ( 2.0f * v_in.
dot(cross_normal) * cross_normal );
352 if( lt.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
355 if( lb.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
359 if( lb.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
362 if( lt.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
371 const float dl = ll.distance(
p0 );
373 if( lr.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
376 if( ll.intersection(reflect_out, cross_normal, cross_point, *
this) ) {
380 if( ll.intersection(reflect_out, cross_normal, cross_point, *
this) ) {
383 if( lr.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
402 virtual void rotate(
const float rad)
noexcept = 0;
405 virtual void move(
const float dx,
const float dy)
noexcept = 0;
406 virtual bool tick(
const float dt)
noexcept { (void)dt;
return true; }
436 return "disk[c " +
center.toString() +
437 ", r " + std::to_string(
radius) +
456 return o.intersects(
box());
460 return box().intersects(o);
464 return box().intersects(o.box());
468 if( !in.intersects(
box() ) ) {
472 const float dx = in.p1.x - in.p0.x;
473 const float dy = in.p1.y - in.p0.y;
474 cross_normal =
Vec2f(-dy, dx).normalize();
475 const Vec2f v_in = in.p1 - in.p0;
477 reflect_out = -1.0f * v_in;
481 void rotate(
const float rad)
noexcept override {
494 void move(
const float dx,
const float dy)
noexcept override {
524 Rect2f(
const Point2f& tl_,
const float width,
const float height,
const float radians)
noexcept
573 void move(
const float dx,
const float dy)
noexcept override {
581 void rotate(
const float radians)
noexcept override {
585 const float cos = std::cos(radians);
586 const float sin = std::sin(radians);
587 p_a.rotate(sin, cos, p);
588 p_b.rotate(sin, cos, p);
589 p_c.rotate(sin, cos, p);
590 p_d.rotate(sin, cos, p);
596 const float dx = p.
x -
p_a.x;
597 const float dy = p.
y -
p_a.y;
602 return box().contains(o);
606 return o.intersects(
box());
610 return box().intersects(o);
614 return box().intersects(o.box());
621 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
628 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
635 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
642 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
653 const Vec2f added_size = (l.p1 - l.p0).normal_ccw().normalize() * in_radius;
656 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
663 const Vec2f added_size = (l.p1 - l.p0).normal_ccw().normalize() * in_radius;
666 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
673 const Vec2f added_size = (l.p1 - l.p0).normal_ccw().normalize() * in_radius;
676 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
683 const Vec2f added_size = (l.p1 - l.p0).normal_ccw().normalize() * in_radius;
686 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
694 return "rect[a " +
p_a.toString() +
695 ", b " +
p_b.toString() +
696 ", c " +
p_c.toString() +
697 ", d " +
p_d.toString() +
725 for(
size_t i=0; i<
p_list.size()-1; ++i) {
734 this->p_center = c /
static_cast<float>(n);
760 void move(
const float dx,
const float dy)
noexcept override {
767 void rotate(
const float radians)
noexcept override {
768 const float cos = std::cos(radians);
769 const float sin = std::sin(radians);
772 for(
size_t i=0; i<
p_list.size(); ++i) {
790 return box().contains(o);
794 return o.intersects(
box());
798 return box().intersects(o);
802 return box().intersects(o.box());
810 for(
size_t i=1; i<
p_list.size(); ++i) {
813 if( l.intersects(o) ) {
822 const LineSeg2f& in)
const noexcept override {
827 for(
size_t i=1; i<
p_list.size(); ++i) {
830 if( l.intersection(reflect_out, cross_normal, cross_point, in) ) {
839 return "linestrip[center " +
p_center.toString() +
840 ", points " + std::to_string(
p_list.size())+
"]"; }
constexpr value_type cross(const Vector2F &o) const noexcept
Returns cross product of this vectors and the given one, i.e.
constexpr_cxx26 value_type angle() const noexcept
Return the direction angle of this vector in radians.
constexpr value_type dot(const Vector2F &o) const noexcept
Return the dot product of this vector and the given one.
static constexpr_cxx26 Vector2F from_length_angle(const value_type magnitude, const value_type radians) noexcept
Axis Aligned Bounding Box.
AABBox2f & resize(const AABBox2f &o) noexcept
Resize the AABBox to encapsulate another AABox.
Animated geometric object.
virtual void move(const float dx, const float dy) noexcept=0
virtual void move(const Point2f &d) noexcept=0
virtual void move_dir(const float d) noexcept=0
virtual void rotate(const float rad) noexcept=0
virtual bool tick(const float dt) noexcept
void move(const float dx, const float dy) noexcept override
void rotate(const float rad) noexcept override
void move(const Point2f &d) noexcept override
Disk2f(const Point2f &c_, const float r_)
Point2f center
Imagine a circle ;-)
std::string toString() const noexcept override
bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in) const noexcept override
Return whether this object intersects with the given line segment and if intersecting,...
void move_dir(const float d) noexcept override
bool intersects(const AABBox2f &o) const noexcept override
bool intersects(const LineSeg2f &o) const noexcept override
float dir_angle
direction angle in radians
Disk2f(float x, float y, const float r_)
void set_center(const Point2f &p)
bool intersects(const Geom2f &o) const noexcept override
bool contains(const Point2f &o) const noexcept override
AABBox2f box() const noexcept override
virtual AABBox2f box() const noexcept=0
virtual ~Geom2f()=default
virtual bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in) const noexcept=0
Return whether this object intersects with the given line segment and if intersecting,...
virtual std::string toString() const noexcept=0
virtual bool intersects(const LineSeg2f &o) const noexcept=0
virtual bool contains(const Point2f &o) const noexcept=0
bool intersects(const LineSeg2f &o) const noexcept override
Return true if this line segment intersect with the given line segment.
bool contains(const Point2f &p2) const noexcept override
Test intersection between this line segment and the give point.
float angle() const noexcept
Return the angle of this line segment in radians.
constexpr LineSeg2f() noexcept
float angle(const LineSeg2f &o) const noexcept
Return the angle between two line segments in radians.
bool intersection(const AABBox2f &box, Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point) const noexcept
bool intersects(const Geom2f &o) const noexcept override
constexpr float length() const noexcept
Return the length of this line segment, i.e.
bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in) const noexcept override
Return whether this object intersects with the given line segment and if intersecting,...
std::string toString() const noexcept override
bool intersects(Point2f &result, const LineSeg2f &o) const noexcept
Compute intersection between two lines segments.
constexpr LineSeg2f(const Point2f &p0_, const Point2f &p1_) noexcept
constexpr LineSeg2f & operator*=(const float s) noexcept
Scale this line segment with given scale factor.
AABBox2f box() const noexcept override
Create an AABBox with given lineseg.
bool intersects(const AABBox2f &box) const noexcept override
float distance(Point2f p) const noexcept
Returns minimum distance between this line segment and given point p.
void rotate(const float radians) noexcept override
bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in) const noexcept override
Return whether this object intersects with the given line segment and if intersecting,...
bool intersects(const AABBox2f &o) const noexcept override
void normalize_center() noexcept
bool intersects_lineonly(const LineSeg2f &o) const noexcept
void move_dir(const float d) noexcept override
void move(const Point2f &d) noexcept override
bool contains(const Point2f &o) const noexcept override
void move(const float dx, const float dy) noexcept override
std::string toString() const noexcept override
float dir_angle
direction angle in radians
AABBox2f box() const noexcept override
bool intersects(const Geom2f &o) const noexcept override
void set_center(const Point2f &p)
std::vector< Point2f > p_list
bool intersects(const LineSeg2f &o) const noexcept override
LineStrip2f(const Point2f ¢er, const float angle) noexcept
bool contains(const Point2f &o) const noexcept override
float dir_angle
direction angle in radians
void move(const Point2f &d) noexcept override
Rect2f(const Point2f &tl_, const float width, const float height, const float radians) noexcept
bool intersects(const AABBox2f &o) const noexcept override
bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in, const float in_radius) const noexcept
AABBox2f box() const noexcept override
bool intersects(const LineSeg2f &o) const noexcept override
bool intersection(Vec2f &reflect_out, Vec2f &cross_normal, Point2f &cross_point, const LineSeg2f &in) const noexcept override
Return whether this object intersects with the given line segment and if intersecting,...
Rect2f(const Point2f &tl_, const Point2f &tr_, const Point2f &bl_, const Point2f &br_) noexcept
std::string toString() const noexcept override
bool intersects(const Geom2f &o) const noexcept override
Point2f p_c
Unrotated bottom-left.
void move(const float dx, const float dy) noexcept override
void move_dir(const float d) noexcept override
Point2f p_b
Unrotated top-right.
void rotate(const float radians, const Point2f &p) noexcept
Point2f p_d
Unrotated bottom_right.
Point2f p_a
Unrotated, clockwise (CW):
Rect2f(const Point2f &tl_, const float width, const float height) noexcept
void set_top_left(const Point2f &p)
void rotate(const float radians) noexcept override
std::enable_if_t< std::is_floating_point_v< T >, bool > constexpr is_zero(const T &a, const T &epsilon=std::numeric_limits< T >::epsilon()) noexcept
Returns true if the given value is less than epsilon, w/ epsilon > 0.
std::shared_ptr< Geom2f > Geom2f_ref
std::vector< AGeom2f_ref > AGeom2f_list
std::vector< Geom2f_ref > Geom2f_list
constexpr orientation_t orientation(const Point2f &a, const Point2f &b, const Point2f &c) noexcept
Return the orientation of the given point triplet a, b and c using triArea()
std::shared_ptr< Disk2f > Disk2f_ref
std::shared_ptr< AGeom2f > AGeom2f_ref
constexpr bool testSeg2SegIntersection2D(Vec2f *result, const Vec2f &p, const Vec2f &p2, const Vec2f &q, const Vec2f &q2, const bool do_collinear=false) noexcept
See p + t r = q + u s and its terse C# implementation
std::shared_ptr< LineStrip2f > LineStrip2f_ref
constexpr double tri_area(const Point2f &a, const Point2f &b, const Point2f &c)
Computes oriented double area of a triangle, i.e.
std::shared_ptr< Rect2f > Rect2f_ref