diff options
Diffstat (limited to '')
-rw-r--r-- | src/toys/boolops-toy.cpp | 242 |
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 : |