summaryrefslogtreecommitdiffstats
path: root/src/toys/match-curve.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/toys/match-curve.cpp')
-rw-r--r--src/toys/match-curve.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/src/toys/match-curve.cpp b/src/toys/match-curve.cpp
new file mode 100644
index 0000000..60e81a5
--- /dev/null
+++ b/src/toys/match-curve.cpp
@@ -0,0 +1,162 @@
+#include <2geom/d2.h>
+#include <2geom/sbasis.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/path.h>
+
+#include <toys/path-cairo.h>
+#include <toys/toy-framework-2.h>
+
+#define ZROOTS_TEST 0
+#if ZROOTS_TEST
+#include <2geom/zroots.c>
+#endif
+
+#include <vector>
+using std::vector;
+using namespace Geom;
+
+//#define HAVE_GSL
+
+template <typename T>
+void shift(T &a, T &b, T const &c) {
+ a = b;
+ b = c;
+}
+template <typename T>
+void shift(T &a, T &b, T &c, T const &d) {
+ a = b;
+ b = c;
+ c = d;
+}
+
+extern unsigned total_steps, total_subs;
+
+class MatchCurve: public Toy {
+public:
+ double timer_precision;
+ double units;
+ PointSetHandle psh;
+
+ void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
+ cairo_set_line_width (cr, 1);
+ cairo_set_source_rgb(cr, 0,0,0);
+ std::vector<Geom::Point> trans;
+ trans.resize(psh.size());
+ for(unsigned i = 0; i < psh.size(); i++) {
+ trans[i] = psh.pts[i] - Geom::Point(0, 3*width/4);
+ }
+
+ std::vector<double> solutions;
+
+ D2<SBasis> test_sb = psh.asBezier();
+
+
+ D2<SBasis> B = psh.asBezier();
+ Geom::Path pb;
+ pb.append(B);
+ pb.close(false);
+ cairo_path(cr, pb);
+ cairo_stroke(cr);
+
+ D2<SBasis> m;
+ D2<SBasis> dB = derivative(B);
+ D2<SBasis> ddB = derivative(dB);
+ D2<SBasis> dddB = derivative(ddB);
+
+ Geom::Point pt = B(0);
+ Geom::Point tang = dB(0);
+ Geom::Point dtang = ddB(0);
+ Geom::Point ddtang = dddB(0);
+ for(int dim = 0; dim < 2; dim++) {
+ m[dim] = Linear(pt[dim],pt[dim]+tang[dim]);
+ m[dim] += Linear(0, 1)*Linear(0, 1*dtang[dim])/2;
+ m[dim] += Linear(0, 1)*Linear(0, 1)*Linear(0, ddtang[dim])/6;
+ }
+
+ double lo = 0, hi = 1;
+ double eps = 5;
+ while(hi - lo > 0.0001) {
+ double mid = (hi + lo)/2;
+ //double Bmid = (Bhi + Blo)/2;
+
+ m = truncate(compose(B, Linear(0, mid)), 2);
+ // perform golden section search
+ double best_f = 0, best_x = 1;
+ for(int n = 2; n < 4; n++) {
+ Geom::Point m_pt = m(double(n)/6);
+ double x0 = 0, x3 = 1.; // just a guess!
+ const double R = 0.61803399;
+ const double C = 1 - R;
+ double x1 = C*x0 + R*x3;
+ double x2 = C*x1 + R*x3;
+ double f1 = Geom::distance(m_pt, B(x1));
+ double f2 = Geom::distance(m_pt, B(x2));
+ while(fabs(x3 - x0) > 1e-3*(fabs(x1) + fabs(x2))) {
+ if(f2 < f1) {
+ shift(x0, x1, x2, R*x1 + C*x3);
+ shift(f1, f2, Geom::distance(m_pt, B(x2)));
+ } else {
+ shift(x3, x2, x1, R*x2 + C*x0);
+ shift(f2, f1, Geom::distance(m_pt, B(x2)));
+ }
+ std::cout << x0 << ","
+ << x1 << ","
+ << x2 << ","
+ << x3 << ","
+ << std::endl;
+ }
+ if(f2 < f1) {
+ f1 = f2;
+ x1 = x2;
+ }
+ if(f1 > best_f) {
+ best_f = f1;
+ best_x = x1;
+ }
+ }
+ std::cout << mid << ":" << best_x << "->" << best_f << std::endl;
+ //draw_cross(cr, point_at(B, x1));
+
+ if(best_f > eps) {
+ hi = mid;
+ } else {
+ lo = mid;
+ }
+ }
+ std::cout << std::endl;
+ //draw_cross(cr, point_at(B, hi));
+ draw_circ(cr, m(hi));
+ {
+ Geom::Path pb;
+ pb.append(m);
+ pb.close(false);
+ cairo_path(cr, pb);
+ }
+
+ cairo_stroke(cr);
+ Toy::draw(cr, notify, width, height, save,timer_stream);
+ }
+ MatchCurve() : timer_precision(0.1), units(1e6) // microseconds
+ {
+ handles.push_back(&psh);
+ for(int i = 0; i < 6; i++)
+ psh.push_back(uniform()*400, uniform()*400);
+ }
+};
+
+int main(int argc, char **argv) {
+ init(argc, argv, new MatchCurve());
+
+ return 0;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :