| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #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; |
| } |
| } |
| } |
|
|
| } |
|
|