Skip to content

Commit

Permalink
Merge pull request #7 from ejmahler/arc-length-inverse
Browse files Browse the repository at this point in the history
Fixed #6 -- Added a feature to solve for desired arc lengths
  • Loading branch information
ejmahler authored Jan 21, 2017
2 parents 52e16d6 + 0fb20e3 commit f0e21e1
Show file tree
Hide file tree
Showing 31 changed files with 1,107 additions and 750 deletions.
13 changes: 9 additions & 4 deletions SplineDemo.pro
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ TEMPLATE = app
CONFIG += c++14

#on mac we want to look for boost in homebrew folder
windows:INCLUDEPATH+= "C:\Boost\boost_1_60_0"
macx:INCLUDEPATH += /usr/local/Cellar/boost/1.59.0/include

#on windows we need to manually add opengl because ???
Expand Down Expand Up @@ -35,7 +36,6 @@ HEADERS += \
spline_library/utils/linearalgebra.h \
spline_library/utils/nanoflann.hpp \
spline_library/utils/splinesample_adaptor.h \
spline_library/utils/spline_setup.h \
spline_library/basis/generic_b_spline.h \
spline_library/basis/looping_generic_b_spline.h \
spline_library/basis/generic_b_spline_common.h \
Expand All @@ -50,7 +50,9 @@ HEADERS += \
spline_library/hermite/cubic/uniform_cr_spline_common.h \
spline_library/hermite/cubic/looping_uniform_cr_spline.h \
spline_library/utils/calculus.h \
spline_library/vector.h
spline_library/vector.h \
spline_library/utils/spline_common.h \
spline_library/arclength.h

FORMS += \
demo/settingswidget.ui \
Expand All @@ -65,14 +67,17 @@ test {
test/testcalculus.h \
test/testvector.h \
test/testspline.h \
test/testlinalg.h
test/testlinalg.h \
test/testarclength.h \
test/common.h

SOURCES += \
test/test_main.cpp \
test/testcalculus.cpp \
test/testvector.cpp \
test/testspline.cpp \
test/testlinalg.cpp
test/testlinalg.cpp \
test/testarclength.cpp
} else {
SOURCES += demo/main.cpp
}
Expand Down
111 changes: 63 additions & 48 deletions demo/benchmarker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
#include <QVector3D>
#include <QTime>

#include "spline_library/basis/uniform_cubic_bspline.h"
#include "spline_library/arclength.h"
#include "spline_library/basis/generic_b_spline.h"
#include "spline_library/hermite/cubic/uniform_cr_spline.h"
#include "spline_library/hermite/cubic/cubic_hermite_spline.h"
#include "spline_library/natural/natural_spline.h"

#include <boost/math/tools/roots.hpp>

Benchmarker::Benchmarker(QObject *parent)
:QObject(parent), bigDistribution(0, 1000), smallDistribution(0,1), smallVarianceDistribution(4, 10)
:QObject(parent), repeats(100)
{

}
Expand All @@ -21,11 +24,38 @@ QMap<QString, float> Benchmarker::runBenchmark(void)
{
canceled = false;

auto randomGenerator = std::bind(&Benchmarker::randomPoints2D_Uniform, this, std::placeholders::_1);
//create a distribution of random numbers, and a parameterles function to generate them
std::uniform_real_distribution<FloatingT> distribution(10,15);
auto randomSource = [this, &distribution]() {
return distribution(this->gen);
};

//create the functions used to generate the splines
auto crSpline = [this, randomSource](size_t size) {
auto points = randomPoints_SmallVariance<VectorT, D, FloatingT>(randomSource, size);
SplinePtr result = std::make_unique<UniformCRSpline<VectorT,FloatingT>>(points);
return result;
};

auto genericBSpline = [this, randomSource](size_t size) {
auto points = randomPoints_SmallVariance<VectorT, D, FloatingT>(randomSource, size);
SplinePtr result = std::make_unique<GenericBSpline<VectorT,FloatingT>>(points, 7);
return result;
};

auto natural = [this, randomSource](size_t size) {
auto points = randomPoints_SmallVariance<VectorT, D, FloatingT>(randomSource, size);
SplinePtr result = std::make_unique<NaturalSpline<VectorT,FloatingT>>(points, true, 0.5f);
return result;
};

QMap<QString, float> results;
results["uniform_cr[100]"] = timeFunction(&Benchmarker::testPrecision, "Testing random precision", 100, 1000, 100,randomGenerator);
results["uniform_cr[1000]"] = timeFunction(&Benchmarker::testPrecision, "Testing random precision", 100, 1000, 1000,randomGenerator);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, crSpline, "FAST: uniform_cr[10]", 10000, 12);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, crSpline, "FAST: uniform_cr[1000]", 1000, 1002);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, genericBSpline, "FAST: bspline[10]", 1000, 16);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, genericBSpline, "FAST: bspline[1000]", 100, 1006);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, natural, "FAST: natural[10]", 10000, 10);
timeSplineMemberFunction(results, &Benchmarker::testSolveArcLength, natural, "FAST: natural[1000]", 1000, 1000);

return results;
}
Expand All @@ -35,59 +65,44 @@ void Benchmarker::cancel(void)
canceled = true;
}

void Benchmarker::testPrecision(QString message, int repeat, int queries, size_t size, std::function<std::vector<VectorT> (size_t)> pointGenerator)
{
gen.seed(10);
void Benchmarker::timeSplineMemberFunction(
QMap<QString, float>& results,
void(Benchmarker::*testFunction)(QString, int, const Spline<VectorT, FloatingT>&) ,
std::function<SplinePtr(size_t)> splineFunction,
QString message, int queries, size_t size) {

emit setProgressText(message + QString(", size ") + QString::number(size));
emit setProgressRange(0, repeat);
emit setProgressText(message);
emit setProgressRange(0, repeats);

for(int i = 0; i < repeat; i++)
{
emit setProgressValue(i);
if(canceled)
return;
int totalElapsed = 0;
gen.seed(10);
QTime t;

UniformCRSpline<VectorT, double> s(pointGenerator(size));
for(int i = 0; i < repeats; i++) {
if(canceled) return;

double max = s.getMaxT();
for(int q = 0; q < queries; q++)
{
double a = randomFloat(max);
double b = randomFloat(max);
emit setProgressValue(i);
auto spline = splineFunction(size);

s.arcLength(a, b);
}
t.start();
(this->*testFunction)(message, queries, *spline.get());
totalElapsed += t.elapsed();
}
emit setProgressValue(repeat);
}


emit setProgressValue(repeats);


std::vector<VectorT> Benchmarker::randomPoints2D_Uniform(size_t size)
{
std::vector<VectorT> result(size);
for(size_t s = 0; s < size; s++)
{
result[s] = VectorT({bigDistribution(gen), bigDistribution(gen)});
}
return result;
results[message] = 1000 * float(totalElapsed) / (repeats * queries);
}

std::vector<VectorT> Benchmarker::randomPoints2D_SmallVariance(size_t size)
void Benchmarker::testSolveArcLength(QString message, int queries, const Spline<VectorT, FloatingT> &spline)
{
std::vector<VectorT> result(size);
result[0] = VectorT({smallVarianceDistribution(gen), smallVarianceDistribution(gen)});
for(size_t s = 1; s < size; s++)
std::uniform_real_distribution<FloatingT> lengthDist(1, spline.totalLength()/2);

for(int q = 0; q < queries; q++)
{
result[s] = result[s - 1] + VectorT({smallVarianceDistribution(gen), smallVarianceDistribution(gen)});
}
return result;
}
//set up the test
FloatingT desired = lengthDist(gen);

double Benchmarker::randomFloat(double max)
{
return smallDistribution(gen) * max;
ArcLength::partition(spline, desired);
}
}

66 changes: 49 additions & 17 deletions demo/benchmarker.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
#include <vector>
#include <random>
#include <functional>
#include <memory>

#include "spline_library/vector.h"
#include "spline_library/spline.h"

typedef Vector<2, double> VectorT;
const size_t D = 2;
typedef float FloatingT;
typedef Vector<D, FloatingT> VectorT;
typedef std::unique_ptr<Spline<VectorT, FloatingT>> SplinePtr;

class Benchmarker : public QObject
{
Expand All @@ -29,30 +34,57 @@ public slots:
void cancel(void);

private:
void timeSplineMemberFunction(
QMap<QString, float>& results,
void(Benchmarker::*testFunction)(QString, int, const Spline<VectorT, FloatingT>&),
std::function<SplinePtr(size_t)> splineFunction,
QString message, int queries, size_t size);

//**********
//all of these functions can change based on whatever you want - i just needed a common place to put performance comparisons

void testPrecision(QString message, int repeat, int queries, size_t size, std::function<std::vector<VectorT> (size_t)> pointGenerator);
void testSolveArcLength(QString message, int queries, const Spline<VectorT, FloatingT> &spline);
void testNaiveSolve(QString message, int queries, const Spline<VectorT, FloatingT> &spline);
void controlGroup(QString message, int queries, const Spline<VectorT, FloatingT> &spline);

private://support stuff

std::vector<VectorT> randomPoints2D_Uniform(size_t size);
std::vector<VectorT> randomPoints2D_SmallVariance(size_t size);
double randomFloat(double max);

template <class Function, typename... Args>
float timeFunction(Function f, Args&&... a) {
QTime t;
t.start();
(this->*f)(std::forward<Args>(a)...);
int elapsedMilli = t.elapsed();
return float(elapsedMilli) / 1000.0;
template<class InterpolationType, size_t dimension, typename floating_t, class RandomSource>
static InterpolationType makeRandomPoint(RandomSource randomSource)
{
std::array<floating_t, dimension> result{};

for(size_t i = 0; i < dimension; i++) {
result[i] = randomSource();
}

return result;
}

template<class InterpolationType, size_t dimension, typename floating_t, class RandomSource>
static std::vector<InterpolationType> randomPoints_Uniform(RandomSource randomSource, size_t size)
{
std::vector<InterpolationType> result(size);
for(size_t i = 0; i < size; i++)
{
result[i] = makeRandomPoint<InterpolationType, dimension, floating_t>(randomSource);
}
return result;
}

template<class InterpolationType, size_t dimension, typename floating_t, class RandomSource>
static std::vector<InterpolationType> randomPoints_SmallVariance(RandomSource randomSource, size_t size)
{
std::vector<InterpolationType> result(size);
result[0] = makeRandomPoint<InterpolationType, dimension, floating_t>(randomSource);
for(size_t i = 1; i < size; i++)
{
result[i] = result[i - 1] + makeRandomPoint<InterpolationType, dimension, floating_t>(randomSource);
}
return result;
}

private: //data
std::minstd_rand gen;
std::uniform_real_distribution<double> bigDistribution;
std::uniform_real_distribution<double> smallDistribution;
std::uniform_real_distribution<double> smallVarianceDistribution;
bool canceled;
int repeats;
};
2 changes: 1 addition & 1 deletion demo/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ void MainWindow::runBenchmark(void)
auto result = future.result();
for(auto it = result.cbegin(); it != result.cend(); it++)
{
resultText += QString("%1: %2s\n").arg(it.key(), QString::number(it.value(), 'f', 2));
resultText += QString("%1: %2ns\n").arg(it.key(), QString::number(it.value(), 'f', 2));
}


Expand Down
Loading

0 comments on commit f0e21e1

Please sign in to comment.