/* Fixed point implementation of 2 dimensional pnttors. */ #ifndef COM_PNT_H #define COM_PNT_H #include "def.h" #include "fix.h" #include "vec.h" #include typedef struct { com_def_alignedas(16) com_def_vector(com_fix_t, a, 2); } com_pnt_t; static inline com_pnt_t com_pnt_from(com_fix_t x, com_fix_t y) { return (com_pnt_t){.a = {x, y}}; } static inline com_pnt_t com_pnt_from_vec(com_vec_t a) { return (com_pnt_t){.a = {a.a[0], a.a[1]}}; } static inline com_pnt_t com_pnt_identity(void) { return (com_pnt_t){.a = { COM_FIX_FRACUNIT, COM_FIX_FRACUNIT, }}; } static inline com_pnt_t com_pnt_add(com_pnt_t a, com_pnt_t b) { return (com_pnt_t){ .a = {com_fix_add(a.a[0], b.a[0]), com_fix_add(a.a[1], b.a[1])}}; } static inline com_pnt_t com_pnt_sub(com_pnt_t a, com_pnt_t b) { return (com_pnt_t){ .a = {com_fix_sub(a.a[0], b.a[0]), com_fix_sub(a.a[1], b.a[1])}}; } static inline com_pnt_t com_pnt_mul(com_pnt_t a, com_pnt_t b) { return (com_pnt_t){ .a = {com_fix_mul(a.a[0], b.a[0]), com_fix_mul(a.a[1], b.a[1])}}; } /* Note: this does not clamp for over/underflow cases */ static inline com_pnt_t com_pnt_div(com_pnt_t a, com_pnt_t b) { return (com_pnt_t){ .a = {com_fix_div(a.a[0], b.a[0]), com_fix_div(a.a[1], b.a[1])}}; } /* Scale pnttor by a fixed point number */ static inline com_pnt_t com_pnt_scl(com_pnt_t a, com_fix_t b) { return (com_pnt_t){.a = {com_fix_mul(a.a[0], b), com_fix_mul(a.a[1], b)}}; } static inline com_fix_t com_pnt_min(com_pnt_t a) { return com_fix_min(a.a[0], a.a[1]); } static inline com_fix_t com_pnt_max(com_pnt_t a) { return com_fix_max(a.a[0], a.a[1]); } /* TODO: Safeguard by com_fix_mul()? */ /* Tests whether a point is lying right to a line produced by l0 and l1. This assumes that l0 and l1 are in clockwise order. Result is positive or zero if it holds true, otherwise it's negative. This also produces area of a triangle! */ static inline com_fix_t com_pnt_edge_orient(com_pnt_t l0, com_pnt_t l1, com_pnt_t p) { return (l0.a[0] - l1.a[0]) * (p.a[1] - l1.a[1]) - (l0.a[1] - l1.a[1]) * (p.a[0] - l1.a[0]); } #define com_pnt_area(m_p0, m_p1, m_p2) (com_pnt_edge_orient(m_p0, m_p1, m_p2)) static inline com_vec_t com_pnt_edge_weight(com_pnt_t v0, com_pnt_t v1, com_pnt_t v2, com_pnt_t p) { return (com_vec_t){.a = {com_pnt_edge_orient(v1, v2, p), com_pnt_edge_orient(v2, v0, p), com_pnt_edge_orient(v0, v1, p)}}; } static inline void com_pnt_print(com_pnt_t a) { com_fix_print(a.a[0]); com_fix_print(a.a[1]); } #endif