diff options
Diffstat (limited to '')
-rw-r--r-- | src/toys/sanitize.cpp | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/toys/sanitize.cpp b/src/toys/sanitize.cpp new file mode 100644 index 0000000..1d9a81f --- /dev/null +++ b/src/toys/sanitize.cpp @@ -0,0 +1,204 @@ +#include <toys/path-cairo.h> +#include <toys/toy-framework-2.h> +#include <2geom/svg-path-parser.h> +#include <2geom/utils.h> +#include <cstdlib> +#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<Edge> 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<class T> +void append(std::vector<T> &vec, std::vector<T> 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<D2<SBasis> > 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<class T> +void remove(std::vector<T> &vec, T const &val) { + for (typename std::vector<T>::iterator it = vec.begin(); it != vec.end(); ++it) { + if(*it == val) { + vec.erase(it); + return; + } + } +} + +std::vector<Edges> cells(cairo_t */*cr*/, PathVector const &ps) { + CrossingSet crs = crossings_among(ps); + Edges es = edges(ps, crs); + std::vector<Edges> ret = std::vector<Edges>(); + + 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<Edges> 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; +} |