normal.hpp 7.92 KB
Newer Older
Pierre Kraemer's avatar
Pierre Kraemer committed
1 2 3
/*******************************************************************************
 * CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps  *
 * version 0.1                                                                  *
4
 * Copyright (C) 2009-2012, IGG Team, LSIIT, University of Strasbourg           *
Pierre Kraemer's avatar
Pierre Kraemer committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *                                                                              *
 * This library 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 library 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 library; if not, write to the Free Software Foundation,      *
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.           *
 *                                                                              *
20
 * Web site: http://cgogn.unistra.fr/                                           *
Pierre Kraemer's avatar
Pierre Kraemer committed
21 22 23 24 25 26
 * Contact information: cgogn@unistra.fr                                        *
 *                                                                              *
 *******************************************************************************/

#include "Algo/Geometry/basic.h"
#include "Algo/Geometry/area.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
27

28 29
#include "Topology/generic/traversor/traversorCell.h"
#include "Topology/generic/traversor/traversor2.h"
Pierre Kraemer's avatar
Pierre Kraemer committed
30

Pierre Kraemer's avatar
Pierre Kraemer committed
31 32 33 34 35 36 37 38
#include <cmath>

namespace CGoGN
{

namespace Algo
{

39 40 41
namespace Surface
{

Pierre Kraemer's avatar
Pierre Kraemer committed
42 43 44
namespace Geometry
{

45
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
46
typename V_ATT::DATA_TYPE triangleNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
47
{
Pierre Kraemer's avatar
Pierre Kraemer committed
48 49 50 51 52
	typename V_ATT::DATA_TYPE N = Geom::triangleNormal(
		position[f.dart],
		position[map.phi1(f)],
		position[map.phi_1(f)]
	) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
53 54 55 56
	N.normalize() ;
	return N ;
}

57
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
58
typename V_ATT::DATA_TYPE newellNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
59
{
60
	typedef typename V_ATT::DATA_TYPE VEC3;
Pierre Kraemer's avatar
Pierre Kraemer committed
61 62 63 64 65 66 67 68 69 70 71 72 73
	VEC3 N(0);

	foreach_incident2<VERTEX>(map, f, [&] (Vertex v)
	{
		const VEC3& P = position[v];
		const VEC3& Q = position[map.phi1(v)];
		N[0] += (P[1] - Q[1]) * (P[2] + Q[2]);
		N[1] += (P[2] - Q[2]) * (P[0] + Q[0]);
		N[2] += (P[0] - Q[0]) * (P[1] + Q[1]);
	});

	N.normalize();
	return N;
74 75
}

76
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
77
typename V_ATT::DATA_TYPE faceNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
78
{
Pierre Kraemer's avatar
Pierre Kraemer committed
79 80
	if(map.faceDegree(f) == 3)
		return triangleNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
81
	else
Pierre Kraemer's avatar
Pierre Kraemer committed
82
		return newellNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
83 84
}

85
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
86
typename V_ATT::DATA_TYPE vertexNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
87
{
88 89
	CHECK_ATTRIBUTEHANDER_ORBIT_TYPE(V_ATT,VERTEX);

90
	typedef typename V_ATT::DATA_TYPE VEC3 ;
Pierre Kraemer's avatar
Pierre Kraemer committed
91 92

	VEC3 N(0) ;
93

Pierre Kraemer's avatar
Pierre Kraemer committed
94
	foreach_incident2<FACE>(map, v, [&] (Face f)
Pierre Kraemer's avatar
Pierre Kraemer committed
95
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
96
		VEC3 n = faceNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
97 98
		if(!n.hasNan())
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
99 100
			VEC3 v1 = vectorOutOfDart<PFP>(map, f.dart, position) ;
			VEC3 v2 = vectorOutOfDart<PFP>(map, map.phi_1(f), position) ;
101 102 103 104 105 106
			typename VEC3::DATA_TYPE l = (v1.norm2() * v2.norm2());
			if (l > (typename VEC3::DATA_TYPE(0.0)) )
			{
				n *= convexFaceArea<PFP>(map, f, position) / l ;
				N += n ;
			}
Pierre Kraemer's avatar
Pierre Kraemer committed
107
		}
Pierre Kraemer's avatar
Pierre Kraemer committed
108
	});
109

Pierre Kraemer's avatar
Pierre Kraemer committed
110 111 112 113
	N.normalize() ;
	return N ;
}

114 115


116
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
117
typename V_ATT::DATA_TYPE vertexBorderNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
118 119 120
{
	assert(map.dimension() == 3);

121
	typedef typename V_ATT::DATA_TYPE VEC3 ;
122 123

	VEC3 N(0) ;
124

125
	std::vector<Dart> faces;
126 127
	faces.reserve(16);
	map.foreach_dart_of_vertex(v, [&] (Dart d) { faces.push_back(d); });
128

129
	CellMarker<typename PFP::MAP, FACE> f(map);
130 131 132

	for(std::vector<Dart>::iterator it = faces.begin() ; it != faces.end() ; ++it)
	{
Sylvain Thery's avatar
Tutos  
Sylvain Thery committed
133
		if(!f.isMarked(*it) && map.isBoundaryIncidentFace(*it))
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
		{
			f.mark(*it);
			VEC3 n = faceNormal<PFP>(map, *it, position);
			if(!n.hasNan())
			{
				VEC3 v1 = vectorOutOfDart<PFP>(map, *it, position);
				VEC3 v2 = vectorOutOfDart<PFP>(map, map.phi_1(*it), position);
				n *= convexFaceArea<PFP>(map, *it, position) / (v1.norm2() * v2.norm2());
				N += n ;
			}
		}
	}

	N.normalize() ;
	return N ;
}

151 152
template <typename PFP, typename V_ATT, typename F_ATT>
void computeNormalFaces(typename PFP::MAP& map, const V_ATT& position, F_ATT& face_normal, unsigned int thread)
Pierre Kraemer's avatar
Pierre Kraemer committed
153
{
Pierre Kraemer's avatar
Pierre Kraemer committed
154
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
155
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
156
		Parallel::computeNormalFaces<PFP,V_ATT,F_ATT>(map, position, face_normal);
Sylvain Thery's avatar
Sylvain Thery committed
157 158 159
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
160 161 162
	foreach_cell<FACE>(map, [&] (Face f)
	{
		face_normal[f] = faceNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
163
	}, AUTO, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
164 165
}

166 167
template <typename PFP, typename V_ATT>
void computeNormalVertices(typename PFP::MAP& map, const V_ATT& position, V_ATT& normal, unsigned int thread)
Pierre Kraemer's avatar
Pierre Kraemer committed
168
{
Pierre Kraemer's avatar
Pierre Kraemer committed
169
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
170
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
171
		Parallel::computeNormalVertices<PFP,V_ATT>(map, position, normal);
Sylvain Thery's avatar
Sylvain Thery committed
172 173 174
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
175 176 177
	foreach_cell<VERTEX>(map, [&] (Vertex v)
	{
		normal[v] = vertexNormal<PFP>(map, v, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
178
	}, FORCE_CELL_MARKING, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
179 180
}

181
template <typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
182
typename PFP::REAL computeAngleBetweenNormalsOnEdge(typename PFP::MAP& map, Edge e, const V_ATT& position)
183
{
184
	typedef typename V_ATT::DATA_TYPE VEC3 ;
185

Pierre Kraemer's avatar
Pierre Kraemer committed
186
	if(map.isBoundaryEdge(e))
187 188
		return 0 ;

Pierre Kraemer's avatar
Pierre Kraemer committed
189 190 191 192 193 194 195
	Vertex v1(e.dart);
	Vertex v2 = map.phi2(e) ;
	const VEC3 n1 = faceNormal<PFP>(map, Face(v1), position) ;
	const VEC3 n2 = faceNormal<PFP>(map, Face(v2), position) ;
	VEC3 edge = position[v2] - position[v1] ;
	edge.normalize() ;
	typename PFP::REAL s = edge * (n1 ^ n2) ;
196 197
	typename PFP::REAL c = n1 * n2 ;
	typename PFP::REAL a(0) ;
198

199
	// the following trick is useful for avoiding NaNs (due to floating point errors)
200
	if (c > 0.5) a = asin(s) ;
201 202
	else
	{
203 204 205
		if(c < -1) c = -1 ;
		if (s >= 0) a = acos(c) ;
		else a = -acos(c) ;
206
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
207
	//	if (isnan(a))
Pierre Kraemer's avatar
Pierre Kraemer committed
208
	if(a != a)
Pierre Kraemer's avatar
Pierre Kraemer committed
209 210
		std::cerr<< "Warning : computeAngleBetweenNormalsOnEdge returns NaN on edge " << v1 << "-" << v2 << std::endl ;

211 212 213
	return a ;
}

214 215
template <typename PFP, typename V_ATT, typename E_ATT>
void computeAnglesBetweenNormalsOnEdges(typename PFP::MAP& map, const V_ATT& position, E_ATT& angles, unsigned int thread)
216
{
Pierre Kraemer's avatar
Pierre Kraemer committed
217
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
218
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
219
		Parallel::computeAnglesBetweenNormalsOnEdges<PFP,V_ATT,E_ATT>(map, position, angles);
Sylvain Thery's avatar
Sylvain Thery committed
220 221 222
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
223 224 225
	foreach_cell<EDGE>(map, [&] (Edge e)
	{
		angles[e] = computeAngleBetweenNormalsOnEdge<PFP>(map, e, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
226
	}, AUTO, thread);
227 228
}

Sylvain Thery's avatar
Sylvain Thery committed
229 230 231 232 233

namespace Parallel
{

template <typename PFP, typename V_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
234
void computeNormalVertices(typename PFP::MAP& map, const V_ATT& position, V_ATT& normal)
Sylvain Thery's avatar
Sylvain Thery committed
235
{
Pierre Kraemer's avatar
Pierre Kraemer committed
236
	CGoGN::Parallel::foreach_cell<VERTEX>(map, [&] (Vertex v, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
237 238
	{
		normal[v] = vertexNormal<PFP>(map, v, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
239
	}, FORCE_CELL_MARKING);
Sylvain Thery's avatar
Sylvain Thery committed
240 241 242
}

template <typename PFP, typename V_ATT, typename F_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
243
void computeNormalFaces(typename PFP::MAP& map, const V_ATT& position, F_ATT& normal)
Sylvain Thery's avatar
Sylvain Thery committed
244
{
Pierre Kraemer's avatar
Pierre Kraemer committed
245
	CGoGN::Parallel::foreach_cell<FACE>(map, [&] (Face f, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
246 247
	{
		normal[f] = faceNormal<PFP>(map, f, position) ;
Sylvain Thery's avatar
Sylvain Thery committed
248
	});
Sylvain Thery's avatar
Sylvain Thery committed
249 250 251
}

template <typename PFP, typename V_ATT, typename E_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
252
void computeAnglesBetweenNormalsOnEdges(typename PFP::MAP& map, const V_ATT& position, E_ATT& angles)
Sylvain Thery's avatar
Sylvain Thery committed
253
{
Pierre Kraemer's avatar
Pierre Kraemer committed
254
	CGoGN::Parallel::foreach_cell<EDGE>(map,[&](Edge e, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
255 256
	{
		angles[e] = computeAngleBetweenNormalsOnEdge<PFP>(map, e, position) ;
Sylvain Thery's avatar
Sylvain Thery committed
257
	});
Sylvain Thery's avatar
Sylvain Thery committed
258 259 260 261 262
}

} // namespace Parallel


Pierre Kraemer's avatar
Pierre Kraemer committed
263 264
} // namespace Geometry

Pierre Kraemer's avatar
Pierre Kraemer committed
265
} // namespace Surface
266

Pierre Kraemer's avatar
Pierre Kraemer committed
267 268 269
} // namespace Algo

} // namespace CGoGN