#include <2geom/cairo-path-sink.h> #include <2geom/ellipse.h> #include <2geom/line.h> #include <2geom/polynomial.h> #include using namespace Geom; class CircleIntersect : public Toy { PointSetHandle psh[2]; Ellipse ea, eb; Line l[6]; void intersect() { // This is code is almost the same as in ellipse.cpp. // We use it here to get the lines. double A, B, C, D, E, F; double a, b, c, d, e, f; ea.coefficients(A, E, B, C, D, F); eb.coefficients(a, e, b, c, d, f); double I, J, K, L; I = (-E*E*F + 4*A*B*F + C*D*E - A*D*D - B*C*C) / 4; J = -((E*E - 4*A*B) * f + (2*E*F - C*D) * e + (2*A*D - C*E) * d + (2*B*C - D*E) * c + (C*C - 4*A*F) * b + (D*D - 4*B*F) * a) / 4; K = -((e*e - 4*a*b) * F + (2*e*f - c*d) * E + (2*a*d - c*e) * D + (2*b*c - d*e) * C + (c*c - 4*a*f) * B + (d*d - 4*b*f) * A) / 4; L = (-e*e*f + 4*a*b*f + c*d*e - a*d*d - b*c*c) / 4; std::vector mu = solve_cubic(I, J, K, L); for (unsigned i = 0; i < mu.size(); ++i) { double aa = mu[i] * A + a; double bb = mu[i] * B + b; double cc = mu[i] * C + c; double dd = mu[i] * D + d; double ee = mu[i] * E + e; double ff = mu[i] * F + f; double delta = ee*ee - 4*aa*bb; if (delta < 0) { continue; } if (aa != 0) { bb /= aa; cc /= aa; dd /= aa; ee /= aa; ff /= aa; double s = (ee + std::sqrt(ee*ee - 4*bb)) / 2; double q = ee - s; double alpha = (dd - cc*q) / (s - q); double beta = cc - alpha; l[i*2] = Line(1, q, alpha); l[i*2+1] = Line(1, s, beta); } else if (bb != 0) { cc /= bb; dd /= bb; ee /= bb; ff /= bb; double s = ee; double q = 0; double alpha = cc / ee; double beta = ff * ee / cc; l[i*2] = Line(q, 1, alpha); l[i*2+1] = Line(s, 1, beta); } else { // both aa and bb are zero l[i*2] = Line(ee, 1, dd); l[i*2+1] = Line(0, 1, cc/ee); } } } void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override { Rect all(Point(0,0), Point(width, height)); double r1x = Geom::distance(psh[0].pts[0], psh[0].pts[1]); double r1y = Geom::distance(psh[0].pts[0], psh[0].pts[2]); double rot1 = Geom::atan2(psh[0].pts[1] - psh[0].pts[0]); double r2x = Geom::distance(psh[1].pts[0], psh[1].pts[1]); double r2y = Geom::distance(psh[1].pts[0], psh[1].pts[2]); double rot2 = Geom::atan2(psh[1].pts[1] - psh[1].pts[0]); ea = Ellipse(psh[0].pts[0], Point(r1x, r1y), rot1); eb = Ellipse(psh[1].pts[0], Point(r2x, r2y), rot2); for (auto & i : l) { i = Line(0, 0, 0); } cairo_set_line_width(cr, 1.0); cairo_set_source_rgb(cr, 0, 0, 0); Geom::CairoPathSink cps(cr); cps.feed(ea); cps.feed(eb); cairo_stroke(cr); try { intersect(); std::vector result = ea.intersect(eb); if (!l[0].isDegenerate() && !l[1].isDegenerate()) { cairo_set_source_rgba(cr, 1, 0, 0, 0.2); draw_line(cr, l[0], all); draw_line(cr, l[1], all); cairo_stroke(cr); } if (!l[2].isDegenerate() && !l[3].isDegenerate()) { cairo_set_source_rgba(cr, 0, 1, 0, 0.2); draw_line(cr, l[2], all); draw_line(cr, l[3], all); cairo_stroke(cr); } if (!l[4].isDegenerate() && !l[5].isDegenerate()) { cairo_set_source_rgba(cr, 0, 0, 1, 0.2); draw_line(cr, l[4], all); draw_line(cr, l[5], all); cairo_stroke(cr); } cairo_set_source_rgb(cr, 1, 0, 0); for (auto & i : result) { draw_handle(cr, i.point()); } cairo_stroke(cr); } catch(...) { *notify << "Exception"; } // TODO: draw_handle at intersections Toy::draw(cr, notify, width, height, save,timer_stream); } public: CircleIntersect(){ psh[0].push_back(300,300); psh[0].push_back(450,150); psh[0].push_back(250, 250); psh[1].push_back(350,300); psh[1].push_back(500,500); psh[1].push_back(300, 350); handles.push_back(&psh[0]); handles.push_back(&psh[1]); } }; int main(int argc, char **argv) { init(argc, argv, new CircleIntersect()); 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 :