#include #include <2geom/path.h> #include <2geom/svg-path-parser.h> #include <2geom/path-intersection.h> #include <2geom/basic-intersection.h> #include <2geom/pathvector.h> #include <2geom/exception.h> #include #include #include #include #include #include #include #include <2geom/bezier-to-sbasis.h> #include <2geom/ord.h> #include "topology.cpp" static double exp_rescale(double x){ return pow(10, x);} std::string exp_formatter(double x){ return default_formatter(exp_rescale(x));} class IntersectDataTester: public Toy { unsigned nb_paths; unsigned nb_curves_per_path; unsigned degree; double tol; PathVector cmd_line_paths; std::vector paths_handles; std::vector sliders; int nb_steps; Topology topo; //TODO conversions to path should be owned by the relevant classes. Path edgeToPath(Topology::OrientedEdge o_edge){ Topology::Edge e = topo.edges[o_edge.edge]; D2 p = topo.input_paths[e.path][e.curve].toSBasis(); Interval dom = e.portion; p = portion(p, dom); if ( o_edge.reversed ){ p = compose( p, Linear(1.,0.) ); } Path ret; ret.setStitching(true); Point center; unsigned c_idx = topo.source(o_edge, true); if ( c_idx == NULL_IDX ){ ret.append(p); }else{ center = topo.vertices[c_idx].bounds.midpoint(); ret = Path(center); ret.append(p); } c_idx = topo.target(o_edge, true); if ( c_idx == NULL_IDX ){ return ret; }else{ center = topo.vertices[c_idx].bounds.midpoint(); if ( center != p.at1() ) ret.appendNew(center); return ret; } } Path boundaryToPath(Topology::Boundary b){ Point pt; Path bndary; bndary.setStitching(true); if (b.size()==0){ return Path(); } Topology::OrientedEdge o_edge = b.front(); unsigned first_v = topo.source(o_edge, true); if ( first_v != NULL_IDX ){ pt = topo.vertices[first_v].bounds.midpoint(); bndary = Path(pt); } for (unsigned i = 0; i < b.size(); i++){ bndary.append( edgeToPath(b[i])); } bndary.close(); return bndary; } //TODO:this should return a path vector, but we glue the components for easy drawing in the toy. Path areaToPath(unsigned a){ Path bndary; bndary.setStitching(true); if ( topo.areas[a].boundary.size()==0 ){//this is the unbounded component... OptRect bbox = bounds_fast( topo.input_paths ); if (!bbox ){return Path();}//??? bbox->expandBy(50); bndary = Path(bbox->corner(0)); bndary.appendNew(bbox->corner(1)); bndary.appendNew(bbox->corner(2)); bndary.appendNew(bbox->corner(3)); bndary.appendNew(bbox->corner(0)); }else{ bndary = boundaryToPath(topo.areas[a].boundary); } for (auto & inner_boundarie : topo.areas[a].inner_boundaries){ bndary.append( boundaryToPath(inner_boundarie)); bndary.appendNew( bndary.initialPoint() ); } bndary.close(); return bndary; } void drawAreas( cairo_t *cr, Topology const &topo, bool fill=true ){ //don't draw the first one... for (unsigned a=0; a=topo.areas.size()) return; Path bndary = areaToPath(a); cairo_path(cr, bndary); double r,g,b; int winding = 0; for (int k : topo.areas[a].windings){ winding += k; } //convertHSVtoRGB(0, 1., .5 + winding/10, r,g,b); //convertHSVtoRGB(360*a/topo.areas.size(), 1., .5, r,g,b); convertHSVtoRGB(180+30*winding, 1., .5, r,g,b); cairo_set_source_rgba (cr, r, g, b, 1); //cairo_set_source_rgba (cr, 1., 0., 1., .3); if (fill){ cairo_fill(cr); }else{ cairo_set_line_width (cr, 5); cairo_stroke(cr); } } void highlightRay( cairo_t *cr, Topology &topo, unsigned b, unsigned r ){ if (b>=topo.vertices.size()) return; if (r>=topo.vertices[b].boundary.size()) return; Rect box = topo.vertices[b].bounds; //box.expandBy(2); cairo_rectangle(cr, box); cairo_set_source_rgba (cr, 1., 0., 0, 1.0); cairo_set_line_width (cr, 1); cairo_fill(cr); unsigned eidx = topo.vertices[b].boundary[r].edge; Topology::Edge e = topo.edges[eidx]; D2 p = topo.input_paths[e.path][e.curve].toSBasis(); Interval dom = e.portion; if (topo.vertices[b].boundary[r].reversed){ //dom[0] += e.portion.extent()*2./3; cairo_set_source_rgba (cr, 0., 1., 0., 1.0); }else{ //dom[1] -= e.portion.extent()*2./3; cairo_set_source_rgba (cr, 0., 0., 1., 1.0); } p = portion(p, dom); cairo_d2_sb(cr, p); cairo_set_source_rgba (cr, 1., 0., 0, 1.0); cairo_set_line_width (cr, 5); cairo_stroke(cr); } void drawEdge( cairo_t *cr, Topology const &topo, unsigned eidx ){ if (eidx>=topo.edges.size()) return; Topology::Edge e = topo.edges[eidx]; D2 p = topo.input_paths[e.path][e.curve].toSBasis(); Interval dom = e.portion; p = portion(p, dom); cairo_d2_sb(cr, p); if (e.start == NULL_IDX || e.end == NULL_IDX ) cairo_set_source_rgba (cr, 0., 1., 0, 1.0); else cairo_set_source_rgba (cr, 0., 0., 0, 1.0); cairo_set_line_width (cr, 1); cairo_stroke(cr); } void drawEdges( cairo_t *cr, Topology const &topo ){ for (unsigned e=0; e=topo.vertices.size()) return; Rect box = topo.vertices[b].bounds; //box.expandBy(5); cairo_rectangle(cr, box); cairo_set_source_rgba (cr, 1., 0., 0, .5); cairo_set_line_width (cr, 1); cairo_stroke(cr); cairo_rectangle(cr, box); cairo_set_source_rgba (cr, 1., 0., 0, .2); cairo_fill(cr); // //std::cout<<"\nintersection boundary:\n"; // for (unsigned i = 0; i < topo.vertices[b].boundary.size(); i++){ // unsigned eidx = topo.vertices[b].boundary[i].edge; // Topology::Edge e = topo.edges[eidx]; // D2 p = topo.input_paths[e.path][e.curve].toSBasis(); // Interval dom = e.portion; // if (topo.vertices[b].boundary[i].reversed){ // dom[0] += e.portion.extent()*2./3; // cairo_set_source_rgba (cr, 0., 1., .5, 1); // }else{ // dom[1] -= e.portion.extent()*2./3; // cairo_set_source_rgba (cr, 0., .5, 1., 1); // } // p = portion(p, dom); // cairo_d2_sb(cr, p); // cairo_set_line_width (cr, 2); // cairo_stroke(cr); // } } void drawBoxes( cairo_t *cr, Topology const &topo ){ for (unsigned b=0; b c = handles_to_sbasis(paths_handles[i].pts.begin()+j, degree); if ( j + degree == paths_handles[i].size()-1 ){ c[X].at(0)[1] = paths_handles[i].pts.front()[X]; c[Y].at(0)[1] = paths_handles[i].pts.front()[Y]; } paths[i].append(c); } paths[i].close(); } } *notify<<"Use '<' and '>' keys to move backward/forward in the sweep: (currently doing "<( cmd_line_paths.size(), PointSetHandle() ); for(unsigned i = 0; i < cmd_line_paths.size(); i++){ //TODO: use path iterators to deal with closed/open paths!!! //cmd_line_paths[i].close(); if ( cmd_line_paths[i].closed() ){ cmd_line_paths[i].appendNew(cmd_line_paths[i].initialPoint() ); } Point p = cmd_line_paths[i].initialPoint(); paths_handles.emplace_back(); paths_handles[i].push_back(p); handles.push_back( &paths_handles[i] ); } initSliders(); } IntersectDataTester(unsigned paths, unsigned curves_in_path, unsigned degree) : nb_paths(paths), nb_curves_per_path(curves_in_path), degree(degree) { paths_handles = std::vector( nb_paths, PointSetHandle() ); for(unsigned i = 0; i < nb_paths; i++){ for(unsigned j = 0; j < (nb_curves_per_path*degree)+1; j++){ paths_handles[i].push_back(uniform()*400, 100+ uniform()*300); } handles.push_back(&paths_handles[i]); } initSliders(); } IntersectDataTester(){ nb_paths=3; nb_curves_per_path = 5; degree = 1; paths_handles.emplace_back(); paths_handles[0].push_back(100,100); paths_handles[0].push_back(100,200); paths_handles[0].push_back(300,200); paths_handles[0].push_back(300,100); paths_handles[0].push_back(100,100); paths_handles.emplace_back(); paths_handles[1].push_back(120,190); paths_handles[1].push_back(200,210); paths_handles[1].push_back(280,190); paths_handles[1].push_back(200,300); paths_handles[1].push_back(120,190); paths_handles.emplace_back(); paths_handles[2].push_back(180,150); paths_handles[2].push_back(200,140); paths_handles[2].push_back(220,150); paths_handles[2].push_back(300,160); paths_handles[2].push_back(180,150); handles.push_back(&paths_handles[0]); handles.push_back(&paths_handles[1]); handles.push_back(&paths_handles[2]); initSliders(); } void first_time(int /*argc*/, char** /*argv*/) override { nb_steps = -1; } void key_hit(GdkEventKey *e) override { char choice = std::toupper(e->keyval); switch ( choice ) { case '>': nb_steps++; break; case '<': if ( nb_steps > -1 ) nb_steps--; break; } redraw(); } }; int main(int argc, char **argv) { if(argc == 2){ const char *path_name = argv[1]; PathVector cmd_line_paths = read_svgd(path_name); //* Scale(3); OptRect bounds = bounds_exact(cmd_line_paths); if (bounds) { cmd_line_paths *= Translate(Point(10,10) - bounds->min()); } init(argc, argv, new IntersectDataTester(cmd_line_paths)); }else{ unsigned nb_paths=3, nb_curves_per_path = 5, degree = 1; if(argc > 3) sscanf(argv[3], "%d", °ree); if(argc > 2) sscanf(argv[2], "%d", &nb_curves_per_path); if(argc > 1){ sscanf(argv[1], "%d", &nb_paths); init(argc, argv, new IntersectDataTester( nb_paths, nb_curves_per_path, degree ) ); }else{ init(argc, argv, new IntersectDataTester()); } } 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 :