summaryrefslogtreecommitdiffstats
path: root/src/toys/point-curve-nearest-time.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/toys/point-curve-nearest-time.cpp')
-rw-r--r--src/toys/point-curve-nearest-time.cpp397
1 files changed, 397 insertions, 0 deletions
diff --git a/src/toys/point-curve-nearest-time.cpp b/src/toys/point-curve-nearest-time.cpp
new file mode 100644
index 0000000..0067920
--- /dev/null
+++ b/src/toys/point-curve-nearest-time.cpp
@@ -0,0 +1,397 @@
+/*
+ * point-curve nearest point routines testing
+ *
+ * Authors:
+ * Marco Cecchetti <mrcekets at gmail.com>
+ *
+ * Copyright 2008 authors
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ */
+
+#include <2geom/d2.h>
+#include <2geom/sbasis.h>
+#include <2geom/path.h>
+#include <2geom/curves.h>
+#include <2geom/angle.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/piecewise.h>
+
+#include <2geom/svg-path-parser.h>
+
+#include <toys/path-cairo.h>
+#include <toys/toy-framework-2.h>
+
+#include <2geom/transforms.h>
+#include <2geom/pathvector.h>
+
+
+#include <algorithm>
+
+using namespace Geom;
+
+std::ostream&
+operator<< (std::ostream &out, PathVectorTime const &pvp)
+{
+ return out << pvp.path_index << "." << pvp.curve_index << "." << pvp.t;
+}
+
+class NearestPoints : public Toy
+{
+ enum menu_item_t
+ {
+ FIRST_ITEM = 1,
+ LINE_SEGMENT = FIRST_ITEM,
+ ELLIPTICAL_ARC,
+ SBASIS_CURVE,
+ PIECEWISE,
+ PATH,
+ PATH_SVGD,
+ TOTAL_ITEMS
+ };
+
+ static const char* menu_items[TOTAL_ITEMS];
+
+private:
+ PathVector paths_b;
+ void draw( cairo_t *cr, std::ostringstream *notify,
+ int width, int height, bool save, std::ostringstream *timer_stream) override
+ {
+
+ Point p = ph.pos;
+ Point np = p;
+ std::vector<Point> nps;
+
+ cairo_set_line_width (cr, 0.3);
+ cairo_set_source_rgb(cr, 0,0,0);
+ switch ( choice )
+ {
+ case '1':
+ {
+ LineSegment seg(psh.pts[0], psh.pts[1]);
+ cairo_move_to(cr, psh.pts[0]);
+ cairo_curve(cr, seg);
+ double t = seg.nearestTime(p);
+ np = seg.pointAt(t);
+ if ( toggles[0].on )
+ {
+ nps.push_back(np);
+ }
+ break;
+ }
+ case '2':
+ {
+ EllipticalArc earc;
+ bool earc_constraints_satisfied = true;
+ try
+ {
+ earc.set(psh.pts[0], 200, 150, 0, true, true, psh.pts[1]);
+ }
+ catch( RangeError e )
+ {
+ earc_constraints_satisfied = false;
+ }
+ if ( earc_constraints_satisfied )
+ {
+ cairo_d2_sb(cr, earc.toSBasis());
+ if ( toggles[0].on )
+ {
+ std::vector<double> t = earc.allNearestTimes(p);
+ for (double i : t)
+ nps.push_back(earc.pointAt(i));
+ }
+ else
+ {
+ double t = earc.nearestTime(p);
+ np = earc.pointAt(t);
+ }
+ }
+ break;
+ }
+ case '3':
+ {
+ D2<SBasis> A = psh.asBezier();
+ cairo_d2_sb(cr, A);
+ if ( toggles[0].on )
+ {
+ std::vector<double> t = Geom::all_nearest_times(p, A);
+ for (double i : t)
+ nps.push_back(A(i));
+ }
+ else
+ {
+ double t = nearest_time(p, A);
+ np = A(t);
+ }
+ break;
+ }
+ case '4':
+ {
+ D2<SBasis> A = handles_to_sbasis(psh.pts.begin(), 3);
+ D2<SBasis> B = handles_to_sbasis(psh.pts.begin() + 3, 3);
+ D2<SBasis> C = handles_to_sbasis(psh.pts.begin() + 6, 3);
+ D2<SBasis> D = handles_to_sbasis(psh.pts.begin() + 9, 3);
+ cairo_d2_sb(cr, A);
+ cairo_d2_sb(cr, B);
+ cairo_d2_sb(cr, C);
+ cairo_d2_sb(cr, D);
+ Piecewise< D2<SBasis> > pwc;
+ pwc.push_cut(0);
+ pwc.push_seg(A);
+ pwc.push_cut(0.25);
+ pwc.push_seg(B);
+ pwc.push_cut(0.50);
+ pwc.push_seg(C);
+ pwc.push_cut(0.75);
+ pwc.push_seg(D);
+ pwc.push_cut(1);
+ if ( toggles[0].on )
+ {
+ std::vector<double> t = Geom::all_nearest_times(p, pwc);
+ for (double i : t)
+ nps.push_back(pwc(i));
+ }
+ else
+ {
+ double t = Geom::nearest_time(p, pwc);
+ np = pwc(t);
+ }
+ break;
+ }
+ case '5':
+ {
+ closed_toggle = true;
+ BezierCurveN<3> A(psh.pts[0], psh.pts[1], psh.pts[2], psh.pts[3]);
+ BezierCurveN<2> B(psh.pts[3], psh.pts[4], psh.pts[5]);
+ BezierCurveN<3> C(psh.pts[5], psh.pts[6], psh.pts[7], psh.pts[8]);
+ Path path;
+ path.append(A);
+ path.append(B);
+ path.append(C);
+ EllipticalArc D;
+ bool earc_constraints_satisfied = true;
+ try
+ {
+ D.set(psh.pts[8], 160, 80, 0, true, true, psh.pts[9]);
+ }
+ catch( RangeError e )
+ {
+ earc_constraints_satisfied = false;
+ }
+ if ( earc_constraints_satisfied ) path.append(D);
+ if ( toggles[1].on ) path.close(true);
+
+ cairo_path(cr, path);
+
+ if ( toggles[0].on )
+ {
+ std::vector<double> t = path.allNearestTimes(p);
+ for (double i : t)
+ nps.push_back(path.pointAt(i));
+ }
+ else
+ {
+ PathTime pt = path.nearestTime(p);
+ np = path.pointAt(pt);
+ }
+ break;
+ }
+ case '6':
+ {
+ closed_toggle = true;
+ PathVector pathv = paths_b*Translate(psh.pts[0]-paths_b[0][0].initialPoint());
+ //std::cout << pathv.size() << std::endl;
+ OptRect optRect = bounds_fast(pathv);
+
+ cairo_rectangle(cr, *optRect);
+ cairo_stroke(cr);
+
+ cairo_path(cr, pathv);
+
+ if ( toggles[0].on )
+ {
+ std::vector<PathVectorTime> t = pathv.allNearestTimes(p);
+ for (auto & i : t)
+ nps.push_back(pathv.pointAt(i));
+ }
+ else
+ {
+ //std::optional<PathVectorTime>
+ double s = 0, e = 1;
+ draw_cross(cr, pathv[0].pointAt(s));
+ draw_cross(cr, pathv[0].pointAt(e));
+ double t = pathv[0][0].nearestTime(p, 0, 1);
+ if(t) {
+ *notify << p+psh.pts[0] << std::endl;
+ *notify << t << std::endl;
+ np = pathv[0].pointAt(t);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ *notify << std::endl;
+ for (int i = FIRST_ITEM; i < TOTAL_ITEMS; ++i)
+ {
+ *notify << " " << i << " - " << menu_items[i] << std::endl;
+ }
+ Toy::draw(cr, notify, width, height, save,timer_stream);
+ return;
+ }
+ }
+
+ if ( toggles[0].on )
+ {
+ for (auto & np : nps)
+ {
+ cairo_move_to(cr, p);
+ cairo_line_to(cr, np);
+ }
+ }
+ else
+ {
+ cairo_move_to(cr, p);
+ cairo_line_to(cr, np);
+ }
+ cairo_stroke(cr);
+
+ toggles[0].bounds = Rect( Point(10, height - 50), Point(10, height - 50) + Point(80,25) );
+ toggles[0].draw(cr);
+ if ( closed_toggle )
+ {
+ toggles[1].bounds = Rect( Point(100, height - 50), Point(100, height - 50) + Point(80,25) );
+ toggles[1].draw(cr);
+ closed_toggle = false;
+ }
+
+ Toy::draw(cr, notify, width, height, save,timer_stream);
+ }
+
+ void key_hit(GdkEventKey *e) override
+ {
+ choice = e->keyval;
+ switch ( choice )
+ {
+ case '1':
+ total_handles = 2;
+ break;
+ case '2':
+ total_handles = 2;
+ break;
+ case '3':
+ total_handles = 6;
+ break;
+ case '4':
+ total_handles = 13;
+ break;
+ case '5':
+ total_handles = 10;
+ break;
+ case '6':
+ total_handles = 1;
+ break;
+ default:
+ total_handles = 0;
+ }
+ psh.pts.clear();
+ psh.push_back( 262.6037,35.824151);
+ psh.pts[0] += Point(300,300);
+ psh.push_back(0,0);
+ psh.pts[1] += psh.pts[0];
+ psh.push_back(-92.64892,-187.405851);
+ psh.pts[2] += psh.pts[0];
+ psh.push_back(30,-149.999981);
+ psh.pts[3] += psh.pts[0];
+ for ( unsigned int i = 0; i < total_handles; ++i )
+ {
+ psh.push_back(uniform()*400, uniform()*400);
+ }
+ ph.pos = Point(uniform()*400, uniform()*400);
+ redraw();
+ }
+
+ void mouse_pressed(GdkEventButton* e) override
+ {
+ toggle_events(toggles, e);
+ Toy::mouse_pressed(e);
+ }
+
+public:
+ void first_time(int argc, char** argv) override {
+ const char *path_b_name="star.svgd";
+ if(argc > 1)
+ path_b_name = argv[1];
+ paths_b = read_svgd(path_b_name);
+ }
+ NearestPoints()
+ : total_handles(0), choice('0'), closed_toggle(false)
+ {
+ handles.push_back(&psh);
+ handles.push_back(&ph);
+ ph.pos = Point(uniform()*400, uniform()*400);
+ toggles.emplace_back("ALL NP", false );
+ toggles.emplace_back("CLOSED", false );
+ }
+
+private:
+ PointSetHandle psh;
+ PointHandle ph;
+ std::vector<Toggle> toggles;
+ unsigned int total_handles;
+ char choice;
+ bool closed_toggle;
+};
+
+const char* NearestPoints::menu_items[] =
+{
+ "",
+ "LineSegment",
+ "EllipticalArc",
+ "SBasisCurve",
+ "Piecewise",
+ "Path",
+ "Path from SVGD"
+};
+
+
+
+int main(int argc, char **argv)
+{
+ init( argc, argv, new NearestPoints() );
+ 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 :