/* * This file is part of libfmr * * File: Curve.cpp * Author: Florian Heinz * * Created on September 14, 2016, 3:07 PM //paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}] //[TOC] [\tableofcontents] [1] Class Curve [TOC] 1 Overview The abstract class Curve represents a single curve. Implemented curves: - Seg - Trochoid - Ravdoid */ #include "fmr_Curve.h" using namespace fmr; /* 2 ~addIntersection~ Define an intersection point on this curve. ~t1~ is the intersection time on this curve, ~t2~ is the time on the peer ~curve~. Multiple curves can join at one intersection time. */ void Curve::addIntersection(double t1, double t2, Curve *curve) { is[t1].push_back(std::pair(t2, curve)); } /* 3 ~getAdjacentCurves~ Returns a vector of all curves, which have an intersection point with this curve. */ std::vector Curve::getAdjacentCurves() { std::vector ret; std::map > >::iterator it = is.begin(); while (it != is.end()) { std::vector >::iterator cit = it->second.begin(); while (cit != (it->second.end())) { ret.push_back(cit->second); cit++; } it++; } return ret; } /* 4 ~getAdjacentIntersectionTimes~ Return the times of the previous and next intersection on this curve relative to ~t~. ~t~ may be an intersection time itself, it is not taken into account in that case. */ std::pair Curve::getAdjacentIntersectionTimes(double t) { bool found = false; double tprev = nan(""), tnext = nan(""); std::map > >::iterator it; for (it = is.begin(); it != is.end(); it++) { double tmp = it->first; if (tmp >= t) { if (tmp > t) tnext = tmp; found = true; break; } tprev = tmp; } it++; if (found && it != is.end() && std::isnan(tnext)) { tnext = it->first; } if (!std::isnan(tprev) && !valid((t + tprev) / 2)) tprev = nan(""); if (!std::isnan(tnext) && !valid((t + tnext) / 2)) tnext = nan(""); return std::pair(tprev, tnext); } #define DELTA 0.0000001 /* 5 ~getAngle~ Return the angle of this curve at time ~t~. This is approximated by calculating the angle between the point at time ~t~ and a point a small step further. ~fromearlier~ specifies the direction. */ double Curve::getAngle(double t, bool fromearlier) { Point p1, p2; if (fromearlier) { p1 = project(t - DELTA); p2 = project(t); } else { p1 = project(t + DELTA); p2 = project(t); } double a = Seg(p1, p2).getAngle(); return a; } /* 6 ~getAngle~ Return the angle of this curve in the point at time ~t1~ in direction ~t2~ similar as in 5. */ double Curve::getAngle(double t1, double t2) { double delta = t2 > t1 ? DELTA : -DELTA; Point p1 = project(t1); Point p2 = project(t1 + delta); double a = Seg(p1, p2).getAngle(); return a; } /* 7 ~getDeltaAngleCW~ Calculate the (clockwise) delta angle between two angles. */ static double getDeltaAngleCW(double a1, double a2) { double ret = a1 + M_PI - a2; if (ret < 0) { ret += 2*M_PI; } else if (ret > 2*M_PI) { ret -= 2*M_PI; } return ret; } /* 8 ~getNext~ Get next curve from the curve segment defined by this curve between times ~t1~ and ~t2~. This is the curve segment on an intersecting curve proceeding with the lowest angle. The function is used to calculate the border of the traversed area. */ std::pair > Curve::getNext(double t1, double t2) { double a1 = getAngle(t2, (bool) (t1 < t2)); // Angle of this curve double bestangle = nan(""); std::pair > bestpeer; bestpeer.first = nan(""); // No curve found std::vector > peers = is[t2]; // std::cerr << this->ToString() << ", Peers: " << peers.size() << std::endl; for (int i = 0; i < peers.size(); i++) { // iterate all intersecting curves std::pair peer = peers[i]; // std::cerr << "Candidate: " << peer.second->ToString() << std::endl; std::pair tts = peer.second->getAdjacentIntersectionTimes(peer.first); for (int j = 0; j < 2; j++) { // Calculate the angle in both directions double tt = (j == 0) ? tts.first : tts.second; if (std::isnan(tt)) continue; double a2 = peer.second->getAngle(peer.first, tt); // Angle on peer double a = getDeltaAngleCW(a1, a2); // Angle between two curve segs // std::cerr << "Angles: " << a1 << ", " << a2 << ", " << a << std::endl; if (a < 0.00001) // Too small angle, probably a numeric error continue; if (std::isnan(bestangle) || a < bestangle) { // best match bestangle = a; bestpeer = std::pair > (tt, peer); } } } // std::cerr << std::endl; return bestpeer; }