/* $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 .
*/
#ifndef CLSURFACE_H
#define CLSURFACE_H
#include
#include
#include
#include
#include "point.hpp"
#include "halfedgediagram.hpp"
namespace ocl
{
namespace clsurf
{
typedef boost::adjacency_list_traits::edge_descriptor CLSEdge;
typedef boost::adjacency_list_traits::vertex_descriptor CLSVertex;
//typedef CLSGraph::Edge CLSEdge;
//typedef CLSGraph::Vertex CLSVertex;
typedef unsigned int CLSFace;
//typedef hedi::HEDIGraph::Face CLSFace;
typedef std::vector CLSVertexVector;
typedef std::vector CLSFaceVector;
typedef std::vector CLSEdgeVector;
struct CLSVertexProps {
CLSVertexProps() {
init();
}
/// construct vertex at position p with type t
CLSVertexProps( Point p) {
position=p;
init();
}
void init() {
index = count;
count++;
}
// HE data
Point position; ///< the position of the vertex
int index; ///< index of vertex
static int count; ///< global vertex count
};
int CLSVertexProps::count = 0;
struct CLSEdgeProps {
CLSEdgeProps() {}
/// create edge with given next, twin, and face
CLSEdgeProps(CLSEdge n, CLSEdge t, CLSFace f) {
next = n;
twin = t;
face = f;
}
CLSEdge next; ///< the next edge, counterclockwise, from this edge
CLSEdge twin; ///< the twin edge
CLSFace face; ///< the face to which this edge belongs
};
/// properties of a face
struct CLSFaceProps {
/// create face with given edge, generator, and type
CLSFaceProps() {}
CLSFaceProps( CLSEdge e ) {
edge = e;
}
CLSFace idx; ///< face index
CLSEdge edge; ///< one edge that bounds this face
};
// the cutter location surface graph
typedef hedi::HEDIGraph< boost::listS, // out-edge storage
boost::listS, // vertex set storage
boost::bidirectionalS, // bidirectional graph.
CLSVertexProps, // vertex properties
CLSEdgeProps, // edge properties
CLSFaceProps, // face properties
boost::no_property, // graph properties
boost::listS // edge storage
> CLSGraph;
/// \brief cutter location surface.
///
/// 1) start with a square sized like the bounding-box of the surface
/// 2) recursively subdivide until we reach sampling
/// 3) run drop cutter to project the surface
/// 4) adaptively subdivide until min_sampling where required
/// 5) do something:
/// - constant step-over (propagating geodesic windows on square grid is easy?)
/// - slicing (?)
/// - classify into steep/flat
/// - use for identifying rest-machining areas?
///
/// geodesic papers: "Fast Exact and Approximate Geodesics on Meshes"
/// doi 10.1145/1073204.1073228
/// http://research.microsoft.com/en-us/um/people/hoppe/geodesics.pdf
///
/// Accurate Computation of Geodesic Distance Fields for Polygonal Curves on Triangle Meshes
/// http://www.graphics.rwth-aachen.de/uploads/media/bommes_07_VMV_01.pdf
///
class CutterLocationSurface : public Operation {
public:
CutterLocationSurface() {
far=1.0;
init();
}
/// create diagram with given far-radius and number of bins
CutterLocationSurface(double f) {
far=f;
init();
}
virtual ~CutterLocationSurface() {
}
void init() {
// initialize cl-surf
//
// b e1 a
// e2 e4
// c e3 d
CLSVertex a = g.add_vertex(); // VertexProps( Point(far,far,0) ), g);
g[a].position = Point(far,far,0);
CLSVertex b = g.add_vertex(); // VertexProps( Point(-far,far,0) ), g);
g[b].position = Point(-far,far,0);
CLSVertex c = g.add_vertex(); // VertexProps( Point(-far,-far,0) ), g);
g[c].position = Point(-far,-far,0);
CLSVertex d = g.add_vertex(); // VertexProps( Point(far,-far,0) ), g);
g[c].position = Point(far,-far,0);
CLSFace f_outer= g.add_face( );
CLSFace f_inner= g.add_face( );
CLSEdge e1 = g.add_edge(a , b );
CLSEdge e1t = g.add_edge(b , a );
CLSEdge e2 = g.add_edge(b , c );
CLSEdge e2t = g.add_edge(c , b );
CLSEdge e3 = g.add_edge(c , d );
CLSEdge e3t = g.add_edge(d , c );
CLSEdge e4 = g.add_edge(d , a );
CLSEdge e4t = g.add_edge(a , d );
g[f_inner].edge = e1;
g[f_outer].edge = e1t;
out_face = f_outer;
// twin edges
g.twin_edges(e1,e1t);
g.twin_edges(e2,e2t);
g.twin_edges(e3,e3t);
g.twin_edges(e4,e4t);
// inner face:
g[e1].face = f_inner;
g[e2].face = f_inner;
g[e3].face = f_inner;
g[e4].face = f_inner;
// outer face:
g[e1t].face = f_outer;
g[e2t].face = f_outer;
g[e3t].face = f_outer;
g[e4t].face = f_outer;
// next-pointers:
g[e1].next = e2;
g[e2].next = e3;
g[e3].next = e4;
g[e4].next = e1;
// outer next-pointers:
g[e1t].next = e4t;
g[e4t].next = e3t;
g[e3t].next = e2t;
g[e2t].next = e1t;
subdivide();
}
void subdivide() {
for( CLSFace f=0; f< g.num_faces() ; ++f ) {
// subdivide each face
if ( f!= out_face ) {
subdivide_face(f);
}
}
}
void subdivide_face(CLSFace f) {
CLSEdgeVector f_edges = g.face_edges(f);
assert( f_edges.size() == 4 );
CLSVertex center = g.add_vertex();
BOOST_FOREACH( CLSEdge e, f_edges ) {
CLSVertex src = g.source(e);
CLSVertex trg = g.target(e);
// new vertex at mid-point of each edge
Point mid = 0.5*(g[src].position+g[trg].position);
g[center].position += 0.25*g[src].position; // average of four corners
CLSVertex v = g.add_vertex();
g[v].position = mid;
g.insert_vertex_in_edge(v,e); // this also removes the old edges...
}
// now loop through edges again:
f_edges = g.face_edges(f);
assert( f_edges.size() == 8 );
// BOOST_FOREACH( CLSEdge e, f_edges ) {
// std::cout << e << "\n";
// }
}
virtual void run() {
}
void setMinSampling(double s) {
min_sampling=s;
}
// PYTHON
boost::python::list getVertices() {
boost::python::list plist;
BOOST_FOREACH( CLSVertex v, g.vertices() ) {
plist.append( g[v].position );
}
return plist;
}
boost::python::list getEdges() {
boost::python::list edge_list;
BOOST_FOREACH( CLSEdge edge, g.edges() ) { // loop through each edge
boost::python::list point_list; // the endpoints of each edge
CLSVertex v1 = g.source( edge );
CLSVertex v2 = g.target( edge );
point_list.append( g[v1].position );
point_list.append( g[v2].position );
edge_list.append(point_list);
}
return edge_list;
}
/// string repr
std::string str() const {
std::ostringstream o;
o << "CutterLocationSurface (nVerts="<< g.num_vertices() << " , nEdges="<< g.num_edges() <<"\n";
return o.str();
}
protected:
// DATA
/// the half-edge diagram
CLSGraph g;
double min_sampling;
double far;
CLSFace out_face;
};
}// end clsurf namespace
} // end ocl namespace
#endif
// end clsurface.h