#include #include #include <2geom/svg-path-parser.h> #include <2geom/utils.h> #include #include <2geom/crossing.h> #include <2geom/path-intersection.h> #include <2geom/transforms.h> #include <2geom/sbasis-geometric.h> #include <2geom/d2.h> #include <2geom/sbasis.h> #include <2geom/pathvector.h> using namespace Geom; struct EndPoint { public: Point point, norm; double time; EndPoint() : time(0) { } EndPoint(Point p, Point n, double t) : point(p), norm(n), time(t) { } }; struct Edge { public: EndPoint from, to; int ix; bool cw; Edge() { } Edge(EndPoint f, EndPoint t, int i, bool c) : from(f), to(t), ix(i), cw(c) { } bool operator==(Edge const &other) { return from.time == other.from.time && to.time == other.to.time; } }; typedef std::vector Edges; Edges edges(Path const &p, Crossings const &cr, unsigned ix) { Edges ret = Edges(); EndPoint prev; for(unsigned i = 0; i <= cr.size(); i++) { double t = cr[i == cr.size() ? 0 : i].getTime(ix); Point pnt = p.pointAt(t); Point normal = p.pointAt(t+0.01) - pnt; normal.normalize(); std::cout << pnt << "\n"; EndPoint cur(pnt, normal, t); if(i == 0) { prev = cur; continue; } ret.push_back(Edge(prev, cur, ix, false)); ret.push_back(Edge(prev, cur, ix, true)); prev = cur; } return ret; } template void append(std::vector &vec, std::vector const &other) { vec.insert(vec.end(),other.begin(), other.end()); } Edges edges(PathVector const &ps, CrossingSet const &crs) { Edges ret = Edges(); for(unsigned i = 0; i < crs.size(); i++) { Edges temp = edges(ps[i], crs[i], i); append(ret, temp); } return ret; } PathVector edges_to_paths(Edges const &es, PathVector const &ps) { PathVector ret; for(const auto & e : es) { ret.push_back(ps[e.ix].portion(e.from.time, e.to.time)); } return ret; } void draw_cell(cairo_t *cr, Edges const &es, PathVector const &ps) { cairo_set_source_rgba(cr, uniform(), uniform(), uniform(), 0.5); cairo_set_line_width(cr, uniform() * 10); PathVector paths = edges_to_paths(es, ps); Piecewise > pw = paths_to_pw(paths); double area; Point centre; Geom::centroid(pw, centre, area); cairo_path(cr, paths); //* (Translate(-centre) * Scale(0.2) * Translate(centre*2))); cairo_stroke(cr); } //Only works for normal double ang(Point n1, Point n2) { return (dot(n1, n2)+1) * (cross(n1, n2) < 0 ? -1 : 1); } template void remove(std::vector &vec, T const &val) { for (typename std::vector::iterator it = vec.begin(); it != vec.end(); ++it) { if(*it == val) { vec.erase(it); return; } } } std::vector cells(cairo_t */*cr*/, PathVector const &ps) { CrossingSet crs = crossings_among(ps); Edges es = edges(ps, crs); std::vector ret = std::vector(); while(!es.empty()) { std::cout << "hello!\n"; Edge start = es.front(); Path p = Path(); Edge cur = start; bool rev = false; Edges cell = Edges(); do { std::cout << rev << " " << cur.from.time << ", " << cur.to.time << "\n"; double a = 0; Edge was = cur; EndPoint curpnt = rev ? cur.from : cur.to; Point norm = rev ? -curpnt.norm : curpnt.norm; //Point to = curpnt.point + norm *20; //std::cout << norm; for(auto & e : es) { if(e == was || e.cw != start.cw) continue; if((!are_near(curpnt.time, e.from.time)) && are_near(curpnt.point, e.from.point, 0.1)) { double v = ang(norm, e.from.norm); //draw_line_seg(cr, curpnt.point, to); //draw_line_seg(cr, to, es[i].from.point + es[i].from.norm*30); //std::cout << v << "\n"; if(start.cw ? v < a : v > a ) { a = v; cur = e; rev = false; } } if((!are_near(curpnt.time, e.to.time)) && are_near(curpnt.point, e.to.point, 0.1)) { double v = ang(norm, -e.to.norm); if(start.cw ? v < a : v > a) { a = v; cur = e; rev = true; } } } cell.push_back(cur); remove(es, cur); if(cur == was) break; } while(!(cur == start)); if(are_near(start.to.point, rev ? cur.from.point : cur.to.point)) { ret.push_back(cell); } } return ret; } int cellWinding(Edges const &/*es*/, PathVector const &/*ps*/) { return 0; } class Sanitize: public Toy { PathVector paths; std::vector es; PointSetHandle angh; PointSetHandle pathix; void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) override { int ix = pathix.pts[0][X] / 10; es = cells(cr, paths); draw_cell(cr, es[ix], paths); cairo_set_source_rgba(cr, 0, 0, 0, 1); //cairo_path(cr, paths); //cairo_stroke(cr); Point ap = angh.pts[1] - angh.pts[0], bp = angh.pts[2] - angh.pts[0]; ap.normalize(); bp.normalize(); *notify << ang(ap, bp); Toy::draw(cr, notify, width, height, save,timer_stream); } public: Sanitize () {} void first_time(int argc, char** argv) override { const char *path_name="sanitize_examples.svgd"; if(argc > 1) path_name = argv[1]; paths = read_svgd(path_name); handles.push_back(&angh); handles.push_back(&pathix); angh.push_back(100, 100); angh.push_back(80, 100); angh.push_back(100, 80); pathix.push_back(30, 200); } }; int main(int argc, char **argv) { init(argc, argv, new Sanitize()); return 0; }