normal.hpp 8.58 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
{
Sylvain Thery's avatar
Sylvain Thery committed
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
{
Sylvain Thery's avatar
Sylvain Thery committed
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
{
Sylvain Thery's avatar
Sylvain Thery committed
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
{
Sylvain Thery's avatar
Sylvain Thery committed
94 95
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

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())
		{
Sylvain Thery's avatar
Sylvain Thery committed
105 106
			VEC3 v1 = Algo::Geometry::vectorOutOfDart<PFP>(map, f.dart, position) ;
			VEC3 v2 = Algo::Geometry::vectorOutOfDart<PFP>(map, map.phi_1(f), position);
Sylvain Thery's avatar
Sylvain Thery committed
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
{
Sylvain Thery's avatar
Sylvain Thery committed
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
Sylvain Thery committed
138 139
//		if(!f.isMarked(*it) && map.isBoundaryIncidentFace(*it))
		if (!f.isMarked(*it) && (map.isBoundaryMarked<3>(map.phi3(*it))))
140 141 142 143 144
		{
			f.mark(*it);
			VEC3 n = faceNormal<PFP>(map, *it, position);
			if(!n.hasNan())
			{
Sylvain Thery's avatar
Sylvain Thery committed
145 146
				VEC3 v1 = Algo::Geometry::vectorOutOfDart<PFP>(map, *it, position);
				VEC3 v2 = Algo::Geometry::vectorOutOfDart<PFP>(map, map.phi_1(*it), position);
147 148 149 150 151 152 153 154 155 156
				n *= convexFaceArea<PFP>(map, *it, position) / (v1.norm2() * v2.norm2());
				N += n ;
			}
		}
	}

	N.normalize() ;
	return N ;
}

157
template <typename PFP, typename V_ATT, typename F_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
158
void computeNormalFaces(typename PFP::MAP& map, const V_ATT& position, F_ATT& face_normal)
Pierre Kraemer's avatar
Pierre Kraemer committed
159
{
Sylvain Thery's avatar
Sylvain Thery committed
160 161 162
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(F_ATT, FACE);

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

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

175
template <typename PFP, typename V_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
176
void computeNormalVertices(typename PFP::MAP& map, const V_ATT& position, V_ATT& normal)
Pierre Kraemer's avatar
Pierre Kraemer committed
177
{
Sylvain Thery's avatar
Sylvain Thery committed
178 179
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);

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

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

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

197
	typedef typename V_ATT::DATA_TYPE VEC3 ;
198

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

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

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

224 225 226
	return a ;
}

227
template <typename PFP, typename V_ATT, typename E_ATT>
Sylvain Thery's avatar
Sylvain Thery committed
228
void computeAnglesBetweenNormalsOnEdges(typename PFP::MAP& map, const V_ATT& position, E_ATT& angles)
229
{
Sylvain Thery's avatar
Sylvain Thery committed
230 231 232
	CHECK_ATTRIBUTEHANDLER_ORBIT(V_ATT, VERTEX);
	CHECK_ATTRIBUTEHANDLER_ORBIT(E_ATT, EDGE);

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

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

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

namespace Parallel
{

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

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

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

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

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

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

} // namespace Parallel


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

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

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

} // namespace CGoGN