// Slow convolution, multiplying two polynomials. // Complexity: O(nu * nv). void conv(const Poly& u, const Poly& v, Poly& w) { if(u.empty() || v.empty()) {w.clear(); return;} int nu = u.size(), nv = v.size(); w.assign(nu + nv - 1, 0); for(int i = 0; i < nu; i++) for(int j = 0; j < nv; j++) w[i+j] ^= (u[i] & v[j]); tidy(w); }
Poly divide(Poly const &a, Poly const &b, Poly &r) { Poly c; r = a; // remainder assert(!b.empty()); const unsigned k = a.degree(); const unsigned l = b.degree(); c.resize(k, 0.); for(unsigned i = k; i >= l; i--) { assert(i >= 0); double ci = r.back()/b.back(); c[i-l] += ci; Poly bb = ci*b; //std::cout << ci <<"*(" << b.shifted(i-l) << ") = " // << bb.shifted(i-l) << " r= " << r << std::endl; r -= bb.shifted(i-l); r.pop_back(); } //std::cout << "r= " << r << std::endl; r.normalize(); c.normalize(); return c; }
void reduce(Poly &v) { while (!v.empty() && v.back() % MOD == 0) { v.pop_back(); } }
// GCD void gcd(const Poly& m, const Poly& n, Poly& w) { if(n.empty()) { w = m; return; } Poly q, r; deconv(m, n, q, r); gcd(n, r, w); }
Poly gcd(Poly const &a, Poly const &b, const double tol) { if(a.size() < b.size()) return gcd(b, a); if(b.empty()) return a; if(b.size() == 1) return a; Poly r; divide(a, b, r); return gcd(b, r); }
float checkCollision(const Poly& a, const Poly& b, Vec2* pnormal, Vec2* pwhere) { Vec2 normal; Vec2 where; if (a.empty() || b.empty()) return 0; float distance = 9e99; for (size_t m = 0; m < 2; m++) { const Poly* pa = m ? &a : &b; const Poly* pb = m ? &b : &a; Vec2 p1 = pa->back(); for (Vec2 p2: *pa) { float c_d = 0; Vec2 c_n; Vec2 c_w; Vec2 n = {p1.y - p2.y, p2.x - p1.x}; for (Vec2 w: *pb) { float d = (p1.x - w.x) * n.x + (p1.y - w.y) * n.y; if (d > c_d) { c_d = d; c_n = n; c_w = w; } } if (c_d == 0) return 0; float ool = 1 / sqrtf(n.x * n.x + n.y * n.y); c_d *= ool; if (c_d < distance) { distance = c_d; if (m == 1) ool = -ool; normal = n * ool; where = c_w; } p1 = p2; } } if (pnormal) *pnormal = normal; if (pwhere) *pwhere = where; return distance; }
bool is_zero(Poly p) { reduce(p); return p.empty(); }
// Simplify the polynomial, eliminates the high-degree zero term. void tidy(Poly& c) { while(!c.empty() && c.back() == 0) c.pop_back(); }