normal.hpp 7.83 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

31 32
#include "Algo/Parallel/parallel_foreach.h"

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

namespace CGoGN
{

namespace Algo
{

41 42 43
namespace Surface
{

Pierre Kraemer's avatar
Pierre Kraemer committed
44 45 46
namespace Geometry
{

47
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
48
typename V_ATT::DATA_TYPE triangleNormal(typename PFP::MAP& map, Face f, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
49
{
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
	typedef typename V_ATT::DATA_TYPE VEC3;
Pierre Kraemer's avatar
Pierre Kraemer committed
63 64 65 66 67 68 69 70 71 72 73 74 75
	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;
76 77
}

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

87
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
88
typename V_ATT::DATA_TYPE vertexNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
Pierre Kraemer's avatar
Pierre Kraemer committed
89
{
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
			n *= convexFaceArea<PFP>(map, f, position) / (v1.norm2() * v2.norm2()) ;
			N += n ;
Pierre Kraemer's avatar
Pierre Kraemer committed
103
		}
Pierre Kraemer's avatar
Pierre Kraemer committed
104
	});
105

Pierre Kraemer's avatar
Pierre Kraemer committed
106 107 108 109
	N.normalize() ;
	return N ;
}

110
template<typename PFP, typename V_ATT>
Pierre Kraemer's avatar
Pierre Kraemer committed
111
typename V_ATT::DATA_TYPE vertexBorderNormal(typename PFP::MAP& map, Vertex v, const V_ATT& position)
112 113 114
{
	assert(map.dimension() == 3);

115
	typedef typename V_ATT::DATA_TYPE VEC3 ;
116 117

	VEC3 N(0) ;
118

119
	std::vector<Dart> faces;
120 121
	faces.reserve(16);
	map.foreach_dart_of_vertex(v, [&] (Dart d) { faces.push_back(d); });
122

123
	CellMarker<typename PFP::MAP, FACE> f(map);
124 125 126

	for(std::vector<Dart>::iterator it = faces.begin() ; it != faces.end() ; ++it)
	{
Sylvain Thery's avatar
Tutos  
Sylvain Thery committed
127
		if(!f.isMarked(*it) && map.isBoundaryIncidentFace(*it))
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
		{
			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 ;
}

145 146
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
147
{
148
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread==0))
Sylvain Thery's avatar
Sylvain Thery committed
149
	{
150
		Parallel::computeNormalFaces<PFP,V_ATT,F_ATT>(map,position,face_normal);
Sylvain Thery's avatar
Sylvain Thery committed
151 152 153
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
154 155 156
	foreach_cell<FACE>(map, [&] (Face f)
	{
		face_normal[f] = faceNormal<PFP>(map, f, position) ;
157 158
	},
	AUTO, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
159 160
}

161 162
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
163
{
164
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread==0))
Sylvain Thery's avatar
Sylvain Thery committed
165
	{
166
		Parallel::computeNormalVertices<PFP,V_ATT>(map,position,normal);
Sylvain Thery's avatar
Sylvain Thery committed
167 168 169
		return;
	}

Pierre Kraemer's avatar
Pierre Kraemer committed
170 171 172
	foreach_cell<VERTEX>(map, [&] (Vertex v)
	{
		normal[v] = vertexNormal<PFP>(map, v, position) ;
173 174
	},
	FORCE_CELL_MARKING, thread);
Pierre Kraemer's avatar
Pierre Kraemer committed
175 176
}

177

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

Pierre Kraemer's avatar
Pierre Kraemer committed
183
	if(map.isBoundaryEdge(e))
184 185
		return 0 ;

Pierre Kraemer's avatar
Pierre Kraemer committed
186 187 188 189 190 191 192
	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) ;
193 194
	typename PFP::REAL c = n1 * n2 ;
	typename PFP::REAL a(0) ;
195

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

208 209 210
	return a ;
}

211 212
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)
213
{
214
	if ((CGoGN::Parallel::NumberOfThreads > 1) && (thread==0))
Sylvain Thery's avatar
Sylvain Thery committed
215
	{
216
		Parallel::computeAnglesBetweenNormalsOnEdges<PFP,V_ATT,E_ATT>(map,position,angles);
Sylvain Thery's avatar
Sylvain Thery committed
217 218 219
		return;
	}

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

Sylvain Thery's avatar
Sylvain Thery committed
227

228

Sylvain Thery's avatar
Sylvain Thery committed
229 230 231 232
namespace Parallel
{

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

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

250

Sylvain Thery's avatar
Sylvain Thery committed
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
{
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) ;
257
	},true,AUTO);
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