/* $Id$ * * Copyright (c) 2010-2011 Anders Wallin (anders.e.e.wallin "at" gmail.com). * * This file is part of OpenCAMlib * (see https://github.com/aewallin/opencamlib). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include "simple_weave.hpp" namespace ocl { namespace weave { std::pair SimpleWeave::find_neighbor_vertices( VertexPair v_pair, Interval& ival) { Interval::VertexPairIterator itr = ival.intersections2.lower_bound( v_pair ); // returns first that is not less than argument (equal or greater) assert( itr != ival.intersections2.end() ); // we must find a lower_bound Interval::VertexPairIterator v_above = itr; // lower_bound returns one beyond the give key, i.e. what we want Interval::VertexPairIterator v_below = --itr; // this is the vertex below the give vertex std::pair out; out.first = v_above->first; // vertex above v (xu) out.second = v_below->first; // vertex below v (xl) assert( out.first != out.second ); return out; } // from the list of fibers, build a graph // FIXME: the problem here is that from N x-fibers and N y-fibers // this builds a graph with roughly N*N vertices/edges. This consumes a lot of RAM even // for small parts, and unacceptably much RAM for large parts. // a smarter build() would keep track of the important faces of the planar graph // (faces that produce toolpath-loops) // vertices/edges belonging to non-toolpath-producing faces could then be deleted // and the RAM consumption should be limited to N+N (i.e. the length/perimeter of the part/toolpath // in contrast to the area for the naive implementation) void SimpleWeave::build() { // 1) add CL-points of X-fiber (if not already in graph) // 2) add CL-points of Y-fiber (if not already in graph) // 3) add intersection point (if not already in graph) (will always be new??) // 4) add edges. (if they provide new connections) // ycl_lower <-> intp <-> ycl_upper // xcl_lower <-> intp <-> xcl_upper // if this connects points that are already connected, then remove old edge and // provide this "via" connection //int n_xfiber=0; // std::cout << " SimpleWeave::build()... \n"; BOOST_FOREACH( Fiber& xf, xfibers) { assert( !xf.empty() ); // no empty fibers please BOOST_FOREACH( Interval& xi, xf.ints ) { //std::cout << "x-fiber " << n_xfiber++ << "\n"; double xmin = xf.point(xi.lower).x; double xmax = xf.point(xi.upper).x; if ( (xmax-xmin) > 0) { assert( !xi.in_weave ); // this is the first time the x-interval is added! xi.in_weave = true; // add the X interval end-points to the weave Point p1( xf.point(xi.lower) ); Vertex xv1 = add_cl_vertex( p1, xi, p1.x ); Point p2( xf.point(xi.upper) ); Vertex xv2 = add_cl_vertex( p2, xi, p2.x ); Edge e1 = g.add_edge(xv1,xv2); Edge e2 = g.add_edge(xv2,xv1); //std::cout << " add_edge " << xv1 << "("<< p1.x<< ") - " << xv2 <<"("<< p2.x << ")\n"; g[e1].next = e2; g[e2].next = e1; g[e1].prev = e2; g[e2].prev = e1; //int n_yfiber=0; BOOST_FOREACH( Fiber& yf, yfibers ) { // loop through all y-fibers for all x-intervals if ( (xmin < yf.p1.x) && ( yf.p1.x < xmax ) ) {// potential intersection between y-fiber and x-interval BOOST_FOREACH( Interval& yi, yf.ints ) { //std::cout << "y-fiber " << n_yfiber++ << "\n"; double ymin = yf.point(yi.lower).y ; double ymax = yf.point(yi.upper).y ; if ( (ymin < xf.p1.y) && (xf.p1.y < ymax) ) { // there is an actual intersection btw x-interval and y-interval // X interval xi on fiber xf intersects with Y interval yi on fiber yf // intersection is at ( yf.p1.x, xf.p1.y , xf.p1.z ) if (!yi.in_weave) { // add y-interval endpoints to weave Point yp1( yf.point(yi.lower) ); add_cl_vertex( yp1, yi, yp1.y ); Point yp2( yf.point(yi.upper) ); add_cl_vertex( yp2, yi, yp2.y ); yi.in_weave = true; } // 3) intersection point, of type INT Vertex v = g.null_vertex(); Point v_position( yf.p1.x, xf.p1.y , xf.p1.z ); // find neighbor to v Vertex x_u, x_l; //std::cout << " fins neighbor to x= " << v_position.x << "\n"; boost::tie( x_u, x_l ) = find_neighbor_vertices( VertexPair(v, v_position.x), xi ); //std::cout << "found: x_u , x_l : " << x_u << " , " << x_l << "\n"; Vertex y_u, y_l; boost::tie( y_u, y_l ) = find_neighbor_vertices( VertexPair(v, v_position.y), yi ); //std::cout << "found: y_u , y_l : " << y_u << " , " << y_l << "\n"; add_int_vertex(v_position,x_l,x_u,y_l,y_u,xi,yi); } // end intersection case } // end y interval loop } // end if(potential intersection) } // end y fiber loop // now we've added an x-interval, we've gone through all the y-intervals // if there isn't a single intersecting interval, then remove the x-interval as it is useless assert( xi.intersections2.size() >= 2 ); if ( xi.intersections2.size() == 2 ) { clVertexSet.erase(xv1); clVertexSet.erase(xv2); g.clear_vertex(xv1); g.clear_vertex(xv2); g.remove_vertex(xv1); g.remove_vertex(xv2); } } // end zero-length interval check } // x interval loop } // end X-fiber loop } // add a new CL-vertex to Weave, also adding it to the interval intersection-set, and to clVertices Vertex SimpleWeave::add_cl_vertex( const Point& position, Interval& ival, double ipos) { Vertex v = g.add_vertex(); g[v].position = position; g[v].type = CL; ival.intersections2.insert( VertexPair( v, ipos) ); // ?? this makes Interval depend on the WeaveGraph type clVertexSet.insert(v); return v; } // add an internal vertex to the weave void SimpleWeave::add_int_vertex( const Point& v_position, // position of new vertex Vertex& x_l, // the x-lower vertex Vertex& x_u, // the x-upper vertex Vertex& y_l, // y-lower Vertex& y_u, // y-upper Interval& x_int, // the x-interval Interval& y_int ) // the y-interval { //std::cout << " add_int_vertex " << "\n"; Vertex v = g.add_vertex(); //hedi::add_vertex( VertexProps( v_position, INT ), g); g[v].position = v_position; g[v].type = INT; assert( g.has_edge(x_l,x_u) ); assert( g.has_edge(x_u,x_l) ); Edge xe_lu = g.edge(x_l,x_u); Edge xe_ul = g.edge(x_u,x_l); Edge xe_lu_next = g[xe_lu].next; Edge xe_lu_prev = g[xe_lu].prev; Edge xe_ul_next = g[xe_ul].next; Edge xe_ul_prev = g[xe_ul].prev; // the next/prev data we need Edge ye_lu_next, ye_lu_prev ; Edge ye_ul_next, ye_ul_prev ; Edge ye_lu, ye_ul; bool y_lu_edge = g.has_edge(y_l,y_u); // flag indicating existing y_l - y_u edge // the case where y_l and y_u are already connected. if ( y_lu_edge ) { assert( g.has_edge( y_u, y_l ) ); // twin must also exist ye_lu = g.edge( y_l, y_u); ye_ul = g.edge( y_u, y_l); ye_lu_next = g[ye_lu].next; ye_lu_prev = g[ye_lu].prev; ye_ul_next = g[ye_ul].next; ye_ul_prev = g[ye_ul].prev; } // and now eight new edges to add Edge xl_v = g.add_edge(x_l, v ); Edge v_yl = g.add_edge(v , y_l); Edge yl_v = g.add_edge(y_l, v ); Edge v_xu = g.add_edge(v , x_u); Edge xu_v = g.add_edge(x_u, v ); Edge v_yu = g.add_edge(v , y_u); Edge yu_v = g.add_edge(y_u, v ); Edge v_xl = g.add_edge(v , x_l); // checks for special cases: if (xe_lu_prev == xe_ul) // xl hairpin xe_lu_prev = v_xl; if (xe_lu_next == xe_ul) // xu hairpin xe_lu_next = xu_v; if (xe_ul_prev == xe_lu) xe_ul_prev = v_xu; if (xe_ul_next == xe_lu) xe_ul_next = xl_v; if ( y_lu_edge ) { // the same checks for the y-edge if (ye_lu_prev == ye_ul) ye_lu_prev = v_yl; if (ye_lu_next == ye_ul) ye_lu_next = yu_v; if (ye_ul_prev == ye_lu) ye_ul_prev = v_yu; if (ye_ul_next == ye_lu) ye_ul_next = yl_v; } else { // we should form a y-hairpin ye_lu_next = yu_v; ye_lu_prev = v_yl; ye_ul_next = yl_v; ye_ul_prev = v_yu; } // now set next/prev edges (there are 2*12=24 of these to do) g[xe_lu_prev].next = xl_v; g[xl_v].prev = xe_lu_prev; g[xl_v].next = v_yl; g[v_yl].prev = xl_v; g[v_yl].next = ye_ul_next; g[ye_ul_next].prev = v_yl; g[ye_lu_prev].next = yl_v; g[yl_v].prev = ye_lu_prev; g[yl_v].next = v_xu; g[v_xu].prev = yl_v; g[v_xu].next = xe_lu_next; g[xe_lu_next].prev = v_xu; g[xe_ul_prev].next = xu_v; g[xu_v].prev = xe_ul_prev; g[xu_v].next = v_yu; g[v_yu].prev = xu_v; g[v_yu].next = ye_lu_next; g[ye_lu_next].prev = v_yu; g[ye_ul_prev].next = yu_v; g[yu_v].prev = ye_ul_prev; g[yu_v].next = v_xl; g[v_xl].prev = yu_v; g[v_xl].next = xe_ul_next; g[xe_ul_next].prev = v_xl; // delete the old x-edges g.remove_edge( x_l, x_u); g.remove_edge( x_u, x_l); if( y_lu_edge ) { // delete old y-edges assert( g.has_edge( y_l, y_u) ); assert( g.has_edge( y_u, y_l) ); g.remove_edge( y_l, y_u); g.remove_edge( y_u, y_l); } // finally add new intersection vertex to the interval sets x_int.intersections2.insert( VertexPair( v, v_position.x ) ); y_int.intersections2.insert( VertexPair( v, v_position.y ) ); } } // end weave namespace } // end ocl namespace // end file simple_weave.cpp