summaryrefslogtreecommitdiffstats
path: root/src/toys/conic-5.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/toys/conic-5.cpp')
-rw-r--r--src/toys/conic-5.cpp356
1 files changed, 356 insertions, 0 deletions
diff --git a/src/toys/conic-5.cpp b/src/toys/conic-5.cpp
new file mode 100644
index 0000000..51140c1
--- /dev/null
+++ b/src/toys/conic-5.cpp
@@ -0,0 +1,356 @@
+#include <iostream>
+#include <2geom/path.h>
+#include <2geom/svg-path-parser.h>
+#include <2geom/path-intersection.h>
+#include <2geom/basic-intersection.h>
+#include <2geom/pathvector.h>
+#include <2geom/exception.h>
+#include <2geom/sbasis-geometric.h>
+#include <2geom/path-intersection.h>
+#include <2geom/nearest-time.h>
+#include <2geom/line.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/sbasis-to-bezier.h>
+
+#include <cstdlib>
+#include <map>
+#include <vector>
+#include <algorithm>
+#include <optional>
+
+#include <toys/path-cairo.h>
+#include <toys/toy-framework-2.h>
+#include <2geom/bezier-to-sbasis.h>
+#include <2geom/ord.h>
+
+
+
+#include <2geom/conicsec.h>
+
+using namespace Geom;
+using namespace std;
+
+
+// File: convert.h
+#include <sstream>
+#include <stdexcept>
+
+class BadConversion : public std::runtime_error {
+public:
+ BadConversion(const std::string& s)
+ : std::runtime_error(s)
+ { }
+};
+
+template <typename T>
+inline std::string stringify(T x)
+{
+ std::ostringstream o;
+ if (!(o << x))
+ throw BadConversion("stringify(T)");
+ return o.str();
+}
+
+void draw_hull(cairo_t*cr, RatQuad rq) {
+ cairo_move_to(cr, rq.P[0]);
+ cairo_line_to(cr, rq.P[1]);
+ cairo_line_to(cr, rq.P[2]);
+ cairo_stroke(cr);
+}
+
+
+
+void draw(cairo_t* cr, xAx C, Rect bnd) {
+ if(bnd[1].extent() < 5) return;
+ vector<double> prev_rts;
+ double py = bnd[Y].min();
+ for(int i = 0; i < 100; i++) {
+ double t = i/100.;
+ double y = bnd[Y].valueAt(t);
+ vector<double> rts = C.roots(Point(1, 0), Point(0, y));
+ int top = 0;
+ for(unsigned j = 0; j < rts.size(); j++) {
+ if(bnd[0].contains(rts[j])) {
+ rts[top] = rts[j];
+ top++;
+ }
+ }
+ rts.erase(rts.begin()+top, rts.end());
+
+ if(rts.size() == prev_rts.size()) {
+ for(unsigned j = 0; j < rts.size(); j++) {
+ cairo_move_to(cr, prev_rts[j], py);
+ cairo_line_to(cr, rts[j], y);
+ cairo_stroke(cr);
+ }
+ } else {
+ draw(cr, C, Rect(bnd[X], Interval(py, y)));
+ }
+ prev_rts = rts;
+ py = y;
+ }
+}
+
+template <typename T>
+static T det(T a, T b, T c, T d) {
+ return a*d - b*c;
+}
+
+template <typename T>
+static T det(T M[2][2]) {
+ return M[0][0]*M[1][1] - M[1][0]*M[0][1];
+}
+
+template <typename T>
+static T det3(T M[3][3]) {
+ return ( M[0][0] * det(M[1][1], M[1][2],
+ M[2][1], M[2][2])
+ -M[1][0] * det(M[0][1], M[0][2],
+ M[2][1], M[2][2])
+ +M[2][0] * det(M[0][1], M[0][2],
+ M[1][1], M[1][2]));
+}
+
+double xAx_descr(xAx const & C) {
+ double mC[3][3] = {{C.c[0], (C.c[1])/2, (C.c[3])/2},
+ {(C.c[1])/2, C.c[2], (C.c[4])/2},
+ {(C.c[3])/2, (C.c[4])/2, C.c[5]}};
+
+ return det3(mC);
+}
+
+void draw_ratquad(cairo_t*cr, RatQuad rq, double tol=1e-1) {
+ CubicBezier cb = rq.toCubic();
+ // I tried using the nearest point to 0.5 for the error, but the improvement was negligible
+ if(L2(cb.pointAt(0.5) - rq.pointAt(0.5)) > tol) {
+ RatQuad a, b;
+ rq.split(a, b);
+ draw_ratquad(cr, a, tol);
+ draw_ratquad(cr, b, tol);
+ } else {
+ cairo_curve(cr, cb);
+ //draw_cross(cr, cb.pointAt(0));
+ //draw_cross(cr, cb.pointAt(1));
+ }
+}
+
+
+class Conic5: public Toy {
+ PointSetHandle path_handles;
+ PointHandle oncurve;
+ PointSetHandle cutting_plane;
+ std::vector<Slider> sliders;
+ RectHandle rh;
+
+ void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
+ cairo_set_source_rgba (cr, 0., 0., 0, 1);
+ cairo_set_line_width (cr, 1);
+
+ if(0) {
+ Path path;
+ path = Path(path_handles.pts[0]);
+ D2<SBasis> c = handles_to_sbasis(path_handles.pts.begin(), 2);
+ path.append(c);
+
+ cairo_save(cr);
+ cairo_path(cr, path);
+ cairo_set_source_rgba (cr, 0., 1., 0, 0.3);
+ cairo_set_line_width (cr, 3);
+ cairo_stroke(cr);
+ cairo_restore(cr);
+
+ //double w = exp(sliders[0].value());
+ }
+ Point A = path_handles.pts[0];
+ Point B = path_handles.pts[1];
+ Point C = path_handles.pts[2];
+
+ if(1) {
+ QuadraticBezier qb(A, B, C);
+ //double abt = qb.nearestTime(oncurve.pos);
+ //oncurve.pos = qb.pointAt(abt);
+
+ RatQuad rq = RatQuad::fromPointsTangents(A, B-A, oncurve.pos, C, B -C); //( A, B, C, w);
+
+ cairo_save(cr);
+ cairo_set_source_rgba (cr, 0., 0., 0, 1);
+ cairo_set_line_width (cr, 1);
+ draw_ratquad(cr, rq);
+ //cairo_d2_sb(cr, rq.hermite());
+ cairo_stroke(cr);
+ cairo_restore(cr);
+ }
+
+ if(0) {
+ RatQuad rq = RatQuad::circularArc(A, B, C);
+
+ cairo_save(cr);
+ cairo_set_source_rgba (cr, 0., 0., 0, 1);
+ cairo_set_line_width (cr, 1);
+ RatQuad a, b;
+ rq.split(a,b);
+ cairo_curve(cr, a.toCubic());
+ cairo_curve(cr, b.toCubic());
+ cairo_stroke(cr);
+ cairo_restore(cr);
+ }
+
+ Rect screen_rect(Interval(10, width-10), Interval(10, height-10));
+ Line cutLine(cutting_plane.pts[0], cutting_plane.pts[1]);
+ //double dist;
+ //Point norm = cutLine.normalAndDist(dist);
+
+ const unsigned N = 3;
+ xAx sources[N] = {
+ xAx::fromPoint(A)*(exp(-sliders[0].value())),
+ xAx::fromPoint(B)*(exp(-sliders[1].value())),
+ xAx::fromPoint(C)*(exp(-sliders[2].value()))
+ //xAx::fromLine(Line(A, oncurve.pos))
+ };
+ for(unsigned i = 0; i < N; i++) {
+ //*notify << sources[i] << "\n";
+ }
+ for(unsigned i = 0; i < N; i++) {
+ for(unsigned j = i+1; j < N; j++) {
+ xAx Q = sources[i]-sources[j];
+ *notify << Q << " is a " << Q.categorise() << "\n";
+ }
+ }
+ {
+ cairo_save(cr);
+ cairo_set_source_rgba(cr, 0, 0, 1, 0.5);
+
+ ::draw(cr, (sources[0]-sources[1]), screen_rect);
+ ::draw(cr, (sources[0]-sources[2]), screen_rect);
+ ::draw(cr, (sources[1]-sources[2]), screen_rect);
+ cairo_restore(cr);
+ }
+ {
+ string os;
+ for(unsigned i = 0; i < N; i++) {
+ for(unsigned j = i+1; j < N; j++) {
+ xAx Q = sources[i]-sources[j];
+ Interval iQ = Q.extrema(rh.pos);
+ if(iQ.contains(0)) {
+ os += stringify(iQ) + "\n";
+
+ Q.toCurve(rh.pos);
+ vector<Point> crs = Q.crossings(rh.pos);
+ for(auto & ei : crs) {
+ draw_cross(cr, ei);
+ }
+
+ }
+ }
+ }
+
+ draw_text(cr, rh.pos.midpoint(),
+ os);
+ }
+ if(1) {
+ xAx oxo=sources[0] - sources[2];
+ Timer tm;
+
+ tm.ask_for_timeslice();
+ tm.start();
+
+ std::vector<Point> intrs = intersect(oxo, sources[0] - sources[1]);
+ Timer::Time als_time = tm.lap();
+ *notify << "intersect time = " << als_time << std::endl;
+ for(auto & intr : intrs) {
+ cairo_save(cr);
+ cairo_set_source_rgb(cr, 1, 0,0);
+ draw_cross(cr, intr);
+ cairo_stroke(cr);
+ cairo_restore(cr);
+ }
+
+ std::optional<RatQuad> orq = oxo.toCurve(rh.pos);
+ if(orq) {
+ RatQuad rq = *orq;
+ draw_hull(cr, rq);
+ vector<SBasis> hrq = rq.homogeneous();
+ SBasis vertex_poly = (sources[0] - sources[1]).evaluate_at(hrq[0], hrq[1], hrq[2]);
+ //*notify << "\n0: " << hrq[0];
+ //*notify << "\n1: " << hrq[1];
+ //*notify << "\n2: " << hrq[2];
+ vector<double> rts = roots(vertex_poly);
+ //*notify << "\nvertex poly:" << vertex_poly << '\n';
+ for(unsigned i = 0; i < rts.size(); i++) {
+ draw_circ(cr, Point(rq.pointAt(rts[i])));
+ *notify << "\nrq" << i << ":" << rts[i];
+ }
+
+ cairo_save(cr);
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ RatQuad a, b;
+ rq.split(a,b);
+ cairo_curve(cr, a.toCubic());
+ cairo_curve(cr, b.toCubic());
+ cairo_stroke(cr);
+ cairo_restore(cr);
+ }
+ }
+ if(0) {
+ RatQuad a, b;
+ //rq.split(a,b);
+ //cairo_move_to(cr, rq.toCubic().pointAt(0.5));
+ cairo_line_to(cr, a.P[2]);
+ cairo_stroke(cr);
+
+ cairo_curve(cr, a.toCubic());
+ cairo_curve(cr, b.toCubic());
+
+ }
+ cairo_stroke(cr);
+
+ //*notify << "w = " << w << "; lambda = " << rq.lambda() << "\n";
+ Toy::draw(cr, notify, width, height, save, timer_stream);
+ }
+
+public:
+ Conic5() {
+ handles.push_back(&path_handles);
+ handles.push_back(&rh);
+ rh.pos = Rect(Point(100,100), Point(200,200));
+ rh.show_center_handle = true;
+ handles.push_back(&oncurve);
+ for(int j = 0; j < 3; j++){
+ path_handles.push_back(uniform()*400, 100+ uniform()*300);
+ }
+ oncurve.pos = ((path_handles.pts[0]+path_handles.pts[1]+path_handles.pts[2])/3);
+ handles.push_back(&cutting_plane);
+ for(int j = 0; j < 2; j++){
+ cutting_plane.push_back(uniform()*400, 100+ uniform()*300);
+ }
+ sliders.emplace_back(0.0, 5.0, 0, 0.0, "a");
+ sliders.emplace_back(0.0, 5.0, 0, 0.0, "b");
+ sliders.emplace_back(0.0, 5.0, 0, 0.0, "c");
+ handles.push_back(&(sliders[0]));
+ handles.push_back(&(sliders[1]));
+ handles.push_back(&(sliders[2]));
+ sliders[0].geometry(Point(50, 20), 250);
+ sliders[1].geometry(Point(50, 50), 250);
+ sliders[2].geometry(Point(50, 80), 250);
+ }
+
+ void first_time(int /*argc*/, char**/* argv*/) override {
+
+ }
+};
+
+int main(int argc, char **argv) {
+ init(argc, argv, new Conic5());
+ 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=4:softtabstop=4:fileencoding=utf-8:textwidth=99 :