void Curve::computeCurvatureAndOrientation () { const_vertex_iterator v = vertices_begin(), vend = vertices_end(), v2, prevV, v0; Vec2d p0, p1, p2; Vec3r p; p = (*v)->point2d(); p0 = Vec2d(p[0], p[1]); prevV = v; ++v; p = (*v)->point2d(); p1 = Vec2d(p[0], p[1]); Vec2d prevDir(p1 - p0); for (; v! = vend; ++v) { v2 = v; ++v2; if (v2 == vend) break; Vec3r p2 = (*v2)->point2d(); Vec2d BA = p0 - p1; Vec2d BC = p2 - p1; real lba = BA.norm(), lbc = BC.norm(); BA.normalizeSafe(); BC.normalizeSafe(); Vec2d normalCurvature = BA + BC; Vec2d dir = Vec2d(BC - BA); Vec2d normal = Vec2d(-dir[1], dir[0]); normal.normalizeSafe(); real curvature = normalCurvature * normal; if (lba + lbc > MY_EPSILON) curvature /= (0.5 * lba + lbc); if (dir.norm() < MY_EPSILON) dir = 0.1 * prevDir; (*v)->setCurvatureFredo(curvature); (*v)->setDirectionFredo(dir); prevV = v; p0 = p1; p1 = p2; prevDir = dir; prevDir.normalize(); } (*v)->setCurvatureFredo((*prevV)->curvatureFredo()); (*v)->setDirectionFredo((*v)->point2d() - (*prevV)->point2d()); v0 = vertices_begin(); v2 = v0; ++v2; (*v0)->setCurvatureFredo((*v2)->curvatureFredo()); (*v0)->setDirectionFredo((*v2)->point2d() - (*v0)->point2d()); //closed curve case one day... // return; //numerical degeneracy verification... we'll see later const_vertex_iterator vLastReliable = vertices_begin(); v = vertices_begin(); p = (*v)->point2d(); p0 = Vec2d(p[0], p[1]); prevV = v; ++v; p = (*v)->point2d(); p1 = Vec2d(p[0], p[1]); bool isReliable = false; if ((p1 - p0).norm > EPS_CURVA) { vLastReliable = v; isReliable = true; } for (; v != vend; ++v) { v2 = v; ++v2; if (v2 == vend) break; Vec3r p2 = (*v2)->point2d(); Vec2d BA = p0 - p1; Vec2d BC = p2 - p1; real lba = BA.norm(), lbc = BC.norm(); if ((lba + lbc) < EPS_CURVA) { isReliable = false; cerr << "/"; } else { if (!isReliable) { //previous points were not reliable const_vertex_iterator vfix = vLastReliable; ++vfix; for (; vfix != v; ++vfix) { (*vfix)->setCurvatureFredo((*v)->curvatureFredo()); (*vfix)->setDirectionFredo((*v)->directionFredo()); } } isReliable = true; vLastReliable = v; } prevV = v; p0 = p1; p1 = p2; } }
static std::vector<Vec2d> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip) { std::vector<Vec2d> points; double dx = M_PI_4; // very coarse spacing to begin with double limit = std::min(2*M_PI, width); for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too x = std::min(x, limit); points.emplace_back(Vec2d(x,f(x, z_sin,z_cos, vertical, flip))); } // now we will check all internal points and in case some are too far from the line connecting its neighbours, // we will add one more point on each side: const double tolerance = .1; for (unsigned int i=1;i<points.size()-1;++i) { auto& lp = points[i-1]; // left point auto& tp = points[i]; // this point Vec2d lrv = tp - lp; auto& rp = points[i+1]; // right point // calculate distance of the point to the line: double dist_mm = unscale<double>(scaleFactor) * std::abs(cross2(rp, lp) - cross2(rp - lp, tp)) / lrv.norm(); if (dist_mm > tolerance) { // if the difference from straight line is more than this double x = 0.5f * (points[i-1](0) + points[i](0)); points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); x = 0.5f * (points[i+1](0) + points[i](0)); points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip))); // we added the points to the end, but need them all in order std::sort(points.begin(), points.end(), [](const Vec2d &lhs, const Vec2d &rhs){ return lhs < rhs; }); // decrement i so we also check the first newly added point --i; } } return points; }