24#ifndef JAU_GEOM2F_HPP_
25#define JAU_GEOM2F_HPP_
56 return (b.
x - a.
x) * (c.
y - a.
y) - (b.
y - a.
y) * (c.
x - a.
x);
63 const double area =
tri_area(a, b, c);
105 : p0( p0_ ), p1( p1_ ) {}
121 constexpr float length() const noexcept {
129 return (p1 - p0).angle();
136 const Vec2f a = p1 - p0;
137 const Vec2f b = o.p1 - o.p0;
143 const float a_move = angle();
159 bool is_on_line(
const Point2f& p2)
const noexcept {
163 const float perpDotProduct = (p0.
x - p2.x) * (p1.
y - p2.y) - (p0.
y - p2.y) * (p1.
x - p2.x);
167 bool is_on_line2(
const Point2f& p2)
const noexcept {
182 if ( !( ( p0.
x <= p2.x && p2.x <= p1.
x ) || ( p1.
x <= p2.x && p2.x <= p0.
x ) ) ) {
186 if ( !( ( p0.
y <= p2.y && p2.y <= p1.
y ) || ( p1.
y <= p2.y && p2.y <= p0.
y ) ) ) {
190 return is_on_line(p2);
200 const Point2f& q,
const Point2f& q2,
const bool do_collinear=
false)
203 constexpr const float eps = std::numeric_limits<float>::epsilon();
204 const Vec2f r = p2 - p;
205 const Vec2f s = q2 - q;
206 const float rxs = r.
cross(s);
209 if ( do_collinear ) {
210 const Vec2f q_p = q - p;
211 const float qpxr = q_p.
cross(r);
217 const float qp_dot_r = q_p.
dot(r);
218 const float pq_dot_s = p_q.
dot(s);
221 if ( ( eps <= qp_dot_r && qp_dot_r - r.
dot(r) <= eps ) ||
222 ( eps <= pq_dot_s && pq_dot_s - s.
dot(s) <= eps ) )
242 const Vec2f q_p = q - p;
243 const float qpxr = q_p.
cross(r);
249 const float t = q_p.
cross(s) / rxs;
252 const float u = qpxr / rxs;
255 if ( (eps <= t && t - 1 <= eps) && (eps <= u && u - 1 <= eps) )
258 result = p + (t * r);
275 return intersects(result, p0, p1, o.p0, o.p1);
285 return intersects(result, p0, p1, o.p0, o.p1);
293 if (or_1 != or_2 && or_3 != or_4) {
294 pixel::log_printf(
"i-g-0: %s with %s\n",
toString().c_str(), o.toString().c_str());
302 if (or_1 == pixel::orientation_t::COL && is_on_line (o.p0)) {
303 pixel::log_printf(
"i-s-1: %s with %s\n",
toString().c_str(), o.toString().c_str());
308 if (or_2 == pixel::orientation_t::COL && is_on_line (o.p1)) {
309 pixel::log_printf(
"i-s-2: %s with %s\n",
toString().c_str(), o.toString().c_str());
314 if (or_3 == pixel::orientation_t::COL && o.is_on_line (p0)) {
315 pixel::log_printf(
"i-s-3: %s with %s\n",
toString().c_str(), o.toString().c_str());
320 if (or_4 == pixel::orientation_t::COL && o.is_on_line (p1)) {
321 pixel::log_printf(
"i-s-4: %s with %s\n",
toString().c_str(), o.toString().c_str());
341 const float l2 = p1.
dist_sq(p0);
342 if( l2 < std::numeric_limits<float>::epsilon() ) {
352 const Vec2f projection = p0 + t * (p1 - p0);
353 return p.
dist(projection);
358 const Vec2f d = (p1 - p0) * 0.5f;
361 const Vec2f lseg_center = p0 + d;
362 const Vec2f c = lseg_center - aabb_center;
378 if (
std::abs(d.
x * c.
y - d.
y * c.
x) > e.
x * ad.
y + e.
y * ad.
x + std::numeric_limits<float>::epsilon()) {
390 cross_normal = (p1 - p0).normal_ccw().normalize();
391 const Vec2f v_in = cross_point - in.p0;
392 reflect_out = v_in - ( 2.0f * v_in.
dot(cross_normal) * cross_normal );
407 if( lt.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
410 if( lb.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
414 if( lb.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
417 if( lt.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
428 if( lr.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
431 if( ll.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
435 if( ll.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
438 if( lr.
intersection(reflect_out, cross_normal, cross_point, *
this) ) {
457 virtual void rotate(
const float rad)
noexcept = 0;
460 virtual void move(
const float dx,
const float dy)
noexcept = 0;
461 virtual bool tick(
const float dt)
noexcept { (void)dt;
return true; }
485 : center( c_), radius(r_), dir_angle(0.0f) {}
488 : center(x, y), radius(r_), dir_angle(0.0f) {}
491 return "disk[c " + center.
toString() +
500 Point2f bl = { center.
x - radius, center.
y - radius};
501 Point2f tr = { center.
x + radius, center.
y + radius};
506 return center.
dist(o) <= radius;
511 return o.intersects(
box());
523 if( !in.intersects(
box() ) ) {
526 cross_point = center;
527 const float dx = in.p1.
x - in.p0.x;
528 const float dy = in.p1.y - in.p0.y;
530 const Vec2f v_in = in.p1 - in.p0;
532 reflect_out = -1.0f * v_in;
536 void rotate(
const float rad)
noexcept override {
542 dir.rotate(dir_angle);
549 void move(
const float dx,
const float dy)
noexcept override {
579 Rect2f(
const Point2f& tl_,
const float width,
const float height,
const float radians)
noexcept
582 p_b = { p_a.
x + width, p_a.
y };
583 p_c = { p_a.
x , p_a.
y - height};
584 p_d = { p_a.
x + width, p_a.
y - height};
585 p_center = { p_a.
x + width/2 , p_a.
y - height/2 };
592 p_b = { p_a.
x + width, p_a.
y };
593 p_c = { p_a.
x , p_a.
y - height};
594 p_d = { p_a.
x + width, p_a.
y - height};
595 p_center = { p_a.
x + width/2 , p_a.
y - height/2 };
601 : p_a(tl_), p_b(tr_), p_c(bl_), p_d(br_)
603 p_center = { ( p_a.
x + p_b.
x ) / 2.0f , ( p_a.
y + p_c.
y ) / 2.0f };
613 dir.rotate(dir_angle);
628 void move(
const float dx,
const float dy)
noexcept override {
633 p_center.
add(dx, dy);
636 void rotate(
const float radians)
noexcept override {
637 rotate(radians, p_center);
640 const float cos = std::cos(radians);
641 const float sin = std::sin(radians);
646 dir_angle += radians;
651 const float dx = p.
x - p_a.
x;
652 const float dy = p.
y - p_a.
y;
661 return o.intersects(
box());
676 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
683 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
690 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
697 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
711 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
721 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
731 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
741 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
770 : p_list(), p_center(), dir_angle(0.0f) {
774 : p_list(), p_center(center), dir_angle(angle) {
780 for(
size_t i=0; i<p_list.size()-1; ++i) {
785 if( p_list[p_list.size()-1] != p_list[0] ) {
786 c += p_list[p_list.size()-1];
789 this->p_center = c /
static_cast<float>(n);
794 for(
const Point2f& p : p_list) {
802 dir.rotate(dir_angle);
815 void move(
const float dx,
const float dy)
noexcept override {
819 p_center.
add(dx, dy);
822 void rotate(
const float radians)
noexcept override {
823 const float cos = std::cos(radians);
824 const float sin = std::sin(radians);
827 for(
size_t i=0; i<p_list.size(); ++i) {
828 point2f_t& p = p_list[i];
829 p.rotate(sin, cos, p_center);
833 p.rotate(sin, cos, p_center);
835 dir_angle += radians;
839 const float dx = p.
x - p_center.
x;
840 const float dy = p.
y - p_center.
y;
849 return o.intersects(
box());
861 if( p_list.size() < 2 ) {
865 for(
size_t i=1; i<p_list.size(); ++i) {
868 if( l.intersects(o) ) {
877 const LineSeg2f& in)
const noexcept override {
878 if( p_list.size() < 2 ) {
882 for(
size_t i=1; i<p_list.size(); ++i) {
885 if( l.
intersection(reflect_out, cross_normal, cross_point, in) ) {
894 return "linestrip[center " + p_center.
toString() +
constexpr Vector2F & normalize() noexcept
Normalize this vector in place, returns *this.
constexpr Vector2F & add(const value_type dx, const value_type dy) noexcept
this = this + {sx, sy}, returns this.
constexpr_cxx26 Vector2F & rotate(const value_type radians, const Vector2F &ctr) noexcept
Rotates this vector in place, returns *this.
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.
std::string toString() const noexcept
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
constexpr value_type dist(const Vector2F &o) const noexcept
Return the distance between this vector and the given one.
constexpr value_type dist_sq(const Vector2F &o) const noexcept
Return the squared distance between this vector and the given one.
Axis Aligned Bounding Box.
AABBox2f & resize(const AABBox2f &o) noexcept
Resize the AABBox to encapsulate another AABox.
Point2f bl
bottom left (low)
Point2f tr
top right (high)
bool intersects(const AABBox2f &o) const noexcept
bool contains(const float x, const float y) const noexcept
Check if the point is bounded/contained by this AABBox.
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.
A clockwise (CW) polyline.
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::string to_string(const alphabet &v) noexcept
std::enable_if< std::is_floating_point_v< T >, bool >::type 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.
constexpr T min(const T x, const T y) noexcept
Returns the minimum of two integrals (w/ branching) in O(1)
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
constexpr T abs(const T x) noexcept
Returns the absolute value of an arithmetic number (w/ branching) in O(1)
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
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