Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_TRIANGULATE_HPP
Toshihiro Shimizu 890ddd
#define TCG_TRIANGULATE_HPP
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "../triangulate.h"
Toshihiro Shimizu 890ddd
#include "../traits.h"
Toshihiro Shimizu 890ddd
#include "../point_ops.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// OS-specific includes
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
#include "windows.h"
Toshihiro Shimizu 890ddd
#include <gl glu.h=""></gl>
Toshihiro Shimizu 890ddd
#elif MACOSX
Toshihiro Shimizu 890ddd
#include <glut glut.h=""></glut>
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_GLU_CALLBACK
Toshihiro Shimizu 890ddd
#ifdef WIN32
Toshihiro Shimizu 890ddd
#define TCG_GLU_CALLBACK void(CALLBACK *)()
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
#define TCG_GLU_CALLBACK void (*)()
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef CALLBACK
Toshihiro Shimizu 890ddd
#define CALLBACK
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace tcg
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    GLU Tessellator Callbacks
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace detail
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
struct CBackData {
Toshihiro Shimizu 890ddd
	mesh_type *m_mesh;
Toshihiro Shimizu 890ddd
	int m_triangle[3];
Toshihiro Shimizu 890ddd
	int m_i;
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// NOTE: must be declared with CALLBACK directive
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
void CALLBACK tessBegin(GLenum type, void *polygon_data)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(type == GL_TRIANGLES);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CBackData<mesh_type> *data = (CBackData<mesh_type> *)polygon_data;</mesh_type></mesh_type>
Toshihiro Shimizu 890ddd
	data->m_i = 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
void CALLBACK tessEnd(void *polygon_data)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	CBackData<mesh_type> *data = (CBackData<mesh_type> *)polygon_data;</mesh_type></mesh_type>
Toshihiro Shimizu 890ddd
	assert(data->m_i == 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type,="" typename="" vertex_type=""></typename>
Toshihiro Shimizu 890ddd
void CALLBACK tessVertex(void *vertex_data, void *polygon_data)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef typename mesh_type::vertex_type::point_type point_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	CBackData<mesh_type> *data = (CBackData<mesh_type> *)polygon_data;</mesh_type></mesh_type>
Toshihiro Shimizu 890ddd
	vertex_type *vData = (vertex_type *)vertex_data;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	GLdouble(&pos)[3] = TriMeshStuff::glu_vertex_traits<vertex_type>::vertex3d(*vData);</vertex_type>
Toshihiro Shimizu 890ddd
	int &idx = TriMeshStuff::glu_vertex_traits<vertex_type>::index(*vData);</vertex_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (idx < 0) {
Toshihiro Shimizu 890ddd
		data->m_mesh->addVertex(typename mesh_type::vertex_type(point_type(pos[0], pos[1])));
Toshihiro Shimizu 890ddd
		idx = data->m_mesh->verticesCount() - 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	data->m_triangle[data->m_i] = idx;
Toshihiro Shimizu 890ddd
	data->m_i = (data->m_i + 1) % 3;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (data->m_i == 0)
Toshihiro Shimizu 890ddd
		data->m_mesh->addFace(data->m_triangle[0], data->m_triangle[1], data->m_triangle[2]);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Supplied to ensure that triangle primitives are always of type GL_TRIANGLE
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
void CALLBACK edgeFlag(GLboolean flag)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace tcg::detail
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Polygon triangulation
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace detail
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename func=""></typename>
Toshihiro Shimizu 890ddd
void gluRegister(GLUtesselator *tess, GLenum which, Func *func)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	gluTessCallback(tess, which, (TCG_GLU_CALLBACK)func);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace tcg::detail
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename containersreader="" forit,="" typename=""></typename>
Toshihiro Shimizu 890ddd
void gluTriangulate(ForIt tribeBegin, ForIt tribeEnd, ContainersReader &meshes_reader)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	using namespace detail;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef typename tcg::traits<typename forit::value_type="">::pointed_type family_type;</typename>
Toshihiro Shimizu 890ddd
	typedef typename tcg::traits<typename family_type::value_type="">::pointed_type polygon_type;</typename>
Toshihiro Shimizu 890ddd
	typedef typename polygon_type::value_type vertex_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef typename tcg::container_reader_traits<containersreader> output;</containersreader>
Toshihiro Shimizu 890ddd
	typedef typename tcg::traits<typename output::value_type="">::pointed_type mesh_type;</typename>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	GLUtesselator *tess = gluNewTess(); // create a tessellator
Toshihiro Shimizu 890ddd
	assert(tess);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Declare callbacks
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTE: On g++, it seems that at this point each of the callbacks still have undefined type.
Toshihiro Shimizu 890ddd
	// We use the above gluRegister template to force the compiler to generate these types.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	gluRegister(tess, GLU_TESS_BEGIN_DATA, tessBegin<mesh_type>);</mesh_type>
Toshihiro Shimizu 890ddd
	gluRegister(tess, GLU_TESS_END_DATA, tessEnd<mesh_type>);</mesh_type>
Toshihiro Shimizu 890ddd
	gluRegister(tess, GLU_TESS_VERTEX_DATA, tessVertex<mesh_type, vertex_type="">);</mesh_type,>
Toshihiro Shimizu 890ddd
	gluRegister(tess, GLU_TESS_EDGE_FLAG, edgeFlag<mesh_type>);</mesh_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	output::openContainer(meshes_reader);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Iterate the tribe. For every polygons family, associate one output mesh
Toshihiro Shimizu 890ddd
	for (ForIt it = tribeBegin; it != tribeEnd; ++it) {
Toshihiro Shimizu 890ddd
		// Build the output mesh and initialize stuff
Toshihiro Shimizu 890ddd
		mesh_type *mesh = new mesh_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CBackData<mesh_type> cbData; // Callback Data about the mesh</mesh_type>
Toshihiro Shimizu 890ddd
		cbData.m_mesh = mesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Tessellate the family
Toshihiro Shimizu 890ddd
		gluTessBeginPolygon(tess, (void *)&cbData);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		typename family_type::iterator ft, fEnd = (*it)->end();
Toshihiro Shimizu 890ddd
		for (ft = (*it)->begin(); ft != fEnd; ++ft) {
Toshihiro Shimizu 890ddd
			gluTessBeginContour(tess);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			typename polygon_type::iterator pt, pEnd = (*ft)->end();
Toshihiro Shimizu 890ddd
			for (pt = (*ft)->begin(); pt != pEnd; ++pt)
Toshihiro Shimizu 890ddd
				gluTessVertex(tess,
Toshihiro Shimizu 890ddd
							  TriMeshStuff::glu_vertex_traits<vertex_type>::vertex3d(*pt),</vertex_type>
Toshihiro Shimizu 890ddd
							  (void *)&*pt);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			gluTessEndContour(tess);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		gluTessEndPolygon(tess); // Invokes the family tessellation
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		output::addElement(meshes_reader, mesh);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	gluDeleteTess(tess); // delete after tessellation
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	output::closeContainer(meshes_reader);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
//    Mesh refinement
Toshihiro Shimizu 890ddd
//**************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace detail
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
inline void touchEdge(std::vector<uchar> &buildEdge, mesh_type &mesh, int e)</uchar>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typename mesh_type::edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
	int f1 = ed.face(0), f2 = ed.face(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f1 >= 0) {
Toshihiro Shimizu 890ddd
		typename mesh_type::face_type &f = mesh.face(f1);
Toshihiro Shimizu 890ddd
		buildEdge[f.edge(0)] = 1, buildEdge[f.edge(1)] = 1, buildEdge[f.edge(2)] = 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (f2 >= 0) {
Toshihiro Shimizu 890ddd
		typename mesh_type::face_type &f = mesh.face(f2);
Toshihiro Shimizu 890ddd
		buildEdge[f.edge(0)] = 1, buildEdge[f.edge(1)] = 1, buildEdge[f.edge(2)] = 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
inline void touchVertex(std::vector<uchar> &buildEdge, mesh_type &mesh, int v)</uchar>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Sign all adjacent edges and adjacent faces' edges to v
Toshihiro Shimizu 890ddd
	typename mesh_type::vertex_type &vx = mesh.vertex(v);
Toshihiro Shimizu 890ddd
	const tcg::list<int> &incidentEdges = vx.edges();</int>
Toshihiro Shimizu 890ddd
	tcg::list<int>::const_iterator it;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (it = incidentEdges.begin(); it != incidentEdges.end(); ++it)
Toshihiro Shimizu 890ddd
		touchEdge(buildEdge, mesh, *it);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
class BoundaryEdges
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<uchar> m_boundaryVertices;</uchar>
Toshihiro Shimizu 890ddd
	const mesh_type &m_mesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	BoundaryEdges(const mesh_type &mesh)
Toshihiro Shimizu 890ddd
		: m_mesh(mesh)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const tcg::list<typename mesh_type::edge_type=""> &edges = mesh.edges();</typename>
Toshihiro Shimizu 890ddd
		const tcg::list<typename mesh_type::vertex_type=""> &vertices = mesh.vertices();</typename>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_boundaryVertices.resize(vertices.nodesCount(), 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		typename tcg::list<typename mesh_type::edge_type="">::const_iterator it;</typename>
Toshihiro Shimizu 890ddd
		for (it = edges.begin(); it != edges.end(); ++it) {
Toshihiro Shimizu 890ddd
			if (it->face(0) < 0 || it->face(1) < 0) {
Toshihiro Shimizu 890ddd
				m_boundaryVertices[it->vertex(0)] = true;
Toshihiro Shimizu 890ddd
				m_boundaryVertices[it->vertex(1)] = true;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	~BoundaryEdges() {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void setBoundaryVertex(int v)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_boundaryVertices.resize(m_mesh.vertices().nodesCount(), 0);
Toshihiro Shimizu 890ddd
		m_boundaryVertices[v] = 1;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isBoundaryVertex(int v) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return v < int(m_boundaryVertices.size()) && m_boundaryVertices[v];
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool isBoundaryEdge(int e) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const typename mesh_type::edge_type &ed = m_mesh.edge(e);
Toshihiro Shimizu 890ddd
		return ed.face(0) < 0 || ed.face(1) < 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace tcg::detail
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
void TriMeshStuff::DefaultEvaluator<mesh_type>::actionSort(</mesh_type>
Toshihiro Shimizu 890ddd
	const mesh_type &mesh, int e, typename ActionEvaluator<mesh_type>::Action *actionSequence)</mesh_type>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef ActionEvaluator<mesh_type> ActionEvaluator;</mesh_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int count = 0;
Toshihiro Shimizu 890ddd
	memset(actionSequence, ActionEvaluator::NONE, 3 * sizeof(typename ActionEvaluator::Action));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Try to minimize the edge length deviation in e's neighbourhood
Toshihiro Shimizu 890ddd
	const typename mesh_type::edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
	int f1 = ed.face(0), f2 = ed.face(1);
Toshihiro Shimizu 890ddd
	const TPointD *v1, *v2, *v3, *v4;
Toshihiro Shimizu 890ddd
	double length[6];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	v1 = &mesh.vertex(ed.vertex(0)).P();
Toshihiro Shimizu 890ddd
	v2 = &mesh.vertex(ed.vertex(1)).P();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	length[0] = norm(*v2 - *v1);
Toshihiro Shimizu 890ddd
	double lengthMax = length[0], lengthMin = length[0];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f1 >= 0) {
Toshihiro Shimizu 890ddd
		v3 = &mesh.vertex(mesh.otherFaceVertex(f1, e)).P();
Toshihiro Shimizu 890ddd
		length[1] = norm(*v3 - *v1);
Toshihiro Shimizu 890ddd
		length[2] = norm(*v3 - *v2);
Toshihiro Shimizu 890ddd
		lengthMax = tmax(lengthMax, length[1], length[2]);
Toshihiro Shimizu 890ddd
		lengthMin = tmin(lengthMin, length[1], length[2]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f2 >= 0) {
Toshihiro Shimizu 890ddd
		v4 = &mesh.vertex(mesh.otherFaceVertex(f2, e)).P();
Toshihiro Shimizu 890ddd
		length[3] = norm(*v4 - *v1);
Toshihiro Shimizu 890ddd
		length[4] = norm(*v4 - *v2);
Toshihiro Shimizu 890ddd
		lengthMax = tmax(lengthMax, length[3], length[4]);
Toshihiro Shimizu 890ddd
		lengthMin = tmin(lengthMin, length[3], length[4]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f1 >= 0 && f2 >= 0) {
Toshihiro Shimizu 890ddd
		//Build the edge lengths
Toshihiro Shimizu 890ddd
		length[5] = norm(*v4 - *v3);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Evaluate swap - take the triangles with least maximum mean boundary edge
Toshihiro Shimizu 890ddd
		double m1 = (length[0] + length[1] + length[2]) / 3.0;
Toshihiro Shimizu 890ddd
		double m2 = (length[0] + length[3] + length[4]) / 3.0;
Toshihiro Shimizu 890ddd
		double m3 = (length[5] + length[1] + length[3]) / 3.0;
Toshihiro Shimizu 890ddd
		double m4 = (length[5] + length[2] + length[4]) / 3.0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (tmax(m3, m4) < tmax(m1, m2) - 1e-5)
Toshihiro Shimizu 890ddd
			actionSequence[count++] = ActionEvaluator::SWAP;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//NOTE: The original swap evaluation was about maximizing the minimal face angle.
Toshihiro Shimizu 890ddd
		//However, this requires quite some cross products - the above test is sufficiently
Toshihiro Shimizu 890ddd
		//simple and has a similar behaviour.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Evaluate collapse
Toshihiro Shimizu 890ddd
		if (length[0] < m_collapseValue)
Toshihiro Shimizu 890ddd
			actionSequence[count++] = ActionEvaluator::COLLAPSE;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Evaluate split
Toshihiro Shimizu 890ddd
	if (length[0] > m_splitValue)
Toshihiro Shimizu 890ddd
		actionSequence[count++] = ActionEvaluator::SPLIT;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace detail
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
inline bool testSwap(const mesh_type &mesh, int e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Retrieve adjacent faces
Toshihiro Shimizu 890ddd
	const typename mesh_type::edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int f1 = ed.face(0), f2 = ed.face(1);
Toshihiro Shimizu 890ddd
	if (f1 < 0 || f2 < 0)
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Retrieve the 4 adjacent vertices
Toshihiro Shimizu 890ddd
	const typename mesh_type::vertex_type &v1 = mesh.vertex(ed.vertex(0));
Toshihiro Shimizu 890ddd
	const typename mesh_type::vertex_type &v2 = mesh.vertex(ed.vertex(1));
Toshihiro Shimizu 890ddd
	const typename mesh_type::vertex_type &v3 = mesh.vertex(mesh.otherFaceVertex(f1, ed.getIndex()));
Toshihiro Shimizu 890ddd
	const typename mesh_type::vertex_type &v4 = mesh.vertex(mesh.otherFaceVertex(f2, ed.getIndex()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Make sure that vertex v4 lies between the semiplane generated by v3v1 and v3v2
Toshihiro Shimizu 890ddd
	TPointD a(v1.P() - v3.P()), b(v2.P() - v3.P());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double normA = norm(a), normB = norm(b);
Toshihiro Shimizu 890ddd
	if (normA < 1e-5 || normB < 1e-5)
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	a = a * (1.0 / normA);
Toshihiro Shimizu 890ddd
	b = b * (1.0 / normB);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TPointD c(v4.P() - v1.P()), d(v4.P() - v2.P());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double normC = norm(c), normD = norm(d);
Toshihiro Shimizu 890ddd
	if (normC < 1e-5 || normD < 1e-5)
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	c = c * (1.0 / normC);
Toshihiro Shimizu 890ddd
	d = d * (1.0 / normD);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double crossAC = point_ops::cross(a, c);
Toshihiro Shimizu 890ddd
	int signAC = crossAC < -1e-5 ? -1 : crossAC > 1e-5 ? 1 : 0;
Toshihiro Shimizu 890ddd
	double crossBD = point_ops::cross(b, d);
Toshihiro Shimizu 890ddd
	int signBD = crossBD < -1e-5 ? -1 : crossBD > 1e-5 ? 1 : 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return signAC == -signBD;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Tests edge e for admissibility of ad edge collapse. Edge e must not have adjacent
Toshihiro Shimizu 890ddd
//faces with boundary components.
Toshihiro Shimizu 890ddd
//Furthermore, we must test that faces adjacent to f1 and f2 keep e on the same side of
Toshihiro Shimizu 890ddd
//the line passing through v3v1 and v3v2.
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
inline bool testCollapse(const mesh_type &mesh, int e, const BoundaryEdges<mesh_type> &boundary)</mesh_type>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Any face adjacent to e must have no boundary edge
Toshihiro Shimizu 890ddd
	const typename mesh_type::edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
	int f1 = ed.face(0), f2 = ed.face(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (f1 < 0 || f2 < 0)
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int v1 = mesh.edge(e).vertex(0), v2 = mesh.edge(e).vertex(1);
Toshihiro Shimizu 890ddd
	if (boundary.isBoundaryVertex(v1) ||
Toshihiro Shimizu 890ddd
		boundary.isBoundaryVertex(v2))
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Test faces adjacent to v1 or v2. Since one of their vertices will change, we must make sure that their
Toshihiro Shimizu 890ddd
	//'side' does not change too.
Toshihiro Shimizu 890ddd
	int v = mesh.otherFaceVertex(f1, e);
Toshihiro Shimizu 890ddd
	int l = mesh.edgeInciding(v1, v);
Toshihiro Shimizu 890ddd
	int f = mesh.edge(l).face(0) == f1 ? mesh.edge(l).face(1) : mesh.edge(l).face(0);
Toshihiro Shimizu 890ddd
	int vNext = mesh.otherFaceVertex(f, l);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (f != f2) {
Toshihiro Shimizu 890ddd
		//Test face f
Toshihiro Shimizu 890ddd
		if (tsign(point_ops::cross(mesh.vertex(vNext).P() - mesh.vertex(v).P(), mesh.vertex(v2).P() - mesh.vertex(v).P())) !=
Toshihiro Shimizu 890ddd
			tsign(point_ops::cross(mesh.vertex(vNext).P() - mesh.vertex(v).P(), mesh.vertex(v1).P() - mesh.vertex(v).P())))
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Update vars
Toshihiro Shimizu 890ddd
		v = vNext;
Toshihiro Shimizu 890ddd
		l = mesh.edgeInciding(v1, v);
Toshihiro Shimizu 890ddd
		f = mesh.edge(l).face(0) == f ? mesh.edge(l).face(1) : mesh.edge(l).face(0);
Toshihiro Shimizu 890ddd
		vNext = mesh.otherFaceVertex(f, l);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Same with respect to v2
Toshihiro Shimizu 890ddd
	v = mesh.otherFaceVertex(f1, e);
Toshihiro Shimizu 890ddd
	l = mesh.edgeInciding(v2, v);
Toshihiro Shimizu 890ddd
	f = mesh.edge(l).face(0) == f1 ? mesh.edge(l).face(1) : mesh.edge(l).face(0);
Toshihiro Shimizu 890ddd
	vNext = mesh.otherFaceVertex(f, l);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (f != f2) {
Toshihiro Shimizu 890ddd
		//Test face f
Toshihiro Shimizu 890ddd
		if (tsign(point_ops::cross(mesh.vertex(vNext).P() - mesh.vertex(v).P(), mesh.vertex(v2).P() - mesh.vertex(v).P())) !=
Toshihiro Shimizu 890ddd
			tsign(point_ops::cross(mesh.vertex(vNext).P() - mesh.vertex(v).P(), mesh.vertex(v1).P() - mesh.vertex(v).P())))
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Update vars
Toshihiro Shimizu 890ddd
		v = vNext;
Toshihiro Shimizu 890ddd
		l = mesh.edgeInciding(v2, v);
Toshihiro Shimizu 890ddd
		f = mesh.edge(l).face(0) == f ? mesh.edge(l).face(1) : mesh.edge(l).face(0);
Toshihiro Shimizu 890ddd
		vNext = mesh.otherFaceVertex(f, l);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace tcg::detail
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename mesh_type=""></typename>
Toshihiro Shimizu 890ddd
void refineMesh(
Toshihiro Shimizu 890ddd
	mesh_type &mesh, TriMeshStuff::ActionEvaluator<mesh_type> &eval, unsigned long maxActions)</mesh_type>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	using namespace detail;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	typedef TriMeshStuff::ActionEvaluator<mesh_type> Evaluator;</mesh_type>
Toshihiro Shimizu 890ddd
	typedef typename Evaluator::Action Action;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//DIAGNOSTICS_TIMER("simplifyMesh");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build boundary edges. They will not be altered by the simplification procedure.
Toshihiro Shimizu 890ddd
	detail::BoundaryEdges<mesh_type> boundary(mesh);</mesh_type>
Toshihiro Shimizu 890ddd
	Action actions[3], *act, *actEnd = actions + 3;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tcg::list<edge> &edges = mesh.edges();</edge>
Toshihiro Shimizu 890ddd
	tcg::list<edge>::iterator it;</edge>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//DIAGNOSTICS_SET("Simplify | Vertex count (before simplify)", mesh.vertexCount());
Toshihiro Shimizu 890ddd
	//DIAGNOSTICS_SET("Simplify | Edges count (before simplify)", edges.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Build a vector of the edges to be analyzed
Toshihiro Shimizu 890ddd
	std::vector<uchar> buildEdge(edges.nodesCount(), 1);</uchar>
Toshihiro Shimizu 890ddd
	int touchedIdx;
Toshihiro Shimizu 890ddd
	bool boundaryEdge;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
cycle:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (maxActions-- == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Analyze mesh for possible updates. Perform the first one.
Toshihiro Shimizu 890ddd
	for (it = edges.begin(); it != edges.end(); ++it) {
Toshihiro Shimizu 890ddd
		if (!buildEdge[it.m_idx])
Toshihiro Shimizu 890ddd
			continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		boundaryEdge = boundary.isBoundaryEdge(it.m_idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		eval.actionSort(mesh, it.m_idx, actions);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (act = actions; act < actEnd; ++act) {
Toshihiro Shimizu 890ddd
			//Try to perform the i-th action
Toshihiro Shimizu 890ddd
			if (*act == Evaluator::NONE)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			else if (!boundaryEdge && *act == Evaluator::SWAP && testSwap(mesh, it.m_idx)) {
Toshihiro Shimizu 890ddd
				touchedIdx = mesh.swapEdge(it.m_idx);
Toshihiro Shimizu 890ddd
				touchEdge(buildEdge, mesh, touchedIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				goto cycle;
Toshihiro Shimizu 890ddd
			} else if (!boundaryEdge && *act == Evaluator::COLLAPSE && testCollapse(mesh, it.m_idx, boundary)) {
Toshihiro Shimizu 890ddd
				touchedIdx = mesh.collapseEdge(it.m_idx);
Toshihiro Shimizu 890ddd
				touchVertex(buildEdge, mesh, touchedIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				goto cycle;
Toshihiro Shimizu 890ddd
			} else if (*act == Evaluator::SPLIT) {
Toshihiro Shimizu 890ddd
				Edge &ed = mesh.edge(it.m_idx);
Toshihiro Shimizu 890ddd
				touchVertex(buildEdge, mesh, ed.vertex(0));
Toshihiro Shimizu 890ddd
				touchVertex(buildEdge, mesh, ed.vertex(1));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				touchedIdx = mesh.splitEdge(it.m_idx);
Toshihiro Shimizu 890ddd
				if (buildEdge.size() < edges.size())
Toshihiro Shimizu 890ddd
					buildEdge.resize(edges.size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				touchVertex(buildEdge, mesh, touchedIdx);
Toshihiro Shimizu 890ddd
				if (boundaryEdge)
Toshihiro Shimizu 890ddd
					boundary.setBoundaryVertex(touchedIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				goto cycle;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		buildEdge[it.m_idx] = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//DIAGNOSTICS_SET("Simplify | Vertex count (after simplify)", mesh.vertexCount());
Toshihiro Shimizu 890ddd
	//DIAGNOSTICS_SET("Simplify | Edges count (after simplify)", edges.size());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace tcg
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#endif // TCG_TRIANGULATE_HPP