summaryrefslogtreecommitdiffstats
path: root/src/toys/ellipse-intersect-toy.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 11:57:42 +0000
commit61f3ab8f23f4c924d455757bf3e65f8487521b5a (patch)
tree885599a36a308f422af98616bc733a0494fe149a /src/toys/ellipse-intersect-toy.cpp
parentInitial commit. (diff)
downloadlib2geom-upstream.tar.xz
lib2geom-upstream.zip
Adding upstream version 1.3.upstream/1.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/toys/ellipse-intersect-toy.cpp')
-rw-r--r--src/toys/ellipse-intersect-toy.cpp158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/toys/ellipse-intersect-toy.cpp b/src/toys/ellipse-intersect-toy.cpp
new file mode 100644
index 0000000..3d65baa
--- /dev/null
+++ b/src/toys/ellipse-intersect-toy.cpp
@@ -0,0 +1,158 @@
+#include <2geom/cairo-path-sink.h>
+#include <2geom/ellipse.h>
+#include <2geom/line.h>
+#include <2geom/polynomial.h>
+#include <toys/toy-framework-2.h>
+
+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<double> 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<ShapeIntersection> 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 :