normal.hpp 8.59 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
{
48 49
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

Pierre Kraemer's avatar
Pierre Kraemer committed
50 51 52 53 54
	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
55 56 57 58
	N.normalize() ;
	return N ;
}

59
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
60
typename V_ATT::DATA_TYPE newellNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
61
{
62 63
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

64
	typedef typename V_ATT::DATA_TYPE VEC3;
Pierre Kraemer's avatar
Pierre Kraemer committed
65 66 67 68 69 70 71 72 73 74 75 76 77
	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;
78 79
}

80
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
81
typename V_ATT::DATA_TYPE faceNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
82
{
83 84
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

Pierre Kraemer's avatar
Pierre Kraemer committed
85 86
	if(map.faceDegree(f) == 3)
		return triangleNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
87
	else
Pierre Kraemer's avatar
Pierre Kraemer committed
88
		return newellNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
89 90
}

91
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
92
typename V_ATT::DATA_TYPE vertexNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
93
{
94
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
95

96
	typedef typename V_ATT::DATA_TYPE VEC3 ;
Pierre Kraemer's avatar
Pierre Kraemer committed
97 98

	VEC3 N(0) ;
99

Pierre Kraemer's avatar
Pierre Kraemer committed
100
	foreach_incident2<FACE>(map, v, [&] (Face f)
Pierre Kraemer's avatar
Pierre Kraemer committed
101
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
102
		VEC3 n = faceNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
103 104
		if(!n.hasNan())
		{
Pierre Kraemer's avatar
Pierre Kraemer committed
105 106
			VEC3 v1 = vectorOutOfDart<PFP>(map, f.dart, position) ;
			VEC3 v2 = vectorOutOfDart<PFP>(map, map.phi_1(f), position) ;
107 108 109 110 111 112
			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
113
		}
Pierre Kraemer's avatar
Pierre Kraemer committed
114
	});
115

Pierre Kraemer's avatar
Pierre Kraemer committed
116 117 118 119
	N.normalize() ;
	return N ;
}

120
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
121
typename V_ATT::DATA_TYPE vertexBorderNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
122
{
123
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
124 125
	assert(map.dimension() == 3);

126
	typedef typename V_ATT::DATA_TYPE VEC3 ;
127 128

	VEC3 N(0) ;
129

130
	std::vector<Dart> faces;
131 132
	faces.reserve(16);
	map.foreach_dart_of_vertex(v, [&] (Dart d) { faces.push_back(d); });
133

134
	CellMarker<typename PFP::MAP, FACE> f(map);
135 136 137

	for(std::vector<Dart>::iterator it = faces.begin() ; it != faces.end() ; ++it)
	{
Sylvain Thery's avatar
Tutos  
Sylvain Thery committed
138
		if(!f.isMarked(*it) && map.isBoundaryIncidentFace(*it))
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
		{
			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 ;
}

156 157
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
158
{
159 160 161
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(F_ATT, FACE);

Pierre Kraemer's avatar
Pierre Kraemer committed
162
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
163
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
164
		Parallel::computeNormalFaces<PFP,V_ATT,F_ATT>(map, position, face_normal);
Sylvain Thery's avatar
Sylvain Thery committed
165 166 167
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
168 169 170
	foreach_cell<FACE>(map, [&] (Face f)
	{
		face_normal[f] = faceNormal<PFP>(map, f, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
171
	}, AUTO, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
172 173
}

174 175
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
176
{
177 178
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

Pierre Kraemer's avatar
Pierre Kraemer committed
179
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
180
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
181
		Parallel::computeNormalVertices<PFP,V_ATT>(map, position, normal);
Sylvain Thery's avatar
Sylvain Thery committed
182 183 184
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
185 186 187
	foreach_cell<VERTEX>(map, [&] (Vertex v)
	{
		normal[v] = vertexNormal<PFP>(map, v, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
188
	}, FORCE_CELL_MARKING, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
189 190
}

191
template <typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
192
typename PFP::REAL computeAngleBetweenNormalsOnEdge(typename PFP::MAP& map, Edge e, const V_ATT& position)
193
{
194 195
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

196
	typedef typename V_ATT::DATA_TYPE VEC3 ;
197

Pierre Kraemer's avatar
Pierre Kraemer committed
198
	if(map.isBoundaryEdge(e))
199 200
		return 0 ;

Pierre Kraemer's avatar
Pierre Kraemer committed
201 202 203 204 205 206 207
	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) ;
208 209
	typename PFP::REAL c = n1 * n2 ;
	typename PFP::REAL a(0) ;
210

211
	// the following trick is useful for avoiding NaNs (due to floating point errors)
212
	if (c > 0.5) a = asin(s) ;
213 214
	else
	{
215 216 217
		if(c < -1) c = -1 ;
		if (s >= 0) a = acos(c) ;
		else a = -acos(c) ;
218
	}
Pierre Kraemer's avatar
Pierre Kraemer committed
219
	//	if (isnan(a))
Pierre Kraemer's avatar
Pierre Kraemer committed
220
	if(a != a)
Pierre Kraemer's avatar
Pierre Kraemer committed
221 222
		std::cerr<< "Warning : computeAngleBetweenNormalsOnEdge returns NaN on edge " << v1 << "-" << v2 << std::endl ;

223 224 225
	return a ;
}

226 227
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)
228
{
229 230 231
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(E_ATT, EDGE);

Pierre Kraemer's avatar
Pierre Kraemer committed
232
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread == 0))
Sylvain Thery's avatar
Sylvain Thery committed
233
	{
Pierre Kraemer's avatar
Pierre Kraemer committed
234
		Parallel::computeAnglesBetweenNormalsOnEdges<PFP,V_ATT,E_ATT>(map, position, angles);
Sylvain Thery's avatar
Sylvain Thery committed
235 236 237
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
238 239 240
	foreach_cell<EDGE>(map, [&] (Edge e)
	{
		angles[e] = computeAngleBetweenNormalsOnEdge<PFP>(map, e, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
241
	}, AUTO, thread);
242 243
}

Sylvain Thery's avatar
Sylvain Thery committed
244 245 246 247 248

namespace Parallel
{

template <typename PFP, typename V_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
249
void computeNormalVertices(typename PFP::MAP& map, const V_ATT& position, V_ATT& normal)
Sylvain Thery's avatar
Sylvain Thery committed
250
{
251 252
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

Pierre Kraemer's avatar
Pierre Kraemer committed
253
	CGoGN::Parallel::foreach_cell<VERTEX>(map, [&] (Vertex v, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
254 255
	{
		normal[v] = vertexNormal<PFP>(map, v, position) ;
Pierre Kraemer's avatar
Pierre Kraemer committed
256
	}, FORCE_CELL_MARKING);
Sylvain Thery's avatar
Sylvain Thery committed
257 258 259
}

template <typename PFP, typename V_ATT, typename F_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
260
void computeNormalFaces(typename PFP::MAP& map, const V_ATT& position, F_ATT& normal)
Sylvain Thery's avatar
Sylvain Thery committed
261
{
262 263 264
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(F_ATT, FACE);

Pierre Kraemer's avatar
Pierre Kraemer committed
265
	CGoGN::Parallel::foreach_cell<FACE>(map, [&] (Face f, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
266 267
	{
		normal[f] = faceNormal<PFP>(map, f, position) ;
Sylvain Thery's avatar
Sylvain Thery committed
268
	});
Sylvain Thery's avatar
Sylvain Thery committed
269 270 271
}

template <typename PFP, typename V_ATT, typename E_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
272
void computeAnglesBetweenNormalsOnEdges(typename PFP::MAP& map, const V_ATT& position, E_ATT& angles)
Sylvain Thery's avatar
Sylvain Thery committed
273
{
274 275 276
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(E_ATT, EDGE);

Pierre Kraemer's avatar
Pierre Kraemer committed
277
	CGoGN::Parallel::foreach_cell<EDGE>(map,[&](Edge e, unsigned int /*thr*/)
Sylvain Thery's avatar
Sylvain Thery committed
278 279
	{
		angles[e] = computeAngleBetweenNormalsOnEdge<PFP>(map, e, position) ;
Sylvain Thery's avatar
Sylvain Thery committed
280
	});
Sylvain Thery's avatar
Sylvain Thery committed
281 282 283 284 285
}

} // namespace Parallel


Pierre Kraemer's avatar
Pierre Kraemer committed
286 287
} // namespace Geometry

Pierre Kraemer's avatar
Pierre Kraemer committed
288
} // namespace Surface
289

Pierre Kraemer's avatar
Pierre Kraemer committed
290 291 292
} // namespace Algo

} // namespace CGoGN