summaryrefslogtreecommitdiffstats
path: root/src/toys/boolops-toy.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/toys/boolops-toy.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/toys/boolops-toy.cpp b/src/toys/boolops-toy.cpp
new file mode 100644
index 0000000..389fdc3
--- /dev/null
+++ b/src/toys/boolops-toy.cpp
@@ -0,0 +1,242 @@
+#include <2geom/d2.h>
+#include <2geom/intersection-graph.h>
+#include <2geom/path.h>
+#include <2geom/sbasis.h>
+#include <2geom/svg-path-parser.h>
+#include <2geom/transforms.h>
+
+#include <toys/path-cairo.h>
+#include <toys/toy-framework-2.h>
+
+#include <algorithm>
+#include <cstdlib>
+
+using namespace Geom;
+
+class BoolOps : public Toy {
+ PathVector as, bs;
+ Line ah, bh;
+ PointHandle path_handles[4];
+ std::vector<Toggle> togs;
+ bool path_handles_inited;
+
+public:
+ BoolOps()
+ : path_handles_inited(false)
+ {}
+
+ void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override {
+ if (!path_handles_inited) {
+ Rect vp(Point(10,10), Point(width-10, height-10));
+ setup_path_handles(vp);
+ }
+
+ Line aht(path_handles[0].pos, path_handles[1].pos);
+ Line bht(path_handles[2].pos, path_handles[3].pos);
+
+ PathVector ast = as * ah.transformTo(aht);
+ PathVector bst = bs * bh.transformTo(bht);
+
+ Timer tm;
+ tm.start();
+
+ PathIntersectionGraph pig(ast, bst);
+ std::vector<Point> dix, ix, wpoints;
+ ix = pig.intersectionPoints();
+ dix = pig.intersectionPoints(true);
+ wpoints = pig.windingPoints();
+ PathVector result, f_in, f_out;
+
+ if (pig.valid()) {
+ if (togs[0].on && !togs[1].on && !togs[2].on) {
+ result = pig.getAminusB();
+ }
+ if (!togs[0].on && togs[1].on && !togs[2].on) {
+ result = pig.getIntersection();
+ }
+ if (!togs[0].on && !togs[1].on && togs[2].on) {
+ result = pig.getBminusA();
+ }
+ if (togs[0].on && togs[1].on && !togs[2].on) {
+ result = ast;
+ }
+ if (togs[0].on && !togs[1].on && togs[2].on) {
+ result = pig.getXOR();
+ }
+ if (!togs[0].on && togs[1].on && togs[2].on) {
+ result = bst;
+ }
+ if (togs[0].on && togs[1].on && togs[2].on) {
+ result = pig.getUnion();
+ }
+ }
+
+ if (togs[5].on || togs[6].on) {
+ pig.fragments(f_in, f_out);
+ }
+ Timer::Time boolop_time = tm.lap();
+
+ cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
+ cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL);
+ cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
+
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_path(cr, result);
+ cairo_fill(cr);
+
+ cairo_set_line_width(cr, 1);
+ cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
+ cairo_path(cr, ast);
+
+ cairo_stroke(cr);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_path(cr, bst);
+ cairo_stroke(cr);
+
+ if (togs[5].on) {
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ cairo_path(cr, f_in);
+ cairo_stroke(cr);
+ }
+ if (togs[6].on) {
+ cairo_set_source_rgb(cr, 0, 0, 1);
+ cairo_path(cr, f_out);
+ cairo_stroke(cr);
+ }
+
+ //cairo_set_line_width(cr, 1);
+
+ if (togs[7].on) {
+ cairo_set_source_rgb(cr, 0, 1, 1);
+ for (auto & wpoint : wpoints) {
+ draw_handle(cr, wpoint);
+ }
+ cairo_stroke(cr);
+ }
+
+ if (togs[3].on) {
+ cairo_set_source_rgb(cr, 0, 1, 0);
+ for (auto & i : ix) {
+ draw_handle(cr, i);
+ }
+ cairo_stroke(cr);
+ }
+
+ if (togs[4].on) {
+ cairo_set_source_rgb(cr, 1, 0, 0);
+ for (auto & i : dix) {
+ draw_handle(cr, i);
+ }
+ cairo_stroke(cr);
+ }
+
+
+ double x = width - 90, y = height - 40, y2 = height - 80;
+ Point p(x, y), p2(x, y2), dpoint(25,25), xo(25,0);
+ togs[0].bounds = Rect(p, p + dpoint);
+ togs[1].bounds = Rect(p + xo, p + xo + dpoint);
+ togs[2].bounds = Rect(p + 2*xo, p + 2*xo + dpoint);
+
+ togs[3].bounds = Rect(p2 - 2*xo, p2 - 2*xo + dpoint);
+ togs[4].bounds = Rect(p2 - xo, p2 - xo + dpoint);
+ togs[5].bounds = Rect(p2, p2 + dpoint);
+ togs[6].bounds = Rect(p2 + xo, p2 + xo + dpoint);
+ togs[7].bounds = Rect(p2 + 2*xo, p2 + 2*xo + dpoint);
+ draw_toggles(cr, togs);
+
+ *notify << ix.size() << " intersections";
+ if (dix.size() != 0) {
+ *notify << " + " << dix.size() << " defective";
+ }
+ if (pig.valid()) {
+ *notify << "\nboolop time: " << boolop_time << std::endl;
+ } else {
+ *notify << "\nboolop failed, time: " << boolop_time << std::endl;
+ }
+ Toy::draw(cr, notify, width, height, save,timer_stream);
+ }
+
+ void mouse_pressed(GdkEventButton* e) override {
+ toggle_events(togs, e);
+ Toy::mouse_pressed(e);
+ }
+
+ void first_time(int argc, char** argv) override {
+ const char *path_a_name="svgd/winding.svgd";
+ const char *path_b_name="svgd/star.svgd";
+ if(argc > 1)
+ path_a_name = argv[1];
+ if(argc > 2)
+ path_b_name = argv[2];
+
+ as = read_svgd(path_a_name);
+ bs = read_svgd(path_b_name);
+
+ OptRect abox = as.boundsExact();
+ OptRect bbox = bs.boundsExact();
+
+ if (!abox) {
+ std::clog << "Error: path A is empty" << std::endl;
+ }
+ if (!bbox) {
+ std::clog << "Error: path B is empty" << std::endl;
+ }
+ if (!abox || !bbox) {
+ std::exit(1);
+ }
+
+ std::vector<Point> anodes = as.nodes();
+ std::vector<Point> bnodes = bs.nodes();
+
+ typedef std::vector<Point>::iterator Iter;
+ std::pair<Iter, Iter> apts =
+ std::minmax_element(anodes.begin(), anodes.end(), Point::LexLess<Y>());
+ std::pair<Iter, Iter> bpts =
+ std::minmax_element(bnodes.begin(), bnodes.end(), Point::LexLess<Y>());
+
+ ah = Line(*apts.first, *apts.second);
+ bh = Line(*bpts.first, *bpts.second);
+
+ togs.emplace_back("R", true);
+ togs.emplace_back("&", false);
+ togs.emplace_back("B", false);
+
+ togs.emplace_back("X", true);
+ togs.emplace_back("D", true);
+ togs.emplace_back("I", false);
+ togs.emplace_back("O", false);
+ togs.emplace_back("W", false);
+ }
+
+ void setup_path_handles(Rect const &viewport) {
+ Line aht = ah * as.boundsExact()->transformTo(viewport, Aspect(ALIGN_XMID_YMID));
+ Line bht = bh * bs.boundsExact()->transformTo(viewport, Aspect(ALIGN_XMID_YMID));
+
+ path_handles[0] = PointHandle(aht.initialPoint());
+ path_handles[1] = PointHandle(aht.finalPoint());
+ path_handles[2] = PointHandle(bht.initialPoint());
+ path_handles[3] = PointHandle(bht.finalPoint());
+
+ for (auto & path_handle : path_handles) {
+ handles.push_back(&path_handle);
+ }
+ path_handles_inited = true;
+ }
+ //virtual bool should_draw_numbers() {return false;}
+};
+
+int main(int argc, char **argv) {
+ init(argc, argv, new BoolOps());
+ 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 :