geometry.cpp 58.4 KB
Newer Older
Kirill Terekhov's avatar
Kirill Terekhov committed
1 2
#include "inmost.h"
#if defined(USE_MESH)
Kirill Terekhov's avatar
Kirill Terekhov committed
3
#include <deque>
Kirill Terekhov's avatar
Kirill Terekhov committed
4
using namespace std;
Kirill Terekhov's avatar
Kirill Terekhov committed
5

Kirill Terekhov's avatar
Kirill Terekhov committed
6 7 8 9 10
const std::string normal_name = "PROTECTED_GEOM_UTIL_NORMAL";
const std::string measure_name = "PROTECTED_GEOM_UTIL_MEASURE";
const std::string centroid_name = "PROTECTED_GEOM_UTIL_CENTROID";
const std::string barycenter_name = "PROTECTED_GEOM_UTIL_BARYCENTER";

Kirill Terekhov's avatar
Kirill Terekhov committed
11 12
namespace INMOST
{
Kirill Terekhov's avatar
Kirill Terekhov committed
13 14 15 16 17 18 19 20 21 22
	typedef struct orient_face_t
	{
		Edge bridge;
		Node first;
		Face face;
		orient_face_t(Edge _bridge, Node _first, Face _face)
		:bridge(_bridge),first(_first),face(_face)
		{
		}
	} orient_face;
Kirill Terekhov's avatar
Kirill Terekhov committed
23

Kirill Terekhov's avatar
Kirill Terekhov committed
24 25 26 27 28 29
	__INLINE static void vec_diff(const Storage::real * vecin1, const Storage::real * vecin2, Storage::real * vecout, unsigned int size)
	{
		for(unsigned int i = 0; i < size; i++)
			vecout[i] = vecin1[i] - vecin2[i];
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
30 31 32 33 34 35 36
	__INLINE static void vec_diff(const Storage::real_array & vecin1,const Storage::real_array & vecin2, Storage::real * vecout, unsigned int size)
	{
		for(unsigned int i = 0; i < size; i++)
			vecout[i] = vecin1[i] - vecin2[i];
	}
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
	__INLINE static void vec_cross_product(const Storage::real * vecin1, const Storage::real * vecin2, Storage::real * vecout)
	{
		Storage::real temp[3];
		temp[0] = vecin1[1]*vecin2[2] - vecin1[2]*vecin2[1];
		temp[1] = vecin1[2]*vecin2[0] - vecin1[0]*vecin2[2];
		temp[2] = vecin1[0]*vecin2[1] - vecin1[1]*vecin2[0];
		vecout[0] = temp[0];
		vecout[1] = temp[1];
		vecout[2] = temp[2];
	}
	
	__INLINE static Storage::real vec_dot_product(const Storage::real * vecin1,const Storage::real * vecin2, unsigned int size)
	{
		Storage::real ret = 0;
		for(unsigned int i = 0; i < size; i++)
			ret += vecin1[i]*vecin2[i];
		return ret;
	}
	
	__INLINE static Storage::real vec_len2(const Storage::real * vecin, unsigned int size)
	{
		return vec_dot_product(vecin,vecin,size);
	}
	
	__INLINE static Storage::real vec_len(const Storage::real * vecin, unsigned int size)
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
63
		return ::sqrt(vec_len2(vecin,size));
Kirill Terekhov's avatar
Kirill Terekhov committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
	}
	
	__INLINE static Storage::real det3d(Storage::real a, Storage::real b, Storage::real c,
	                         Storage::real d, Storage::real e, Storage::real f,
	                         Storage::real g, Storage::real h, Storage::real i ) 
	{
		return a*e*i - c*e*g + b*f*g - a*f*h + c*d*h - b*d*i;
	}
	
	__INLINE static Storage::real det3v(const Storage::real * x,const Storage::real * y,const Storage::real * z) 
	{
		return det3d(x[0], x[1], x[2],  y[0], y[1], y[2],  z[0], z[1], z[2]);
	}
	
	__INLINE static Storage::real det4v(const Storage::real * w, const Storage::real * x, const Storage::real * y, const Storage::real * z) 
	{
		return det3d(x[0]-w[0], x[1]-w[1], x[2]-w[2],  y[0]-w[0], y[1]-w[1], y[2]-w[2],  z[0]-w[0], z[1]-w[1], z[2]-w[2]);
	}	
	
	
	__INLINE static Storage::real vec_normalize(Storage::real * vecin, unsigned int size)
	{
		Storage::real len = 0;
		for(unsigned int i = 0; i < size; i++)
			len += vecin[i]*vecin[i];
Kirill Terekhov's avatar
Kirill Terekhov committed
89
		len = ::sqrt(len);
Kirill Terekhov's avatar
Kirill Terekhov committed
90 91 92 93 94 95
		for(unsigned int i = 0; i < size; i++)
			vecin[i] /= len;
		return len;
	}
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
96
	ElementArray<Cell> Cell::NeighbouringCells() const
Kirill Terekhov's avatar
Kirill Terekhov committed
97
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
98 99 100
		ElementArray<Cell> ret(GetMeshLink());
		ElementArray<Face> faces = getFaces();
		for(ElementArray<Face>::iterator f = faces.begin(); f != faces.end(); f++)
Kirill Terekhov's avatar
Kirill Terekhov committed
101
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
102 103
			Cell c = Neighbour(f->self());
			if( c.isValid() ) ret.push_back(c);
Kirill Terekhov's avatar
Kirill Terekhov committed
104 105 106 107 108
		}
		return ret;
	}
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
109
	Cell Cell::Neighbour(Face f) const
Kirill Terekhov's avatar
Kirill Terekhov committed
110
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
111 112
		Cell b = f->BackCell();
		if( b == self() )
Kirill Terekhov's avatar
Kirill Terekhov committed
113 114 115 116
			return f->FrontCell();
		return b;
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
117
	bool Cell::Inside(const Storage::real * point) const//check for 2d case
Kirill Terekhov's avatar
Kirill Terekhov committed
118
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
119
		Mesh * mesh = GetMeshLink();
Kirill Terekhov's avatar
Kirill Terekhov committed
120 121 122
		integer dim = GetElementDimension();
		if( dim == 3 )
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
123 124 125 126 127 128 129 130 131 132 133
			/*
			tiny_map<HandleType,real,16> hits;
			real ray[3];
			ray[0] = rand()/(real)RAND_MAX;
			ray[1] = rand()/(real)RAND_MAX;
			ray[2] = rand()/(real)RAND_MAX;
			CastRay(point,ray,hits);
			if( hits.size()%2 == 0 ) return false;
			return true;
			 */
			assert(mesh->GetDimensions() == 3);
Kirill Terekhov's avatar
Kirill Terekhov committed
134 135 136
			integer vp = 0;
			integer vm = 0;
			integer vz = 0;
Kirill Terekhov's avatar
Kirill Terekhov committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
			real eps = mesh->GetEpsilon();
			real c,d, fcnt[3];
			real_array v1,v2;
			ElementArray<Face> data = getFaces();
			Face cur = data[0];
			MarkerType mrk = mesh->CreatePrivateMarker();
			MarkerType rev = mesh->CreatePrivateMarker(); //reverse orientation
			data.SetPrivateMarker(mrk); //0-th face orientation is default
			cur->RemPrivateMarker(mrk);
			Node n1,n2; //to retrive edge
			bool reverse = false; //reverse orientation in considered face
			std::deque< orient_face > stack; //edge and first node and face for visiting
			//todo: can do faster by retriving edges and going over their nodes
			//should not use FindSharedAdjacency
			ElementArray<Edge> edges = cur->getEdges();
			do
			{
				//figure out starting node order
				if( edges[0]->getBeg() == edges[1]->getBeg() ||
				   edges[0]->getBeg() == edges[1]->getEnd() )
				{
					n1 = edges[0]->getEnd();
					n2 = edges[0]->getBeg();
				}
				else
				{
					n1 = edges[0]->getBeg();
					n2 = edges[0]->getEnd();
				}
				//schedule unvisited adjacent faces
				for(unsigned j = 0; j < edges.size(); j++)
				{
					//schedule face adjacent to considered edge
					ElementArray<Face> adjacent = edges[j]->getFaces(mrk);
					assert(adjacent.size() <= 1);
					if( !adjacent.empty() && adjacent[0].GetPrivateMarker(mrk))
					{
						adjacent.RemPrivateMarker(mrk);
						stack.push_back(orient_face(edges[j],reverse ? n2 : n1,adjacent[0]));
					}
					//update edge nodes
					n1 = n2; //current end is new begin
					//find new end
					if( n2 == edges[(j+1)%edges.size()]->getBeg() )
						n2 = edges[(j+1)%edges.size()]->getEnd();
					else
						n2 = edges[(j+1)%edges.size()]->getBeg();
				}
				if( stack.empty() ) break;
				//get entry from stack
				orient_face r = stack.front();
				//remove face from stack
				stack.pop_front();
				//retrive edges for new face
				edges = r.face->getEdges();
				reverse = false;
				//figure out starting node order
				if( edges[0]->getBeg() == edges[1]->getBeg() ||
				   edges[0]->getBeg() == edges[1]->getEnd() )
				{
					n1 = edges[0]->getEnd();
					n2 = edges[0]->getBeg();
				}
				else
				{
					n1 = edges[0]->getBeg();
					n2 = edges[0]->getEnd();
				}
				//find out common edge orientation
				for(unsigned j = 0; j < edges.size(); j++)
				{
					if( edges[j] == r.bridge ) //found the edge
					{
						//reverse ordering on this face
						if( r.first == n1 )
						{
							r.face->SetPrivateMarker(rev);
							reverse = true;
						}
						break;
					}
					//update edge nodes
					n1 = n2; //current end is new begin
					//find new end
					if( n2 == edges[(j+1)%edges.size()]->getBeg() )
						n2 = edges[(j+1)%edges.size()]->getEnd();
					else
						n2 = edges[(j+1)%edges.size()]->getBeg();
				}
			} while(true);
			data.RemPrivateMarker(mrk);
			mesh->ReleasePrivateMarker(mrk);
			for(ElementArray<Face>::size_type f = 0; f < data.size(); f++)
Kirill Terekhov's avatar
Kirill Terekhov committed
230 231
			{
				d = 0.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
232 233 234 235 236 237 238 239 240 241 242 243 244
				data[f]->Centroid(fcnt);
				ElementArray<Node> nodes = data[f]->getNodes();
				v1 = nodes[0].Coords();
				for (ElementArray<Node>::size_type i=0; i<nodes.size(); i++)
				{
					v2 = nodes[(i+1)%nodes.size()].Coords();
					d += c = det4v(point, fcnt, v1.data(), v2.data());
					v1.swap(v2);
				}
				//if(!data[f]->FaceOrientedOutside(self()))
				if( data[f]->GetPrivateMarker(rev) )
					c = -1.0;
				else
Kirill Terekhov's avatar
Kirill Terekhov committed
245
					c = 1.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
246 247 248 249 250
				if(c*d > eps)
					vp++;
				else if(c*d < -eps)
					vm++;
				else
Kirill Terekhov's avatar
Kirill Terekhov committed
251 252
					vz++;
			}
Kirill Terekhov's avatar
Kirill Terekhov committed
253 254
			data.RemPrivateMarker(rev);
			mesh->ReleasePrivateMarker(rev);
Kirill Terekhov's avatar
Kirill Terekhov committed
255
			if(vp*vm > 0) return false;
Kirill Terekhov's avatar
Kirill Terekhov committed
256
			else if( vz == 0 ) return true;
Kirill Terekhov's avatar
Kirill Terekhov committed
257
			else return true;
Kirill Terekhov's avatar
Kirill Terekhov committed
258 259
		}
		else
Kirill Terekhov's avatar
Kirill Terekhov committed
260
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
261
			int mdim = mesh->GetDimensions();
Kirill Terekhov's avatar
Kirill Terekhov committed
262 263 264 265 266 267 268 269
			assert(mdim <= 3);
			Storage::real data[9][3];
			if( mdim < 3 )
			{
				memset(data,0,sizeof(Storage::real)*9*3);
			}
			Centroid(data[0]);
			ElementArray<Node> nodes = getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
270
			for(int i = 0; i < static_cast<int>(nodes.size()); i++)
Kirill Terekhov's avatar
Kirill Terekhov committed
271 272 273 274 275 276 277 278 279 280
			{
				int j = (i+1)%nodes.size();
				nodes[i].Centroid(data[1]);
				nodes[j].Centroid(data[2]);
				vec_diff(point,data[0],data[3],mdim);
				vec_diff(point,data[1],data[4],mdim);
				vec_diff(point,data[2],data[5],mdim);
				vec_cross_product(data[3],data[4],data[6]);
				vec_cross_product(data[4],data[5],data[7]);
				vec_cross_product(data[5],data[3],data[8]);
Kirill Terekhov's avatar
Kirill Terekhov committed
281
				
Kirill Terekhov's avatar
Kirill Terekhov committed
282
				if( vec_dot_product(data[6],data[7],mdim) >= 0 &&
Kirill Terekhov's avatar
Kirill Terekhov committed
283 284
				   vec_dot_product(data[7],data[8],mdim) >= 0 &&
				   vec_dot_product(data[6],data[8],mdim) >= 0 )
Kirill Terekhov's avatar
Kirill Terekhov committed
285 286 287
					return true; //inside one of the triangles
			}
			return false;
Kirill Terekhov's avatar
Kirill Terekhov committed
288 289 290 291
		}
	}
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
292
	void Face::UnitNormal(real * nrm) const
Kirill Terekhov's avatar
Kirill Terekhov committed
293
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
294 295 296
		Mesh * m = GetMeshLink();
		m->GetGeometricData(GetHandle(),NORMAL,nrm); 
		integer dim = m->GetDimensions();
Kirill Terekhov's avatar
Kirill Terekhov committed
297
		real    l   = ::sqrt(vec_dot_product(nrm,nrm,dim)); 
Kirill Terekhov's avatar
Kirill Terekhov committed
298
		if(::fabs(l) > m->GetEpsilon()) 
Kirill Terekhov's avatar
Kirill Terekhov committed
299 300
		{
			for(integer i = 0; i < dim; i++) 
Kirill Terekhov's avatar
Kirill Terekhov committed
301
				nrm[i] /= l; 
Kirill Terekhov's avatar
Kirill Terekhov committed
302
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
303 304
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
305
	void Face::OrientedNormal(Cell c, Storage::real * nrm) const
Kirill Terekhov's avatar
Kirill Terekhov committed
306 307
	{
		Normal(nrm); 
Kirill Terekhov's avatar
Kirill Terekhov committed
308 309 310 311
		if( !FaceOrientedOutside(c) )
		{
			integer dim = GetMeshLink()->GetDimensions();
			for(integer i = 0; i < dim; i++) 
Kirill Terekhov's avatar
Kirill Terekhov committed
312
				nrm[i] = -nrm[i];
Kirill Terekhov's avatar
Kirill Terekhov committed
313
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
314 315 316
	}
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
317
	void Face::OrientedUnitNormal(Cell c, Storage::real * nrm) const
Kirill Terekhov's avatar
Kirill Terekhov committed
318 319 320
	{
		UnitNormal(nrm); 
		if( !FaceOrientedOutside(c) ) 
Kirill Terekhov's avatar
Kirill Terekhov committed
321 322 323
		{
			integer dim = GetMeshLink()->GetDimensions();
			for(integer i = 0; i < dim; i++) 
Kirill Terekhov's avatar
Kirill Terekhov committed
324
				nrm[i] = -nrm[i];
Kirill Terekhov's avatar
Kirill Terekhov committed
325
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
326 327 328 329
	}
	
	
	
Kirill Terekhov's avatar
Kirill Terekhov committed
330
	bool Mesh::TestClosure(const HandleType * elements, integer num) const
Kirill Terekhov's avatar
Kirill Terekhov committed
331
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
332 333 334
		integer i;
		tiny_map<HandleType,int,64> e_visit;
		tiny_map<HandleType,int,64>::iterator it;
Kirill Terekhov's avatar
Kirill Terekhov committed
335 336 337 338
		if( !HideMarker() )
		{
			for(i = 0; i < num; i++)
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
339 340 341
				Element::adj_type const & lc = LowConn(elements[i]);
				for(Element::adj_type::size_type jt = 0; jt < lc.size(); jt++)
					e_visit[lc[jt]]++;
Kirill Terekhov's avatar
Kirill Terekhov committed
342 343 344 345
			}
		}
		else
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
346
			for(i = 0; i < num; i++) if( !GetMarker(elements[i],HideMarker()) )
Kirill Terekhov's avatar
Kirill Terekhov committed
347
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
348 349 350 351 352 353
				Element::adj_type const & lc = LowConn(elements[i]);
				for(Element::adj_type::size_type jt = 0; jt < lc.size(); jt++) 
				{
					if( !GetMarker(lc[jt],HideMarker()) ) 
						e_visit[lc[jt]]++;
				}
Kirill Terekhov's avatar
Kirill Terekhov committed
354 355 356 357 358 359 360
			}
		}
		for(it = e_visit.begin(); it != e_visit.end(); it++)
			if( it->second != 2 ) return false;
		return true;
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
361
	Element::GeometricType Mesh::ComputeGeometricType(ElementType etype, const HandleType * lc, INMOST_DATA_ENUM_TYPE s) const
Kirill Terekhov's avatar
Kirill Terekhov committed
362 363
	{
		Element::GeometricType ret = Element::Unset;
364
		int dmax = -1, dmin = 4;
Kirill Terekhov's avatar
Kirill Terekhov committed
365 366 367 368 369 370 371 372 373 374 375
		if( s == 0 && etype != NODE) return ret;
		switch(etype)
		{
			case NODE: ret = Element::Vertex; break;
			case EDGE:
				if( s == 1 )
					ret = Element::Vertex;
				else if( s == 2 )
					ret = Element::Line;
				break;
			case FACE:
376 377 378 379 380 381 382 383
				for (INMOST_DATA_ENUM_TYPE k = 0; k < s; ++k)
				{
					int d = Element::GetGeometricDimension(GetGeometricType(lc[k]));
					if (dmax < d) dmax = d;
					if (dmin > d) dmin = d;
				}
				if (dmax != dmin)
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
384
					ret = Element::MultiLine;
385 386
				}
				else if( dmax == 0 )
Kirill Terekhov's avatar
Kirill Terekhov committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404
				{ 
					ret = Element::Line;
				}
				else
				{
					if( !GetTopologyCheck(NEED_TEST_CLOSURE) || TestClosure(lc,s) )
					{
						if( s == 3 )
							ret = Element::Tri;
						else if( s == 4 )
							ret = Element::Quad;
						else
							ret = Element::Polygon;
					}
					else ret = Element::MultiLine;
				}
				break;
			case CELL:
405 406 407 408 409 410 411 412 413 414 415
				for (INMOST_DATA_ENUM_TYPE k = 0; k < s; ++k)
				{
					int d = Element::GetGeometricDimension(GetGeometricType(lc[k]));
					if (dmax < d) dmax = d;
					if (dmin > d) dmin = d;
				}
				if (dmax != dmin)
				{
					ret = Element::MultiPolygon;
				}
				else if(  dmax == 1 )
Kirill Terekhov's avatar
Kirill Terekhov committed
416
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
417
					if( !GetTopologyCheck(NEED_TEST_CLOSURE) || TestClosure(lc,s) )
Kirill Terekhov's avatar
Kirill Terekhov committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
					{
						if( s == 3 )
							ret = Element::Tri;
						else if( s == 4 )
							ret = Element::Quad;
						else
							ret = Element::Polygon;
					}
					else ret = Element::MultiLine;
				}
				else 
				{
					if( !GetTopologyCheck(NEED_TEST_CLOSURE) ||  TestClosure(lc,s) )
					{
						//test c_faces closure, if no closure, set as MultiPolygon
						INMOST_DATA_ENUM_TYPE quads = 0,tris = 0,i;
						for(i = 0; i < s; i++)
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
436
							if( GetGeometricType(lc[i]) == Element::Tri )
Kirill Terekhov's avatar
Kirill Terekhov committed
437
								tris++;
Kirill Terekhov's avatar
Kirill Terekhov committed
438
							else if( GetGeometricType(lc[i]) == Element::Quad )
Kirill Terekhov's avatar
Kirill Terekhov committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
								quads++;
						}
						if( tris == 4 && s == 4 )
							ret = Element::Tet;
						else if( quads == 6 && s == 6 )
							ret = Element::Hex;
						else if( tris == 4 && quads == 1 && s == tris+quads)
							ret = Element::Pyramid;
						else if( quads == 3 && tris == 2 && s == tris+quads)
							ret = Element::Prism;
						else
							ret = Element::Polyhedron;
					}
					else ret = Element::MultiPolygon;
				}
				break;
			case ESET: ret = Element::Set; break;
		}
		return ret;
	}

Kirill Terekhov's avatar
Kirill Terekhov committed
460
	Storage::real Edge::Length() const 
Kirill Terekhov's avatar
Kirill Terekhov committed
461
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
		Storage::real ret; 
		GetMeshLink()->GetGeometricData(GetHandle(),MEASURE,&ret); 
		return ret;
	}

	Storage::real Face::Area() const 
	{
		real ret; 
		GetMeshLink()->GetGeometricData(GetHandle(),MEASURE,&ret); 
		return ret;
	}
	void Face::Normal(real * nrm) const 
	{
		GetMeshLink()->GetGeometricData(GetHandle(),NORMAL,nrm);
	}

	Storage::real Cell::Volume() const 
	{
		real ret; 
		GetMeshLink()->GetGeometricData(GetHandle(),MEASURE,&ret); 
		return ret;
	}

	void Element::ComputeGeometricType() const
	{
		GetMeshLink()->ComputeGeometricType(GetHandle());
Kirill Terekhov's avatar
Kirill Terekhov committed
488 489
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
490 491 492 493 494 495 496
	void Mesh::ComputeGeometricType(HandleType h) 
	{
		SetGeometricType(h,Element::Unset);
		Element::adj_type const & lc = LowConn(h);
		if( !lc.empty() )
			SetGeometricType(h,ComputeGeometricType(GetHandleElementType(h),lc.data(),static_cast<integer>(lc.size())));
	}
Kirill Terekhov's avatar
Kirill Terekhov committed
497
	
Kirill Terekhov's avatar
Kirill Terekhov committed
498
	void Mesh::RecomputeGeometricData(HandleType e)
Kirill Terekhov's avatar
Kirill Terekhov committed
499 500 501 502 503
	{
		//static std::map<Element *, int> numfixes;
		GeometricData d ;
		for(d = CENTROID; d <= NORMAL; d++) // first compute centroids and normals 
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
504
			if( HaveGeometricData(d,GetHandleElementType(e)) ) //compute centroid first
Kirill Terekhov's avatar
Kirill Terekhov committed
505 506
			{
				Tag t = GetGeometricTag(d);
Kirill Terekhov's avatar
Kirill Terekhov committed
507 508
				Storage::real * a = static_cast<Storage::real *>(MGetDenseLink(e,t));
				HideGeometricData(d,GetHandleElementType(e));
Kirill Terekhov's avatar
Kirill Terekhov committed
509
				GetGeometricData(e,d,a);
Kirill Terekhov's avatar
Kirill Terekhov committed
510
				ShowGeometricData(d,GetHandleElementType(e));
Kirill Terekhov's avatar
Kirill Terekhov committed
511 512 513 514
			}
		}


Kirill Terekhov's avatar
Kirill Terekhov committed
515
		if( GetHandleElementType(e) == CELL && HaveGeometricData(ORIENTATION,FACE)) //then correct the normal
Kirill Terekhov's avatar
Kirill Terekhov committed
516
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
517 518 519
			Element::adj_type & lc = LowConn(e);
			for(Element::adj_type::iterator it = lc.begin(); it != lc.end(); ++it)
				if( !GetMarker(*it,HideMarker()) && HighConn(*it).size() == 1 )
Kirill Terekhov's avatar
Kirill Terekhov committed
520
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
521
					Face(this,*it)->FixNormalOrientation();
Kirill Terekhov's avatar
Kirill Terekhov committed
522 523 524 525
				}
		}
		for(d = MEASURE; d <= BARYCENTER; d++) // compute the rest
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
526
			if( HaveGeometricData(d,GetHandleElementType(e)) )
Kirill Terekhov's avatar
Kirill Terekhov committed
527 528
			{
				Tag t = GetGeometricTag(d);
Kirill Terekhov's avatar
Kirill Terekhov committed
529 530
				Storage::real * a = static_cast<Storage::real *>(MGetDenseLink(e,t));
				HideGeometricData(d,GetHandleElementType(e));
Kirill Terekhov's avatar
Kirill Terekhov committed
531
				GetGeometricData(e,d,a);
Kirill Terekhov's avatar
Kirill Terekhov committed
532
				ShowGeometricData(d,GetHandleElementType(e));
Kirill Terekhov's avatar
Kirill Terekhov committed
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
			}
		}
	}
	
	
	void Mesh::RemoveGeometricData(GeomParam table)
	{
		for(GeomParam::iterator it = table.begin(); it != table.end(); ++it)
		{
			if( it->first == MEASURE    ) 
			{
				if(measure_tag.isValid())    
					measure_tag    = DeleteTag(measure_tag   ,it->second);
				for(ElementType etype = EDGE; etype <= CELL; etype = etype << 1) if( etype & it->second) HideGeometricData(MEASURE,etype);
			}
			if( it->first == CENTROID   ) 
			{
				if(centroid_tag.isValid())   
					centroid_tag   = DeleteTag(centroid_tag  ,it->second);
				for(ElementType etype = EDGE; etype <= CELL; etype = etype << 1) if( etype & it->second) HideGeometricData(CENTROID,etype);
			}
			if( it->first == BARYCENTER ) 
			{
				if(barycenter_tag.isValid()) 
					barycenter_tag = DeleteTag(barycenter_tag,it->second);
				for(ElementType etype = EDGE; etype <= CELL; etype = etype << 1) if( etype & it->second) HideGeometricData(BARYCENTER,etype);
			}
			if( it->first == NORMAL     ) 
			{
				if(normal_tag.isValid())
					normal_tag     = DeleteTag(normal_tag    ,it->second);
				for(ElementType etype = FACE; etype <= CELL; etype = etype << 1) if( etype & it->second) HideGeometricData(NORMAL,etype);
			}
			if( it->first == ORIENTATION) 
				if( FACE & it->second) HideGeometricData(ORIENTATION,FACE);
		}
	}
	
	void Mesh::RestoreGeometricTags()
	{
		for(GeometricData gtype = MEASURE; gtype <= NORMAL; gtype++)
		{
			bool restore = false;
576
			for(ElementType etype = EDGE; etype <= CELL && !restore; etype = NextElementType(etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
577 578 579 580 581 582
				if( HaveGeometricData(gtype,etype) )
					restore = true;
			if( restore )
			{
				switch(gtype)
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
583 584 585 586
				case MEASURE:       measure_tag = GetTag(measure_name);    break;
				case CENTROID:     centroid_tag = GetTag(centroid_name);   break;
				case BARYCENTER: barycenter_tag = GetTag(barycenter_name); break;
				case NORMAL:         normal_tag = GetTag(normal_name);     break;
Kirill Terekhov's avatar
Kirill Terekhov committed
587 588 589 590
				}
			}
		}
	}
591

Kirill Terekhov's avatar
Kirill Terekhov committed
592 593
	void Mesh::RepairGeometricTags()
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
594
		if( HaveTag(measure_name) )
Kirill Terekhov's avatar
Kirill Terekhov committed
595
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
596
			measure_tag = GetTag(measure_name);
Kirill Terekhov's avatar
Kirill Terekhov committed
597 598 599 600
			for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
				if( measure_tag.isDefined(etype) && !HaveGeometricData(MEASURE,etype) )
					ShowGeometricData(MEASURE,etype);
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
601
		if( HaveTag(centroid_name) )
Kirill Terekhov's avatar
Kirill Terekhov committed
602
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
603
			centroid_tag = GetTag(centroid_name);
Kirill Terekhov's avatar
Kirill Terekhov committed
604 605 606 607
			for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
				if( centroid_tag.isDefined(etype) && !HaveGeometricData(CENTROID,etype) )
					ShowGeometricData(CENTROID,etype);
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
608
		if( HaveTag(barycenter_name) )
Kirill Terekhov's avatar
Kirill Terekhov committed
609
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
610
			barycenter_tag = GetTag(barycenter_name);
Kirill Terekhov's avatar
Kirill Terekhov committed
611 612 613 614
			for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
				if( barycenter_tag.isDefined(etype) && !HaveGeometricData(BARYCENTER,etype) )
					ShowGeometricData(BARYCENTER,etype);
		}
Kirill Terekhov's avatar
Kirill Terekhov committed
615
		if( HaveTag(normal_name) )
Kirill Terekhov's avatar
Kirill Terekhov committed
616
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
617
			normal_tag = GetTag(normal_name);
Kirill Terekhov's avatar
Kirill Terekhov committed
618 619 620 621 622
			for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
				if( normal_tag.isDefined(etype) && !HaveGeometricData(NORMAL,etype) )
					ShowGeometricData(NORMAL,etype);
		}
	}
Kirill Terekhov's avatar
Kirill Terekhov committed
623 624 625
	
	void Mesh::PrepareGeometricData(GeomParam table)
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
626
		std::sort(&*table.begin(),&*table.end());
Kirill Terekhov's avatar
Kirill Terekhov committed
627 628 629 630 631 632
		for(GeomParam::iterator it = table.begin(); it != table.end(); ++it)
		{
			GeometricData types = it->first;
			ElementType mask = it->second;
			if( types == ORIENTATION )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
633
				//std::cout << "ORIENTATION" << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
634
				if( mask & FACE )
Kirill Terekhov's avatar
Kirill Terekhov committed
635
				{
636 637 638
					if( HideMarker() )
					{
						MarkerType hm = HideMarker();
Kirill Terekhov's avatar
Kirill Terekhov committed
639 640 641
#if defined(USE_OMP)
#pragma omp parallel for
#endif
642 643 644 645 646 647 648 649 650 651 652
						for(integer e = 0; e < FaceLastLocalID(); ++e) 
						{
							if( isValidElement(FACE,e) )
							{
								HandleType h = ComposeHandle(FACE,e);
								if( !GetMarker(h,hm) )
									Face(this,h)->FixNormalOrientation();
							}
						}
					}
					else
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
653
					{
654 655 656 657 658 659 660 661
#if defined(USE_OMP)
#pragma omp parallel for
#endif
						for(integer e = 0; e < FaceLastLocalID(); ++e) 
						{
							if( isValidElement(FACE,e) )
								Face(this,ComposeHandle(FACE,e))->FixNormalOrientation();
						}
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
662
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
663
				}
Kirill Terekhov's avatar
Kirill Terekhov committed
664 665 666 667
				ShowGeometricData(ORIENTATION,FACE);
			}
			if( types == MEASURE )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
668
				//std::cout << "MEASURE" << std::endl;
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
669
				for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
670 671 672
				{
					if( (mask & etype) && !HaveGeometricData(MEASURE,etype))
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
673
						measure_tag = CreateTag(measure_name,DATA_REAL,etype,NONE,1);
674 675 676
						if( HideMarker() )
						{
							MarkerType hm = HideMarker();
Kirill Terekhov's avatar
Kirill Terekhov committed
677 678 679
#if defined(USE_OMP)
#pragma omp parallel for
#endif
680 681 682 683 684 685 686
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								if( !GetMarker(h,hm) ) GetGeometricData(h,MEASURE,static_cast<Storage::real *>(MGetDenseLink(h,measure_tag)));
							}
						}
						else
Kirill Terekhov's avatar
Kirill Terekhov committed
687
						{
688 689 690 691 692 693 694 695
#if defined(USE_OMP)
#pragma omp parallel for
#endif
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								GetGeometricData(h,MEASURE,static_cast<Storage::real *>(MGetDenseLink(h,measure_tag)));
							}
Kirill Terekhov's avatar
Kirill Terekhov committed
696
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
697 698 699 700 701 702
						ShowGeometricData(MEASURE,etype);
					}
				}
			}
			if( types == CENTROID )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
703
				//std::cout << "CENTROID" << std::endl;
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
704
				for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
705 706 707
				{
					if( (mask & etype) && !HaveGeometricData(CENTROID,etype))
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
708
						centroid_tag = CreateTag(centroid_name,DATA_REAL,etype,NONE,GetDimensions());
709 710 711
						if( HideMarker() )
						{
							MarkerType hm = HideMarker();
Kirill Terekhov's avatar
Kirill Terekhov committed
712 713 714
#if defined(USE_OMP)
#pragma omp parallel for
#endif
715 716 717 718 719 720 721
							for(integer k = 0; k < LastLocalID(etype); ++k) if( isValidElement(etype,k) )
							{
								HandleType h = ComposeHandle(etype,k);
								if( !GetMarker(h,hm) ) GetGeometricData(h,CENTROID,static_cast<Storage::real *>(MGetDenseLink(h,centroid_tag)));
							}
						}
						else
Kirill Terekhov's avatar
Kirill Terekhov committed
722
						{
723 724 725 726 727 728 729 730
#if defined(USE_OMP)
#pragma omp parallel for
#endif
							for(integer k = 0; k < LastLocalID(etype); ++k) if( isValidElement(etype,k) )
							{
								HandleType h = ComposeHandle(etype,k);
								GetGeometricData(h,CENTROID,static_cast<Storage::real *>(MGetDenseLink(h,centroid_tag)));
							}
Kirill Terekhov's avatar
Kirill Terekhov committed
731
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
732 733 734 735 736 737
						ShowGeometricData(CENTROID,etype);
					}
				}
			}
			if( types == BARYCENTER )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
738
				//std::cout << "BARYCENTER" << std::endl;
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
739
				for(ElementType etype = EDGE; etype <= CELL; etype = NextElementType(etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
740 741 742
				{
					if( (mask & etype) && !HaveGeometricData(BARYCENTER,etype))
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
743
						barycenter_tag = CreateTag(barycenter_name,DATA_REAL,etype,NONE,GetDimensions());
744 745 746
						if( HideMarker() )
						{
							MarkerType hm = HideMarker();
Kirill Terekhov's avatar
Kirill Terekhov committed
747 748 749
#if defined(USE_OMP)
#pragma omp parallel for
#endif
750 751 752 753 754 755 756
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								if( !GetMarker(h,hm) ) GetGeometricData(h,BARYCENTER,static_cast<Storage::real *>(MGetDenseLink(h,barycenter_tag)));
							}
						}
						else
Kirill Terekhov's avatar
Kirill Terekhov committed
757
						{
758 759 760 761 762 763 764 765
#if defined(USE_OMP)
#pragma omp parallel for
#endif
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								GetGeometricData(h,BARYCENTER,static_cast<Storage::real *>(MGetDenseLink(h,barycenter_tag)));
							}
Kirill Terekhov's avatar
Kirill Terekhov committed
766
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
767 768 769 770 771 772
						ShowGeometricData(BARYCENTER,etype);
					}
				}	
			}
			if( types == NORMAL )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
773
				//std::cout << "NORMAL" << std::endl;
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
774
				for(ElementType etype = FACE; etype <= CELL; etype = NextElementType(etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
775
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
776 777
					if( (mask & etype) && !HaveGeometricData(NORMAL,etype))
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
778
						normal_tag = CreateTag(normal_name,DATA_REAL,etype,NONE,GetDimensions());
779 780 781
						if( HideMarker() )
						{
							MarkerType hm = HideMarker();
Kirill Terekhov's avatar
Kirill Terekhov committed
782 783 784
#if defined(USE_OMP)
#pragma omp parallel for
#endif
785 786 787 788 789 790 791
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								if( !GetMarker(h,hm) ) GetGeometricData(h,NORMAL,static_cast<Storage::real *>(MGetDenseLink(h,normal_tag)));
							}
						}
						else
Kirill Terekhov's avatar
Kirill Terekhov committed
792
						{
793 794 795 796 797 798 799 800
#if defined(USE_OMP)
#pragma omp parallel for
#endif
							for(integer e = 0; e < LastLocalID(etype); ++e) if( isValidElement(etype,e) )
							{
								HandleType h = ComposeHandle(etype,e);
								GetGeometricData(h,NORMAL,static_cast<Storage::real *>(MGetDenseLink(h,normal_tag)));
							}
Kirill Terekhov's avatar
Kirill Terekhov committed
801
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
802 803
						ShowGeometricData(NORMAL,etype);
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
804
				}
Kirill Terekhov's avatar
Kirill Terekhov committed
805 806 807 808
			}
		}
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
	void Mesh::FacesOrientation(ElementArray<Face> & faces, MarkerType rev)
	{
		//can copy orientation-independent algorithm from
		//incident_matrix.hpp: incident_matrix::compute_measure
		//assume mdim is of size 3 at most
		if( !faces.empty() )
		{
			//real was = *ret/3.0;
			Face cur = faces[0];
			Mesh * mesh = faces.GetMeshLink();
			//firstly, have to figure out orientation of each face
			//mark all faces, so that we can perform adjacency retrival
			MarkerType mrk = mesh->CreatePrivateMarker();
			//MarkerType rev = mesh->CreatePrivateMarker(); //reverse orientation
			faces.SetPrivateMarker(mrk); //0-th face orientation is default
			cur->RemPrivateMarker(mrk);
			Node n1,n2; //to retrive edge
			bool reverse = false; //reverse orientation in considered face
			std::deque< orient_face > stack; //edge and first node and face for visiting
			ElementArray<Edge> edges = cur->getEdges();
			do
			{
				//figure out starting node order
				if( edges[0]->getBeg() == edges[1]->getBeg() ||
				    edges[0]->getBeg() == edges[1]->getEnd() )
				{
					n1 = edges[0]->getEnd();
					n2 = edges[0]->getBeg();
				}
				else
				{
					n1 = edges[0]->getBeg();
					n2 = edges[0]->getEnd();
				}
				//schedule unvisited adjacent faces
				for(unsigned j = 0; j < edges.size(); j++)
				{
					//schedule face adjacent to considered edge
					ElementArray<Face> adjacent = edges[j]->getFaces(mrk);
					assert(adjacent.size() <= 1);
					if( !adjacent.empty() )
					{
						adjacent.RemPrivateMarker(mrk);
						stack.push_back(orient_face(edges[j],reverse ? n2 : n1,adjacent[0]));
					}
					//update edge nodes
					n1 = n2; //current end is new begin
					//find new end
					if( n2 == edges[(j+1)%edges.size()]->getBeg() )
						n2 = edges[(j+1)%edges.size()]->getEnd();
						else
							n2 = edges[(j+1)%edges.size()]->getBeg();
							}
				if( stack.empty() ) break;
				//get entry from stack
				orient_face r = stack.front();
				//remove face from stack
				stack.pop_front();
				//retrive edges for new face
				edges = r.face->getEdges();
				reverse = false;
				//figure out starting node order
				if( edges[0]->getBeg() == edges[1]->getBeg() ||
				    edges[0]->getBeg() == edges[1]->getEnd() )
				{
					n1 = edges[0]->getEnd();
					n2 = edges[0]->getBeg();
				}
				else
				{
					n1 = edges[0]->getBeg();
					n2 = edges[0]->getEnd();
				}
				//find out common edge orientation
				for(unsigned j = 0; j < edges.size(); j++)
				{
					if( edges[j] == r.bridge ) //found the edge
					{
						//reverse ordering on this face
						if( r.first == n1 )
						{
							if( isPrivate(rev) )
								r.face->SetPrivateMarker(rev);
							else
								r.face->SetMarker(rev);
							reverse = true;
						}
						break;
					}
					//update edge nodes
					n1 = n2; //current end is new begin
					//find new end
					if( n2 == edges[(j+1)%edges.size()]->getBeg() )
						n2 = edges[(j+1)%edges.size()]->getEnd();
					else
						n2 = edges[(j+1)%edges.size()]->getBeg();
				}
			} while(true);
			faces.RemPrivateMarker(mrk);
			mesh->ReleasePrivateMarker(mrk);
			//faces.RemPrivateMarker(rev);
		}
	}
	
Kirill Terekhov's avatar
Kirill Terekhov committed
913
	void Mesh::GetGeometricData(HandleType e, GeometricData type, Storage::real * ret)
Kirill Terekhov's avatar
Kirill Terekhov committed
914
	{
Kirill Terekhov's avatar
Kirill Terekhov committed
915 916
		assert(e != InvalidHandle());
		assert(ret != NULL);
Kirill Terekhov's avatar
Kirill Terekhov committed
917 918 919 920
		assert(type == MEASURE ||
			   type == CENTROID ||
			   type == BARYCENTER ||
			   type == NORMAL);
Kirill Terekhov's avatar
Kirill Terekhov committed
921 922 923
		ElementType etype = GetHandleElementType(e);
		integer edim = Element::GetGeometricDimension(GetGeometricType(e));
		integer mdim = GetDimensions();
Kirill Terekhov's avatar
Kirill Terekhov committed
924 925 926 927 928
		switch(type)
		{
			case MEASURE:
			if( HaveGeometricData(MEASURE,etype) )
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
929
				*ret = static_cast<Storage::real *>(MGetDenseLink(e,measure_tag))[0];
Kirill Terekhov's avatar
Kirill Terekhov committed
930 931 932 933 934 935 936 937 938
				//~ if( isnan(*ret) || fabs(*ret) < 1e-15  ) throw -1;
			}
			else
			{
				switch(edim)
				{
					case 0: *ret = 0; break;
					case 1: //length of edge
					{
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
939
						ElementArray<Node> nodes = Element(this,e)->getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
940 941
						if( nodes.size() > 1 )
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
942 943 944 945
							real c[3] = {0,0,0};
							real_array v0 = nodes[0].Coords();
							real_array v1 = nodes[1].Coords();
							vec_diff(v0.data(),v1.data(),c,mdim);
Kirill Terekhov's avatar
Kirill Terekhov committed
946 947 948
							*ret = vec_len(c,mdim);
						}
						else *ret = 0;
Kirill Terekhov's avatar
Kirill Terekhov committed
949 950 951 952 953
						//~ if( isnan(*ret) || fabs(*ret) < 1e-15  ) throw -1;
						break;
					}
					case 2: //area of face
					{
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
954
						ElementArray<Node> nodes = Element(this,e)->getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
955
						if( nodes.size() > 2 )
Kirill Terekhov's avatar
Kirill Terekhov committed
956
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
957 958
							*ret = 0;
							real nt[3] = {0,0,0}, l1[3] = {0,0,0}, l2[3] = {0,0,0},n0[3] = {0,0,0}, ss;
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
							//real_array v0 = nodes[0].Coords();
							//real_array v1 = nodes[1].Coords();
							//real_array v2 = nodes[2].Coords();
							//vec_diff(v1,v0,l1,mdim);
							//vec_diff(v2,v0,l2,mdim);
							//vec_cross_product(l1,l2,n0);
							real_array v0 = nodes[0].Coords(), v1, v2;
							for(int i = 1; i < (int)nodes.size()-1; i++)
							{
								v1 = nodes[i].Coords();
								v2 = nodes[i+1].Coords();
								vec_diff(v1,v0,l1,mdim);
								vec_diff(v2,v0,l2,mdim);
								vec_cross_product(l1,l2,nt);
								for(int q = 0; q < 3; ++q)
									n0[q] += nt[q]*0.5;
							}
Kirill Terekhov's avatar
Kirill Terekhov committed
976
							for(int i = 1; i < (int)nodes.size()-1; i++)
Kirill Terekhov's avatar
Kirill Terekhov committed
977
							{
Kirill Terekhov's avatar
Kirill Terekhov committed
978 979 980 981 982 983
								v1 = nodes[i].Coords();
								v2 = nodes[i+1].Coords();
								vec_diff(v1,v0,l1,mdim);
								vec_diff(v2,v0,l2,mdim);
								vec_cross_product(l1,l2,nt);
								ss = vec_dot_product(n0,nt,3);
984
								if( ss ) ss /= fabs(ss);
Kirill Terekhov's avatar
Kirill Terekhov committed
985
								*ret += sqrt(vec_dot_product(nt,nt,3))*0.5*ss;
Kirill Terekhov's avatar
Kirill Terekhov committed
986
							}
987
							if( *ret != *ret ) std::cout << "area is nan" << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
988
							*ret = fabs(*ret);
Kirill Terekhov's avatar
Kirill Terekhov committed
989
						} else *ret = 0;
Kirill Terekhov's avatar
Kirill Terekhov committed
990 991 992 993 994
						//~ if( isnan(*ret) || fabs(*ret) < 1e-15  ) throw -1;
						break;
					}
					case 3: //volume of cell
					{
995 996
						//bool print = false;
//redo:
Kirill Terekhov's avatar
Kirill Terekhov committed
997 998
						Cell me = Cell(this,e);
						ElementArray<Face> faces = me->getFaces();
999
						bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
Kirill Terekhov's avatar
Kirill Terekhov committed
1000 1001
						MarkerType rev = 0;
						if( ornt )
Kirill Terekhov's avatar
Kirill Terekhov committed
1002
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1003 1004
							rev = CreatePrivateMarker();
							FacesOrientation(faces,rev);
Kirill Terekhov's avatar
Kirill Terekhov committed
1005
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1006 1007 1008
						real vol = 0, a, at;
						real x[3] = {0,0,0}, n[3] = {0,0,0}, n0[3] = {0,0,0}, s, ss;
						real l1[3] = {0,0,0}, l2[3] = {0,0,0};
Kirill Terekhov's avatar
Kirill Terekhov committed
1009 1010
						real nt[3] = {0,0,0}, cx[3] = {0,0,0};
						me.Centroid(cx);
1011
						//if( print ) std::cout << "cx: " << cx[0] << " " << cx[1] << " " << cx[2] << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1012
						for(unsigned j = 0; j < faces.size(); j++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1013
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1014 1015 1016 1017 1018 1019 1020 1021
							//compute normal to face
							ElementArray<Node> nodes = faces[j].getNodes();
							if( ornt )
								s = faces[j].GetPrivateMarker(rev) ? -1.0 : 1.0;
							else
								s = faces[j].FaceOrientedOutside(me) ? 1.0 : -1.0;
							x[0] = x[1] = x[2] = 0;
							n[0] = n[1] = n[2] = 0;
1022
							n0[0] = n0[1] = n0[2] = 0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1023
							a = 0;
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
							//real_array v0 = nodes[0].Coords();
							//real_array v1 = nodes[1].Coords();
							//real_array v2 = nodes[2].Coords();
							//vec_diff(v1,v0,l1,mdim);
							//vec_diff(v2,v0,l2,mdim);
							//vec_cross_product(l1,l2,n0);
							real_array v0 = nodes[0].Coords(), v1, v2;
							for(int i = 1; i < (int)nodes.size()-1; i++)
							{
								v1 = nodes[i].Coords();
								v2 = nodes[i+1].Coords();
								vec_diff(v1,v0,l1,mdim);
								vec_diff(v2,v0,l2,mdim);
								vec_cross_product(l1,l2,nt);
								//if( print ) std::cout << "nt: " << nt[0] << " " << nt[1] << " " << nt[2] << std::endl;
								for(int q = 0; q < 3; ++q)
									n0[q] += nt[q]*0.5;
							}
							//if( print ) std::cout << "n0: " << n0[0] << " " << n0[1] << " " << n0[2] << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1043
							for(int k = 1; k < (int)nodes.size()-1; k++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1044
							{
Kirill Terekhov's avatar
Kirill Terekhov committed
1045 1046 1047 1048 1049 1050 1051
								v1 = nodes[k+0].Coords();
								v2 = nodes[k+1].Coords();
								vec_diff(v1,v0,l1,mdim);
								vec_diff(v2,v0,l2,mdim);
								vec_cross_product(l1,l2,nt);
								for(int q = 0; q < 3; ++q) nt[q] *= 0.5;
								ss = vec_dot_product(n0,nt,3);
1052
								if( ss ) ss /= fabs(ss);
Kirill Terekhov's avatar
Kirill Terekhov committed
1053
								at = sqrt(vec_dot_product(nt,nt,3))*ss;
1054
								//if( print ) std::cout << "nt: " << nt[0] << " " << nt[1] << " " << nt[2] << " ss " << ss << " at " << at << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1055 1056 1057 1058 1059
								//same as faces[j].Normal(n)
								for(int q = 0; q < 3; ++q)
									n[q] += nt[q];
								//same as faces[j].Centroid(x)
								for(int q = 0; q < 3; ++q)
Kirill Terekhov's avatar
Kirill Terekhov committed
1060
									x[q] += at*((v0[q]-cx[q])+(v1[q]-cx[q])+(v2[q]-cx[q]))/3.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1061
								a += at;
Kirill Terekhov's avatar
Kirill Terekhov committed
1062
							}
1063 1064
							//if( print ) std::cout << "n: " << n[0] << " " << n[1] << " " << n[2] << std::endl;
							//if( print ) std::cout << "x: " << x[0] << " " << x[1] << " " << x[2] << " a " << a << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1065 1066 1067
							for(int q = 0; q < 3; ++q) x[q] /= a;
							vol += s*vec_dot_product(x,n,3);
						}
1068
						//if( print ) std::cout << "vol: " << vol << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1069 1070 1071
						if( ornt )
						{
							if( vol < 0.0 ) vol = -vol;
Kirill Terekhov's avatar
Kirill Terekhov committed
1072
							faces.RemPrivateMarker(rev);
Kirill Terekhov's avatar
Kirill Terekhov committed
1073
							ReleasePrivateMarker(rev);
Kirill Terekhov's avatar
Kirill Terekhov committed
1074
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1075
						*ret = vol/3.0;
1076 1077 1078 1079 1080 1081
						//if( *ret < 0 || *ret != *ret ) 
						//{
						//	std::cout << "volume is " << *ret << std::endl;
						//	print = true;
						//	goto redo;
						//}
Kirill Terekhov's avatar
Kirill Terekhov committed
1082 1083 1084 1085 1086 1087 1088
						break;
					}
				}
			}
			//~ if( isnan(*ret) || fabs(*ret) < 1e-15  ) throw -1;
			break;
			case CENTROID:
Kirill Terekhov's avatar
Kirill Terekhov committed
1089 1090 1091
				if(etype == NODE )
					memcpy(ret,MGetDenseLink(e,CoordsTag()),sizeof(real)*mdim);
				else if(HaveGeometricData(CENTROID,etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
1092
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
1093 1094 1095 1096 1097 1098 1099
					memcpy(ret,MGetDenseLink(e,centroid_tag),sizeof(real)*mdim);
				}
				else
				{
					ElementArray<Node> nodes = Element(this,e).getNodes();
					memset(ret,0,sizeof(real)*mdim);
					for(unsigned k = 0; k < nodes.size(); ++k)
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
1100
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1101 1102
						for(int q = 0; q < mdim; ++q)
							ret[q] += nodes[k].Coords()[q];
Kirill Terekhov's avatar
Fixes  
Kirill Terekhov committed
1103
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1104 1105
					for(int q = 0; q < mdim; ++q)
						ret[q] /= (real)nodes.size();
Kirill Terekhov's avatar
Kirill Terekhov committed
1106 1107 1108
				}
			break;
			case BARYCENTER:
Kirill Terekhov's avatar
Kirill Terekhov committed
1109
			if(etype == NODE )
Kirill Terekhov's avatar
Kirill Terekhov committed
1110
				memcpy(ret,MGetDenseLink(e,CoordsTag()),sizeof(real)*mdim);
Kirill Terekhov's avatar
Kirill Terekhov committed
1111
			else if(HaveGeometricData(BARYCENTER,etype))
Kirill Terekhov's avatar
Kirill Terekhov committed
1112
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
1113
				memcpy(ret,MGetDenseLink(e,barycenter_tag),sizeof(real)*mdim);
Kirill Terekhov's avatar
Kirill Terekhov committed
1114
			}
Kirill Terekhov's avatar
Kirill Terekhov committed
1115 1116 1117 1118 1119
			else
			{
				memset(ret,0,sizeof(real)*mdim);
				if( edim == 1 )
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
1120
					ElementArray<Node> n = Element(this,e)->getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
1121 1122
					if( n.size() == 2 )
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1123 1124 1125 1126
						real_array v0 = n[0].Coords();
						real_array v1 = n[1].Coords();
						for(integer j = 0; j < dim; j++)
							ret[j] = (v0[j] + v1[j])*0.5;
Kirill Terekhov's avatar
Kirill Terekhov committed
1127 1128 1129
					}
					else if( n.size() == 1 )
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1130 1131
						real_array v0 = n[0].Coords();
						for(integer j = 0; j < dim; j++) ret[j] = v0[j];
Kirill Terekhov's avatar
Kirill Terekhov committed
1132
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1133 1134 1135
				}
				else if( edim == 2 )
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
1136
					ElementArray<Node> nodes = Element(this,e)->getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
1137
					if( nodes.size() > 2 )
Kirill Terekhov's avatar
Kirill Terekhov committed
1138
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1139 1140
						*ret = 0;
						real nt[3] = {0,0,0}, l1[3] = {0,0,0}, l2[3] = {0,0,0};
Kirill Terekhov's avatar
Kirill Terekhov committed
1141
						real c[3] = {0,0,0}, n0[3] = {0,0,0}, ss, cx[3] = {0,0,0};
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
						//real_array v0 = nodes[0].Coords();
						//real_array v1 = nodes[1].Coords();
						//real_array v2 = nodes[2].Coords();
						//vec_diff(v1,v0,l1,mdim);
						//vec_diff(v2,v0,l2,mdim);
						//vec_cross_product(l1,l2,n0);
						real_array v0 = nodes[0].Coords(), v1, v2;
						for(int i = 1; i < (int)nodes.size()-1; i++)
						{
							v1 = nodes[i].Coords();
							v2 = nodes[i+1].Coords();
							vec_diff(v1,v0,l1,mdim);
							vec_diff(v2,v0,l2,mdim);
							vec_cross_product(l1,l2,nt);
							for(int q = 0; q < 3; ++q)
								n0[q] += nt[q]*0.5;
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1159
						real a = 0, at;
Kirill Terekhov's avatar
Kirill Terekhov committed
1160
						Element(this,e).Centroid(cx);
Kirill Terekhov's avatar
Kirill Terekhov committed
1161
						for(int i = 1; i < (int)nodes.size()-1; i++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1162
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1163 1164 1165 1166 1167 1168
							real_array v1 = nodes[i].Coords();
							real_array v2 = nodes[i+1].Coords();
							vec_diff(v1,v0,l1,mdim);
							vec_diff(v2,v0,l2,mdim);
							vec_cross_product(l1,l2,nt);
							ss = vec_dot_product(n0,nt,3);
1169
							if( ss ) ss /= fabs(ss);
Kirill Terekhov's avatar
Kirill Terekhov committed
1170 1171
							at = sqrt(vec_dot_product(nt,nt,3))*0.5*ss;
							for(int q = 0; q < mdim; ++q)
Kirill Terekhov's avatar
Kirill Terekhov committed
1172
								c[q] += at*((v0[q]-cx[q])+(v1[q]-cx[q])+(v2[q]-cx[q]))/3.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1173
							a += at;
Kirill Terekhov's avatar
Kirill Terekhov committed
1174
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1175
						for(int q = 0; q < mdim; ++q) ret[q] = c[q]/a+cx[q];
Kirill Terekhov's avatar
Kirill Terekhov committed
1176
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1177 1178 1179 1180 1181 1182
					//std::cout << ret[0] << " " << ret[1] << " " << ret[2] << std::endl;
				}
				else if( edim == 3 )
				{
					Cell me = Cell(this,e);
					ElementArray<Face> faces = me->getFaces();
1183
					bool ornt = true;//!HaveGeometricData(ORIENTATION,FACE);
Kirill Terekhov's avatar
Kirill Terekhov committed
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
					MarkerType rev = 0;
					if( ornt )
					{
						rev = CreatePrivateMarker();
						FacesOrientation(faces,rev);
					}
					real vol = 0, a, at;
					real x[3] = {0,0,0}, nt[3] = {0,0,0}, s;
					real c[3] = {0,0,0}, n[3] = {0,0,0};
					real n0[3] = {0,0,0}, ss;
					real l1[3] = {0,0,0}, l2[3] = {0,0,0};
Kirill Terekhov's avatar
Kirill Terekhov committed
1195 1196
					real cx[3] = {0,0,0};
					me.Centroid(cx);
Kirill Terekhov's avatar
Kirill Terekhov committed
1197
					for(unsigned j = 0; j < faces.size(); j++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1198
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1199 1200 1201 1202 1203 1204
						//compute normal to face
						ElementArray<Node> nodes = faces[j].getNodes();
						if( ornt )
							s = faces[j].GetPrivateMarker(rev) ? -1.0 : 1.0;
						else
							s = faces[j].FaceOrientedOutside(me) ? 1.0 : -1.0;
1205 1206 1207 1208 1209 1210 1211
						//real_array v0 = nodes[0].Coords();
						//real_array v1 = nodes[1].Coords();
						//real_array v2 = nodes[2].Coords();
						//vec_diff(v1,v0,l1,mdim);
						//vec_diff(v2,v0,l2,mdim);
						//vec_cross_product(l1,l2,n0);
						n0[0] = n0[1] = n0[2] = 0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1212 1213 1214
						x[0] = x[1] = x[2] = 0;
						n[0] = n[1] = n[2] = 0;
						a = 0;
1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
						real_array v0 = nodes[0].Coords(), v1, v2;
						for(int i = 1; i < (int)nodes.size()-1; i++)
						{
							v1 = nodes[i].Coords();
							v2 = nodes[i+1].Coords();
							vec_diff(v1,v0,l1,mdim);
							vec_diff(v2,v0,l2,mdim);
							vec_cross_product(l1,l2,nt);
							for(int q = 0; q < 3; ++q)
								n0[q] += nt[q]*0.5;
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1226
						for(int i = 1; i < (int)nodes.size()-1; i++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1227
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1228 1229 1230 1231 1232 1233 1234 1235
							real_array v1 = nodes[i].Coords();
							real_array v2 = nodes[i+1].Coords();
							vec_diff(v1,v0,l1,mdim);
							vec_diff(v2,v0,l2,mdim);
							vec_cross_product(l1,l2,nt);
							for(int q = 0; q < 3; ++q)
								nt[q] *= 0.5;
							ss = vec_dot_product(n0,nt,3);
1236
							if( ss ) ss /= fabs(ss);
Kirill Terekhov's avatar
Kirill Terekhov committed
1237 1238 1239 1240 1241 1242
							at = sqrt(vec_dot_product(nt,nt,3))*ss;
							//same as faces[j].Normal(n)
							for(int q = 0; q < 3; ++q)
								n[q] += nt[q];
							//same as faces[j].Centroid(x)
							for(int q = 0; q < 3; ++q)
Kirill Terekhov's avatar
Kirill Terekhov committed
1243
								x[q] += at*((v0[q]-cx[q])+(v1[q]-cx[q])+(v2[q]-cx[q]))/3.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1244 1245 1246
							a += at;
							//second-order midpoint formula
							for(int q = 0; q < 3; ++q)
Kirill Terekhov's avatar
Kirill Terekhov committed
1247
								c[q] += s*nt[q]*(pow((v0[q]-cx[q])+(v1[q]-cx[q]),2)+pow((v0[q]-cx[q])+(v2[q]-cx[q]),2)+pow((v1[q]-cx[q])+(v2[q]-cx[q]),2))/24.0;
Kirill Terekhov's avatar
Kirill Terekhov committed
1248
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1249
						for(int q = 0; q < 3; ++q) x[q] = x[q]/a;
Kirill Terekhov's avatar
Kirill Terekhov committed
1250
						vol += s*vec_dot_product(x,n,3);
Kirill Terekhov's avatar
Kirill Terekhov committed
1251
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1252
					if( ornt )
Kirill Terekhov's avatar
Kirill Terekhov committed
1253
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1254
						if( vol < 0.0 )
Kirill Terekhov's avatar
Kirill Terekhov committed
1255
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1256 1257 1258
							vol = -vol;
							for(int q = 0; q < 3; ++q)
								c[q] = -c[q];
Kirill Terekhov's avatar
Kirill Terekhov committed
1259
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1260 1261
						faces.RemPrivateMarker(rev);
						ReleasePrivateMarker(rev);
Kirill Terekhov's avatar
Kirill Terekhov committed
1262
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1263
					vol /= 3.0;
1264 1265 1266 1267 1268 1269
					if( vol ) 
					{
						for(int q = 0; q < mdim; ++q)
							ret[q] = c[q]/(vol) + cx[q];
					}
					else for(int q = 0; q < mdim; ++q) ret[q] = cx[q];
Kirill Terekhov's avatar
Kirill Terekhov committed
1270
					//std::cout << ret[0] << " " << ret[1] << " " << ret[2] << std::endl;
Kirill Terekhov's avatar
Kirill Terekhov committed
1271 1272 1273 1274 1275
				}
			}
			break;
			case NORMAL:
			{
Kirill Terekhov's avatar
Kirill Terekhov committed
1276
				if( HaveGeometricData(NORMAL,etype) )
Kirill Terekhov's avatar
Kirill Terekhov committed
1277
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
1278
					memcpy(ret,MGetDenseLink(e,normal_tag),sizeof(real)*mdim);
Kirill Terekhov's avatar
Kirill Terekhov committed
1279
				}
Kirill Terekhov's avatar
Kirill Terekhov committed
1280
				else
Kirill Terekhov's avatar
Kirill Terekhov committed
1281
				{
Kirill Terekhov's avatar
Kirill Terekhov committed
1282 1283 1284 1285
					memset(ret,0,sizeof(real)*mdim);
					if( edim == 2 )//&& mdim == 3)
					{
						ElementArray<Node> nodes = Element(this,e)->getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
1286 1287 1288 1289
						real n[3] = {0,0,0}, l1[3] = {0,0,0}, l2[3] = {0,0,0};
						real nt[3] = {0,0,0};
						real_array v0 = nodes[0].Coords();
						for(int i = 1; i < (int)nodes.size()-1; i++)
Kirill Terekhov's avatar
Kirill Terekhov committed
1290
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1291 1292 1293 1294 1295 1296 1297
							real_array v1 = nodes[i].Coords();
							real_array v2 = nodes[i+1].Coords();
							vec_diff(v1,v0,l1,mdim);
							vec_diff(v2,v0,l2,mdim);
							vec_cross_product(l1,l2,nt);
							for(int q = 0; q < 3; ++q)
								n[q] += nt[q]*0.5;
Kirill Terekhov's avatar
Kirill Terekhov committed
1298
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1299 1300
						for(int q = 0; q < mdim; ++q)
							ret[q] = n[q];
Kirill Terekhov's avatar
Kirill Terekhov committed
1301 1302
					}
					else if( edim == 1 )//&& mdim == 2 )
Kirill Terekhov's avatar
Kirill Terekhov committed
1303
					{
Kirill Terekhov's avatar
Kirill Terekhov committed
1304 1305
						ElementArray<Node> nodes = Element(this,e)->getNodes();
						if( nodes.size() > 1 )
Kirill Terekhov's avatar
Kirill Terekhov committed
1306
						{
Kirill Terekhov's avatar
Kirill Terekhov committed
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
							Storage::real_array a = nodes[0].Coords();
							Storage::real_array b = nodes[1].Coords();
							ret[0] = b[1] - a[1];
							ret[1] = a[0] - b[0];
							Storage::real l = ::sqrt(ret[0]*ret[0]+ret[1]*ret[1]);
							if( l )
							{
								ret[0] /= l;
								ret[1] /= l;
							}
							l = ::sqrt((a[0]-b[0])*(a[0]-b[0])+(a[1]-b[1])*(a[1]-b[1]));
							ret[0] *= l;
							ret[1] *= l;
Kirill Terekhov's avatar
Kirill Terekhov committed
1320
						}
Kirill Terekhov's avatar
Kirill Terekhov committed
1321
					}
Kirill Terekhov's avatar
Kirill Terekhov committed
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
				}
			}
			break;
		}
		//~ if( type == MEASURE )
		//~ {
			//~ if( isnan(*ret) || fabs(*ret) < 1e-15  ) throw -1;
		//~ }
	}
	


Kirill Terekhov's avatar
Kirill Terekhov committed
1334
	bool Element::Planarity() const
Kirill Terekhov's avatar
Kirill Terekhov committed
1335 1336
	{
		Mesh * m = GetMeshLink();
Kirill Terekhov's avatar
Kirill Terekhov committed
1337
		integer dim = m->GetDimensions();
Kirill Terekhov's avatar
Kirill Terekhov committed
1338
		if( dim < 3 ) return true;
Kirill Terekhov's avatar
Kirill Terekhov committed
1339
		ElementArray<Node> p = getNodes();
Kirill Terekhov's avatar
Kirill Terekhov committed
1340
		if( p.size() <= 3 ) return true;
Kirill Terekhov's avatar
Kirill Terekhov committed
1341
		ElementArray<Node>::size_type i, s = p.size();
Kirill Terekhov's avatar
Kirill Terekhov committed
1342
		Storage::real v[2][3] = {{0,0,0},{0,0,0}};
Kirill Terekhov's avatar
Kirill Terekhov committed
1343 1344
		vec_diff(p[1].Coords().data(),p[0].Coords().data(),v[0],3);
		vec_diff(p[2].Coords().data(),p[0].Coords().data(),v[1],3);
Kirill Terekhov's avatar
Kirill Terekhov committed
1345 1346 1347
		vec_cross_product(v[0],v[1],v[1]);
		for(i = 3; i < s; i++)
		{
Kirill Terekhov's avatar
Kirill Terekhov committed
1348
			vec_diff(p[i].Coords().data(),p[0].Coords().data(),v[0],3);
Kirill Terekhov's avatar
Kirill Terekhov committed
1349
			if( ::fabs(vec_dot_product(v[0],v[1],3)) > m->GetEpsilon() ) return false;
Kirill Terekhov's avatar
Kirill Terekhov committed
1350 1351 1352 1353 1354
		}
		return true;
	}