| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #define DEBUG_DERIVS 0 |
| | #if DEBUG_DERIVS |
| | #endif |
| |
|
| | #include <cassert> |
| |
|
| | #include "Geo.h" |
| |
|
| |
|
| | namespace GCS |
| | { |
| |
|
| | |
| | int Point::PushOwnParams(VEC_pD& pvec) const |
| | { |
| | int cnt = 0; |
| | pvec.push_back(x); |
| | cnt++; |
| | pvec.push_back(y); |
| | cnt++; |
| | return cnt; |
| | } |
| |
|
| | void Point::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | x = pvec[cnt]; |
| | cnt++; |
| | y = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | |
| | DeriVector2::DeriVector2(const Point& p, const double* derivparam) |
| | : x(*p.x) |
| | , dx(0.0) |
| | , y(*p.y) |
| | , dy(0.0) |
| | { |
| | if (derivparam == p.x) { |
| | dx = 1.0; |
| | } |
| | if (derivparam == p.y) { |
| | dy = 1.0; |
| | } |
| | } |
| |
|
| | double DeriVector2::length(double& dlength) const |
| | { |
| | double l = length(); |
| | if (l == 0) { |
| | dlength = 1.0; |
| | return l; |
| | } |
| | dlength = (x * dx + y * dy) / l; |
| | return l; |
| | } |
| |
|
| | DeriVector2 DeriVector2::getNormalized() const |
| | { |
| | double l = length(); |
| | if (l == 0.0) { |
| | return DeriVector2(0, 0, dx, dy); |
| | } |
| | DeriVector2 rtn; |
| | rtn.x = x / l; |
| | rtn.y = y / l; |
| | |
| | rtn.dx = dx / l; |
| | rtn.dy = dy / l; |
| | |
| | double dsc = rtn.dx * rtn.x + rtn.dy * rtn.y; |
| | rtn.dx -= dsc * rtn.x; |
| | rtn.dy -= dsc * rtn.y; |
| | return rtn; |
| | } |
| |
|
| | double DeriVector2::scalarProd(const DeriVector2& v2, double* dprd) const |
| | { |
| | if (dprd) { |
| | *dprd = dx * v2.x + x * v2.dx + dy * v2.y + y * v2.dy; |
| | } |
| | return x * v2.x + y * v2.y; |
| | } |
| |
|
| | DeriVector2 DeriVector2::divD(double val, double dval) const |
| | { |
| | return {x / val, y / val, dx / val - x * dval / (val * val), dy / val - y * dval / (val * val)}; |
| | } |
| |
|
| | double DeriVector2::crossProdZ(const DeriVector2& v2, double& dprd) const |
| | { |
| | dprd = dx * v2.y + x * v2.dy - dy * v2.x - y * v2.dx; |
| | return x * v2.y - y * v2.x; |
| | } |
| |
|
| | DeriVector2 Curve::Value(double , double , const double* ) const |
| | { |
| | assert(false ); |
| | return {}; |
| | } |
| |
|
| | |
| |
|
| | DeriVector2 Line::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | (void)p; |
| | DeriVector2 p1v(p1, derivparam); |
| | DeriVector2 p2v(p2, derivparam); |
| |
|
| | return p2v.subtr(p1v).rotate90ccw(); |
| | } |
| |
|
| | DeriVector2 Line::Value(double u, double du, const double* derivparam) const |
| | { |
| | DeriVector2 p1v(p1, derivparam); |
| | DeriVector2 p2v(p2, derivparam); |
| |
|
| | DeriVector2 line_vec = p2v.subtr(p1v); |
| | return p1v.sum(line_vec.multD(u, du)); |
| | } |
| |
|
| | int Line::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | pvec.push_back(p1.x); |
| | cnt++; |
| | pvec.push_back(p1.y); |
| | cnt++; |
| | pvec.push_back(p2.x); |
| | cnt++; |
| | pvec.push_back(p2.y); |
| | cnt++; |
| | return cnt; |
| | } |
| | void Line::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | p1.x = pvec[cnt]; |
| | cnt++; |
| | p1.y = pvec[cnt]; |
| | cnt++; |
| | p2.x = pvec[cnt]; |
| | cnt++; |
| | p2.y = pvec[cnt]; |
| | cnt++; |
| | } |
| | Line* Line::Copy() |
| | { |
| | return new Line(*this); |
| | } |
| |
|
| |
|
| | |
| |
|
| | DeriVector2 Circle::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | DeriVector2 cv(center, derivparam); |
| | DeriVector2 pv(p, derivparam); |
| |
|
| | return cv.subtr(pv); |
| | } |
| |
|
| | DeriVector2 Circle::Value(double u, double du, const double* derivparam) const |
| | { |
| | DeriVector2 cv(center, derivparam); |
| | double r, dr; |
| | r = *(this->rad); |
| | dr = (derivparam == this->rad) ? 1.0 : 0.0; |
| | DeriVector2 ex(r, 0.0, dr, 0.0); |
| | DeriVector2 ey = ex.rotate90ccw(); |
| | double si, dsi, co, dco; |
| | si = std::sin(u); |
| | dsi = du * std::cos(u); |
| | co = std::cos(u); |
| | dco = du * (-std::sin(u)); |
| | return cv.sum(ex.multD(co, dco).sum(ey.multD(si, dsi))); |
| | } |
| |
|
| | int Circle::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | pvec.push_back(center.x); |
| | cnt++; |
| | pvec.push_back(center.y); |
| | cnt++; |
| | pvec.push_back(rad); |
| | cnt++; |
| | return cnt; |
| | } |
| | void Circle::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | center.x = pvec[cnt]; |
| | cnt++; |
| | center.y = pvec[cnt]; |
| | cnt++; |
| | rad = pvec[cnt]; |
| | cnt++; |
| | } |
| | Circle* Circle::Copy() |
| | { |
| | return new Circle(*this); |
| | } |
| |
|
| | |
| | int Arc::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | cnt += Circle::PushOwnParams(pvec); |
| | pvec.push_back(start.x); |
| | cnt++; |
| | pvec.push_back(start.y); |
| | cnt++; |
| | pvec.push_back(end.x); |
| | cnt++; |
| | pvec.push_back(end.y); |
| | cnt++; |
| | pvec.push_back(startAngle); |
| | cnt++; |
| | pvec.push_back(endAngle); |
| | cnt++; |
| | return cnt; |
| | } |
| | void Arc::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | Circle::ReconstructOnNewPvec(pvec, cnt); |
| | start.x = pvec[cnt]; |
| | cnt++; |
| | start.y = pvec[cnt]; |
| | cnt++; |
| | end.x = pvec[cnt]; |
| | cnt++; |
| | end.y = pvec[cnt]; |
| | cnt++; |
| | startAngle = pvec[cnt]; |
| | cnt++; |
| | endAngle = pvec[cnt]; |
| | cnt++; |
| | } |
| | Arc* Arc::Copy() |
| | { |
| | return new Arc(*this); |
| | } |
| |
|
| |
|
| | |
| |
|
| | |
| | double Ellipse::getRadMaj( |
| | const DeriVector2& center, |
| | const DeriVector2& f1, |
| | double b, |
| | double db, |
| | double& ret_dRadMaj |
| | ) const |
| | { |
| | double cf, dcf; |
| | cf = f1.subtr(center).length(dcf); |
| | DeriVector2 hack( |
| | b, |
| | cf, |
| | db, |
| | dcf |
| | ); |
| | |
| | return hack.length(ret_dRadMaj); |
| | } |
| |
|
| | |
| | double Ellipse::getRadMaj(double* derivparam, double& ret_dRadMaj) const |
| | { |
| | DeriVector2 c(center, derivparam); |
| | DeriVector2 f1(focus1, derivparam); |
| | return getRadMaj(c, f1, *radmin, radmin == derivparam ? 1.0 : 0.0, ret_dRadMaj); |
| | } |
| |
|
| | |
| | double Ellipse::getRadMaj() const |
| | { |
| | double dradmaj; |
| | return getRadMaj(nullptr, dradmaj); |
| | } |
| |
|
| | DeriVector2 Ellipse::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | |
| | DeriVector2 cv(center, derivparam); |
| | DeriVector2 f1v(focus1, derivparam); |
| | DeriVector2 pv(p, derivparam); |
| |
|
| | |
| | |
| | DeriVector2 f2v = cv.linCombi(2.0, f1v, -1.0); |
| |
|
| | |
| | DeriVector2 pf1 = f1v.subtr(pv); |
| | DeriVector2 pf2 = f2v.subtr(pv); |
| |
|
| | |
| | return pf1.getNormalized().sum(pf2.getNormalized()); |
| | } |
| |
|
| | DeriVector2 Ellipse::Value(double u, double du, const double* derivparam) const |
| | { |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | DeriVector2 c(this->center, derivparam); |
| | DeriVector2 f1(this->focus1, derivparam); |
| |
|
| | DeriVector2 emaj = f1.subtr(c).getNormalized(); |
| | DeriVector2 emin = emaj.rotate90ccw(); |
| | double b, db; |
| | b = *(this->radmin); |
| | db = this->radmin == derivparam ? 1.0 : 0.0; |
| | double a, da; |
| | a = this->getRadMaj(c, f1, b, db, da); |
| | DeriVector2 a_vec = emaj.multD(a, da); |
| | DeriVector2 b_vec = emin.multD(b, db); |
| | |
| |
|
| | |
| | double co, dco, si, dsi; |
| | co = std::cos(u); |
| | dco = -std::sin(u) * du; |
| | si = std::sin(u); |
| | dsi = std::cos(u) * du; |
| |
|
| | |
| | return a_vec.multD(co, dco).sum(b_vec.multD(si, dsi)).sum(c); |
| | } |
| |
|
| | int Ellipse::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | pvec.push_back(center.x); |
| | cnt++; |
| | pvec.push_back(center.y); |
| | cnt++; |
| | pvec.push_back(focus1.x); |
| | cnt++; |
| | pvec.push_back(focus1.y); |
| | cnt++; |
| | pvec.push_back(radmin); |
| | cnt++; |
| | return cnt; |
| | } |
| | void Ellipse::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | center.x = pvec[cnt]; |
| | cnt++; |
| | center.y = pvec[cnt]; |
| | cnt++; |
| | focus1.x = pvec[cnt]; |
| | cnt++; |
| | focus1.y = pvec[cnt]; |
| | cnt++; |
| | radmin = pvec[cnt]; |
| | cnt++; |
| | } |
| | Ellipse* Ellipse::Copy() |
| | { |
| | return new Ellipse(*this); |
| | } |
| |
|
| |
|
| | |
| | int ArcOfEllipse::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | cnt += Ellipse::PushOwnParams(pvec); |
| | pvec.push_back(start.x); |
| | cnt++; |
| | pvec.push_back(start.y); |
| | cnt++; |
| | pvec.push_back(end.x); |
| | cnt++; |
| | pvec.push_back(end.y); |
| | cnt++; |
| | pvec.push_back(startAngle); |
| | cnt++; |
| | pvec.push_back(endAngle); |
| | cnt++; |
| | return cnt; |
| | } |
| | void ArcOfEllipse::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | Ellipse::ReconstructOnNewPvec(pvec, cnt); |
| | start.x = pvec[cnt]; |
| | cnt++; |
| | start.y = pvec[cnt]; |
| | cnt++; |
| | end.x = pvec[cnt]; |
| | cnt++; |
| | end.y = pvec[cnt]; |
| | cnt++; |
| | startAngle = pvec[cnt]; |
| | cnt++; |
| | endAngle = pvec[cnt]; |
| | cnt++; |
| | } |
| | ArcOfEllipse* ArcOfEllipse::Copy() |
| | { |
| | return new ArcOfEllipse(*this); |
| | } |
| |
|
| | |
| |
|
| | |
| | double Hyperbola::getRadMaj( |
| | const DeriVector2& center, |
| | const DeriVector2& f1, |
| | double b, |
| | double db, |
| | double& ret_dRadMaj |
| | ) const |
| | { |
| | double cf, dcf; |
| | cf = f1.subtr(center).length(dcf); |
| | double a, da; |
| | a = sqrt(cf * cf - b * b); |
| | da = (dcf * cf - db * b) / a; |
| | ret_dRadMaj = da; |
| | return a; |
| | } |
| |
|
| | |
| | double Hyperbola::getRadMaj(double* derivparam, double& ret_dRadMaj) const |
| | { |
| | DeriVector2 c(center, derivparam); |
| | DeriVector2 f1(focus1, derivparam); |
| | return getRadMaj(c, f1, *radmin, radmin == derivparam ? 1.0 : 0.0, ret_dRadMaj); |
| | } |
| |
|
| | |
| | double Hyperbola::getRadMaj() const |
| | { |
| | double dradmaj; |
| | return getRadMaj(nullptr, dradmaj); |
| | } |
| |
|
| | DeriVector2 Hyperbola::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | |
| | DeriVector2 cv(center, derivparam); |
| | DeriVector2 f1v(focus1, derivparam); |
| | DeriVector2 pv(p, derivparam); |
| |
|
| | |
| | |
| | DeriVector2 f2v = cv.linCombi(2.0, f1v, -1.0); |
| |
|
| | |
| | DeriVector2 pf1 = f1v.subtr(pv).mult(-1.0); |
| | |
| | DeriVector2 pf2 = f2v.subtr(pv); |
| |
|
| | |
| | return pf1.getNormalized().sum(pf2.getNormalized()); |
| | } |
| |
|
| | DeriVector2 Hyperbola::Value(double u, double du, const double* derivparam) const |
| | { |
| |
|
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | DeriVector2 c(this->center, derivparam); |
| | DeriVector2 f1(this->focus1, derivparam); |
| |
|
| | DeriVector2 emaj = f1.subtr(c).getNormalized(); |
| | DeriVector2 emin = emaj.rotate90ccw(); |
| | double b, db; |
| | b = *(this->radmin); |
| | db = this->radmin == derivparam ? 1.0 : 0.0; |
| | double a, da; |
| | a = this->getRadMaj(c, f1, b, db, da); |
| | DeriVector2 a_vec = emaj.multD(a, da); |
| | DeriVector2 b_vec = emin.multD(b, db); |
| | |
| |
|
| | |
| | double co, dco, si, dsi; |
| | co = std::cosh(u); |
| | dco = std::sinh(u) * du; |
| | si = std::sinh(u); |
| | dsi = std::cosh(u) * du; |
| |
|
| | |
| | return a_vec.multD(co, dco).sum(b_vec.multD(si, dsi)).sum(c); |
| | } |
| |
|
| | int Hyperbola::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | pvec.push_back(center.x); |
| | cnt++; |
| | pvec.push_back(center.y); |
| | cnt++; |
| | pvec.push_back(focus1.x); |
| | cnt++; |
| | pvec.push_back(focus1.y); |
| | cnt++; |
| | pvec.push_back(radmin); |
| | cnt++; |
| | return cnt; |
| | } |
| | void Hyperbola::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | center.x = pvec[cnt]; |
| | cnt++; |
| | center.y = pvec[cnt]; |
| | cnt++; |
| | focus1.x = pvec[cnt]; |
| | cnt++; |
| | focus1.y = pvec[cnt]; |
| | cnt++; |
| | radmin = pvec[cnt]; |
| | cnt++; |
| | } |
| | Hyperbola* Hyperbola::Copy() |
| | { |
| | return new Hyperbola(*this); |
| | } |
| |
|
| | |
| | int ArcOfHyperbola::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | cnt += Hyperbola::PushOwnParams(pvec); |
| | pvec.push_back(start.x); |
| | cnt++; |
| | pvec.push_back(start.y); |
| | cnt++; |
| | pvec.push_back(end.x); |
| | cnt++; |
| | pvec.push_back(end.y); |
| | cnt++; |
| | pvec.push_back(startAngle); |
| | cnt++; |
| | pvec.push_back(endAngle); |
| | cnt++; |
| | return cnt; |
| | } |
| | void ArcOfHyperbola::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | Hyperbola::ReconstructOnNewPvec(pvec, cnt); |
| | start.x = pvec[cnt]; |
| | cnt++; |
| | start.y = pvec[cnt]; |
| | cnt++; |
| | end.x = pvec[cnt]; |
| | cnt++; |
| | end.y = pvec[cnt]; |
| | cnt++; |
| | startAngle = pvec[cnt]; |
| | cnt++; |
| | endAngle = pvec[cnt]; |
| | cnt++; |
| | } |
| | ArcOfHyperbola* ArcOfHyperbola::Copy() |
| | { |
| | return new ArcOfHyperbola(*this); |
| | } |
| |
|
| | |
| |
|
| | DeriVector2 Parabola::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | |
| | DeriVector2 cv(vertex, derivparam); |
| | DeriVector2 f1v(focus1, derivparam); |
| | DeriVector2 pv(p, derivparam); |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | return cv.subtr(f1v).getNormalized().subtr(f1v.subtr(pv).getNormalized()); |
| | } |
| |
|
| | DeriVector2 Parabola::Value(double u, double du, const double* derivparam) const |
| | { |
| |
|
| | |
| | |
| |
|
| | DeriVector2 c(this->vertex, derivparam); |
| | DeriVector2 f1(this->focus1, derivparam); |
| |
|
| | DeriVector2 fv = f1.subtr(c); |
| |
|
| | double f, df; |
| |
|
| | f = fv.length(df); |
| |
|
| | DeriVector2 xdir = fv.getNormalized(); |
| | DeriVector2 ydir = xdir.rotate90ccw(); |
| |
|
| | DeriVector2 dirx = xdir.multD(u, du).multD(u, du).divD(4 * f, 4 * df); |
| | DeriVector2 diry = ydir.multD(u, du); |
| |
|
| | DeriVector2 dir = dirx.sum(diry); |
| |
|
| | DeriVector2 ret; |
| |
|
| | ret = c.sum(dir); |
| |
|
| | return ret; |
| | } |
| |
|
| | int Parabola::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | pvec.push_back(vertex.x); |
| | cnt++; |
| | pvec.push_back(vertex.y); |
| | cnt++; |
| | pvec.push_back(focus1.x); |
| | cnt++; |
| | pvec.push_back(focus1.y); |
| | cnt++; |
| | return cnt; |
| | } |
| |
|
| | void Parabola::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | vertex.x = pvec[cnt]; |
| | cnt++; |
| | vertex.y = pvec[cnt]; |
| | cnt++; |
| | focus1.x = pvec[cnt]; |
| | cnt++; |
| | focus1.y = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | Parabola* Parabola::Copy() |
| | { |
| | return new Parabola(*this); |
| | } |
| |
|
| | |
| | int ArcOfParabola::PushOwnParams(VEC_pD& pvec) |
| | { |
| | int cnt = 0; |
| | cnt += Parabola::PushOwnParams(pvec); |
| | pvec.push_back(start.x); |
| | cnt++; |
| | pvec.push_back(start.y); |
| | cnt++; |
| | pvec.push_back(end.x); |
| | cnt++; |
| | pvec.push_back(end.y); |
| | cnt++; |
| | pvec.push_back(startAngle); |
| | cnt++; |
| | pvec.push_back(endAngle); |
| | cnt++; |
| | return cnt; |
| | } |
| | void ArcOfParabola::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | Parabola::ReconstructOnNewPvec(pvec, cnt); |
| | start.x = pvec[cnt]; |
| | cnt++; |
| | start.y = pvec[cnt]; |
| | cnt++; |
| | end.x = pvec[cnt]; |
| | cnt++; |
| | end.y = pvec[cnt]; |
| | cnt++; |
| | startAngle = pvec[cnt]; |
| | cnt++; |
| | endAngle = pvec[cnt]; |
| | cnt++; |
| | } |
| | ArcOfParabola* ArcOfParabola::Copy() |
| | { |
| | return new ArcOfParabola(*this); |
| | } |
| |
|
| | |
| | DeriVector2 BSpline::CalculateNormal(const Point& p, const double* derivparam) const |
| | { |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if (mult[0] > degree && mult[mult.size() - 1] > degree) { |
| | |
| | if (*p.x == *start.x && *p.y == *start.y) { |
| | |
| | |
| | DeriVector2 endpt(this->poles[1], derivparam); |
| | DeriVector2 spt(this->poles[0], derivparam); |
| |
|
| | DeriVector2 tg = endpt.subtr(spt); |
| | return tg.rotate90ccw(); |
| | } |
| | if (*p.x == *end.x && *p.y == *end.y) { |
| | |
| | |
| | DeriVector2 endpt(this->poles[poles.size() - 1], derivparam); |
| | DeriVector2 spt(this->poles[poles.size() - 2], derivparam); |
| |
|
| | DeriVector2 tg = endpt.subtr(spt); |
| | return tg.rotate90ccw(); |
| | } |
| | |
| | return {}; |
| | } |
| | |
| | |
| | return {}; |
| | } |
| |
|
| | DeriVector2 BSpline::CalculateNormal(const double* param, const double* derivparam) const |
| | { |
| | |
| | size_t startpole = 0; |
| | for (size_t j = 1; j < mult.size() && *(knots[j]) <= *param; ++j) { |
| | startpole += mult[j]; |
| | } |
| | if (!periodic && startpole >= poles.size()) { |
| | startpole = poles.size() - degree - 1; |
| | } |
| |
|
| | auto polexat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].x; |
| | }; |
| | auto poleyat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].y; |
| | }; |
| | auto weightat = [&](size_t i) { |
| | return weights[(startpole + i) % weights.size()]; |
| | }; |
| |
|
| | double xsum, xslopesum; |
| | double ysum, yslopesum; |
| | double wsum, wslopesum; |
| |
|
| | valueHomogenous(*param, &xsum, &ysum, &wsum, &xslopesum, &yslopesum, &wslopesum); |
| |
|
| | |
| | |
| | |
| | DeriVector2 result(wsum * xslopesum - wslopesum * xsum, wsum * yslopesum - wslopesum * ysum); |
| |
|
| | size_t numpoints = degree + 1; |
| |
|
| | |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | if (derivparam != polexat(i) && derivparam != poleyat(i) && derivparam != weightat(i)) { |
| | continue; |
| | } |
| |
|
| | VEC_D d(numpoints); |
| | d[i] = 1; |
| | double factor = splineValue(*param, startpole + degree, degree, d, flattenedknots); |
| | VEC_D sd(numpoints - 1); |
| | if (i > 0) { |
| | sd[i - 1] = 1.0 |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | if (i < numpoints - 1) { |
| | sd[i] = -1.0 |
| | / (flattenedknots[startpole + i + 1 + degree] - flattenedknots[startpole + i + 1]); |
| | } |
| | double slopefactor = splineValue(*param, startpole + degree, degree - 1, sd, flattenedknots); |
| |
|
| | if (derivparam == polexat(i)) { |
| | result.dx = *weightat(i) * (wsum * slopefactor - wslopesum * factor); |
| | } |
| | else if (derivparam == poleyat(i)) { |
| | result.dy = *weightat(i) * (wsum * slopefactor - wslopesum * factor); |
| | } |
| | else if (derivparam == weightat(i)) { |
| | result.dx = degree |
| | * (factor * (xslopesum - wslopesum * (*polexat(i))) |
| | - slopefactor * (xsum - wsum * (*polexat(i)))); |
| | result.dy = degree |
| | * (factor * (yslopesum - wslopesum * (*poleyat(i))) |
| | - slopefactor * (ysum - wsum * (*poleyat(i)))); |
| | } |
| | break; |
| | } |
| |
|
| | |
| | |
| | |
| | if (derivparam != param) { |
| | return result.rotate90ccw(); |
| | } |
| |
|
| | |
| | VEC_D sd(numpoints - 1), ssd(numpoints - 2); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | sd[i - 1] = (*weightat(i) - *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | for (size_t i = 1; i < numpoints - 1; ++i) { |
| | ssd[i - 1] = (sd[i] - sd[i - 1]) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double wslopeslopesum = degree * (degree - 1) |
| | * BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots); |
| |
|
| | for (size_t i = 1; i < numpoints; ++i) { |
| | sd[i - 1] = (*polexat(i) * *weightat(i) - *polexat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | for (size_t i = 1; i < numpoints - 1; ++i) { |
| | ssd[i - 1] = (sd[i] - sd[i - 1]) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double xslopeslopesum = degree * (degree - 1) |
| | * BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots); |
| |
|
| | for (size_t i = 1; i < numpoints; ++i) { |
| | sd[i - 1] = (*poleyat(i) * *weightat(i) - *poleyat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | for (size_t i = 1; i < numpoints - 1; ++i) { |
| | ssd[i - 1] = (sd[i] - sd[i - 1]) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double yslopeslopesum = degree * (degree - 1) |
| | * BSpline::splineValue(*param, startpole + degree, degree - 2, ssd, flattenedknots); |
| |
|
| | result.dx = wsum * xslopeslopesum - wslopeslopesum * xsum; |
| | result.dy = wsum * yslopeslopesum - wslopeslopesum * ysum; |
| |
|
| | return result.rotate90ccw(); |
| | } |
| |
|
| | DeriVector2 BSpline::Value(double u, double , const double* ) const |
| | { |
| | |
| | size_t startpole = 0; |
| | for (size_t j = 1; j < mult.size() && *(knots[j]) <= u; ++j) { |
| | startpole += mult[j]; |
| | } |
| | if (!periodic && startpole >= poles.size()) { |
| | startpole = poles.size() - degree - 1; |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | auto polexat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].x; |
| | }; |
| | auto poleyat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].y; |
| | }; |
| | auto weightat = [&](size_t i) { |
| | return weights[(startpole + i) % weights.size()]; |
| | }; |
| |
|
| | size_t numpoints = degree + 1; |
| | |
| | |
| | |
| | VEC_D d(numpoints); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *polexat(i) * *weightat(i); |
| | } |
| | double xsum = splineValue(u, startpole + degree, degree, d, flattenedknots); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *poleyat(i) * *weightat(i); |
| | } |
| | double ysum = splineValue(u, startpole + degree, degree, d, flattenedknots); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *weightat(i); |
| | } |
| | double wsum = splineValue(u, startpole + degree, degree, d, flattenedknots); |
| |
|
| | d.resize(numpoints - 1); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*polexat(i) * *weightat(i) - *polexat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double xslopesum = degree * splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*poleyat(i) * *weightat(i) - *poleyat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double yslopesum = degree * splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*weightat(i) - *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | double wslopesum = degree * splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| |
|
| | return { |
| | xsum / wsum, |
| | ysum / wsum, |
| | (wsum * xslopesum - wslopesum * xsum) / wsum / wsum, |
| | (wsum * yslopesum - wslopesum * ysum) / wsum / wsum |
| | }; |
| | } |
| |
|
| | void BSpline::valueHomogenous( |
| | const double u, |
| | double* xw, |
| | double* yw, |
| | double* w, |
| | double* dxwdu, |
| | double* dywdu, |
| | double* dwdu |
| | ) const |
| | { |
| | |
| | size_t startpole = 0; |
| | for (size_t j = 1; j < mult.size() && *(knots[j]) <= u; ++j) { |
| | startpole += mult[j]; |
| | } |
| | if (!periodic && startpole >= poles.size()) { |
| | startpole = poles.size() - degree - 1; |
| | } |
| |
|
| | auto polexat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].x; |
| | }; |
| | auto poleyat = [&](size_t i) { |
| | return poles[(startpole + i) % poles.size()].y; |
| | }; |
| | auto weightat = [&](size_t i) { |
| | return weights[(startpole + i) % weights.size()]; |
| | }; |
| |
|
| | size_t numpoints = degree + 1; |
| | VEC_D d(numpoints); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *polexat(i) * *weightat(i); |
| | } |
| | *xw = BSpline::splineValue(u, startpole + degree, degree, d, flattenedknots); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *poleyat(i) * *weightat(i); |
| | } |
| | *yw = BSpline::splineValue(u, startpole + degree, degree, d, flattenedknots); |
| | for (size_t i = 0; i < numpoints; ++i) { |
| | d[i] = *weightat(i); |
| | } |
| | *w = BSpline::splineValue(u, startpole + degree, degree, d, flattenedknots); |
| |
|
| | d.resize(numpoints - 1); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*polexat(i) * *weightat(i) - *polexat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | *dxwdu = degree * BSpline::splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*poleyat(i) * *weightat(i) - *poleyat(i - 1) * *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | *dywdu = degree * BSpline::splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| | for (size_t i = 1; i < numpoints; ++i) { |
| | d[i - 1] = (*weightat(i) - *weightat(i - 1)) |
| | / (flattenedknots[startpole + i + degree] - flattenedknots[startpole + i]); |
| | } |
| | *dwdu = degree * BSpline::splineValue(u, startpole + degree, degree - 1, d, flattenedknots); |
| | } |
| |
|
| | int BSpline::PushOwnParams(VEC_pD& pvec) |
| | { |
| | std::size_t cnt = 0; |
| |
|
| | for (const auto& pole : poles) { |
| | pvec.push_back(pole.x); |
| | pvec.push_back(pole.y); |
| | } |
| |
|
| | cnt = cnt + poles.size() * 2; |
| |
|
| | pvec.insert(pvec.end(), weights.begin(), weights.end()); |
| | cnt = cnt + weights.size(); |
| |
|
| | pvec.insert(pvec.end(), knots.begin(), knots.end()); |
| | cnt = cnt + knots.size(); |
| |
|
| | pvec.push_back(start.x); |
| | cnt++; |
| | pvec.push_back(start.y); |
| | cnt++; |
| | pvec.push_back(end.x); |
| | cnt++; |
| | pvec.push_back(end.y); |
| | cnt++; |
| |
|
| | return static_cast<int>(cnt); |
| | } |
| |
|
| | void BSpline::ReconstructOnNewPvec(VEC_pD& pvec, int& cnt) |
| | { |
| | for (auto& pole : poles) { |
| | pole.x = pvec[cnt]; |
| | cnt++; |
| | pole.y = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | for (auto& weight : weights) { |
| | weight = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | for (auto& knot : knots) { |
| | knot = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | start.x = pvec[cnt]; |
| | cnt++; |
| | start.y = pvec[cnt]; |
| | cnt++; |
| | end.x = pvec[cnt]; |
| | cnt++; |
| | end.y = pvec[cnt]; |
| | cnt++; |
| | } |
| |
|
| | BSpline* BSpline::Copy() |
| | { |
| | return new BSpline(*this); |
| | } |
| |
|
| | double BSpline::getLinCombFactor(double x, size_t k, size_t i, unsigned int p) |
| | { |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if (flattenedknots.empty()) { |
| | setupFlattenedKnots(); |
| | } |
| |
|
| | std::vector d(p + 1, 0.0); |
| | |
| | int idxOfPole = static_cast<int>(i) + p - static_cast<int>(k); |
| | if (idxOfPole < 0 || idxOfPole > static_cast<int>(p)) { |
| | return 0.0; |
| | } |
| | d[idxOfPole] = 1.0; |
| |
|
| | for (size_t r = 1; r < p + 1; ++r) { |
| | for (size_t j = p; j > r - 1; --j) { |
| | double alpha = (x - flattenedknots[j + k - p]) |
| | / (flattenedknots[j + 1 + k - r] - flattenedknots[j + k - p]); |
| | d[j] = (1.0 - alpha) * d[j - 1] + alpha * d[j]; |
| | } |
| | } |
| |
|
| | return d[p]; |
| | } |
| |
|
| | double BSpline::splineValue(double x, size_t k, unsigned int p, VEC_D& d, const VEC_D& flatknots) |
| | { |
| | for (size_t r = 1; r < p + 1; ++r) { |
| | for (size_t j = p; j > r - 1; --j) { |
| | double alpha = (x - flatknots[j + k - p]) |
| | / (flatknots[j + 1 + k - r] - flatknots[j + k - p]); |
| | d[j] = (1.0 - alpha) * d[j - 1] + alpha * d[j]; |
| | } |
| | } |
| |
|
| | return p < d.size() ? d[p] : 0.0; |
| | } |
| |
|
| | void BSpline::setupFlattenedKnots() |
| | { |
| | flattenedknots.clear(); |
| |
|
| | for (size_t i = 0; i < knots.size(); ++i) { |
| | flattenedknots.insert(flattenedknots.end(), mult[i], *knots[i]); |
| | } |
| |
|
| | |
| | if (periodic) { |
| | double period = *knots.back() - *knots.front(); |
| | int c = degree + 1 - mult[0]; |
| |
|
| | |
| | flattenedknots.reserve(flattenedknots.size() + 2 * c); |
| |
|
| | |
| | auto frontStart = flattenedknots.end() - mult.back() - c; |
| | auto frontEnd = flattenedknots.end() - mult.back(); |
| | auto backStart = flattenedknots.begin() + mult.front(); |
| | auto backEnd = flattenedknots.begin() + mult.front() + c; |
| |
|
| | |
| | std::vector<double> frontNew(frontStart, frontEnd); |
| | std::vector<double> backNew(backStart, backEnd); |
| |
|
| | flattenedknots.insert(flattenedknots.end(), backNew.begin(), backNew.end()); |
| | flattenedknots.insert(flattenedknots.begin(), frontNew.begin(), frontNew.end()); |
| |
|
| | for (int i = 0; i < c; ++i) { |
| | *(flattenedknots.begin() + i) -= period; |
| | *(flattenedknots.end() - 1 - i) += period; |
| | } |
| | } |
| | } |
| |
|
| | } |
| |
|