PageRenderTime 31ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/MeshOptimizer/MeshOptCommon.cpp

https://bitbucket.org/pefarrell/gmsh
C++ | 347 lines | 270 code | 35 blank | 42 comment | 54 complexity | f41a01771517f8263380fa637f23eb8c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, AGPL-3.0, BSD-3-Clause
  1. // Copyright (C) 2013 ULg-UCL
  2. //
  3. // Permission is hereby granted, free of charge, to any person
  4. // obtaining a copy of this software and associated documentation
  5. // files (the "Software"), to deal in the Software without
  6. // restriction, including without limitation the rights to use, copy,
  7. // modify, merge, publish, distribute, and/or sell copies of the
  8. // Software, and to permit persons to whom the Software is furnished
  9. // to do so, provided that the above copyright notice(s) and this
  10. // permission notice appear in all copies of the Software and that
  11. // both the above copyright notice(s) and this permission notice
  12. // appear in supporting documentation.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  17. // NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
  18. // COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
  19. // ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
  20. // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21. // WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  22. // ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  23. // OF THIS SOFTWARE.
  24. //
  25. // Please report all bugs and problems to the public mailing list
  26. // <gmsh@onelab.info>.
  27. //
  28. // Contributors: Thomas Toulorge, Jonathan Lambrechts
  29. #include <iostream>
  30. #include <fstream>
  31. #include <list>
  32. #include <string.h>
  33. #include "MElement.h"
  34. #include "MeshOptCommon.h"
  35. #ifdef HAVE_NCURSES
  36. #include "ncurses.h"
  37. void catchPause(){
  38. timeout(0);
  39. if (getch() == ' '){
  40. mvpause();
  41. }
  42. };
  43. void mvinit(){
  44. initscr();
  45. start_color();
  46. noecho();
  47. curs_set(FALSE);
  48. timeout(0);
  49. init_pair(0, COLOR_WHITE, COLOR_BLACK);
  50. init_pair(1, COLOR_BLACK, COLOR_WHITE);
  51. init_pair(2, COLOR_BLACK, COLOR_YELLOW);
  52. init_pair(3, COLOR_RED, COLOR_WHITE);
  53. init_pair(4, COLOR_GREEN, COLOR_WHITE);
  54. init_pair(5, COLOR_BLUE, COLOR_WHITE);
  55. init_pair(6, COLOR_RED, COLOR_BLACK);
  56. init_pair(7, COLOR_GREEN, COLOR_BLACK);
  57. init_pair(8, COLOR_BLUE, COLOR_BLACK);
  58. }
  59. void mvterminate(){
  60. endwin();
  61. }
  62. void mvgetScreenSize(int &nbRow, int &nbCol){
  63. getmaxyx(stdscr,nbRow,nbCol);
  64. }
  65. void mvbold(bool on){
  66. if (on)
  67. attron(A_BOLD);
  68. else
  69. attroff(A_BOLD);
  70. }
  71. void mvcolor(int colorScheme, bool on){
  72. if (on)
  73. attron(COLOR_PAIR(colorScheme));
  74. else
  75. attroff(COLOR_PAIR(colorScheme));
  76. }
  77. void mvpause(){
  78. attron(COLOR_PAIR(1));
  79. attron(A_BOLD);
  80. mvprintCenter(-1, " PAUSED (PRESS SPACE TO CONTINUE) ");
  81. attroff(COLOR_PAIR(1));
  82. attroff(A_BOLD);
  83. timeout(-1);
  84. while (getch() != ' '){}
  85. mvfillRow(-1);
  86. }
  87. void mvprintCenter(int row, const char* fmt, ...){
  88. catchPause();
  89. char str[1000];
  90. va_list args;
  91. va_start(args, fmt);
  92. vsnprintf(str, sizeof(str), fmt, args);
  93. va_end(args);
  94. int nbRow, nbCol;
  95. getmaxyx(stdscr,nbRow,nbCol);
  96. if (row<0)
  97. row = nbRow+row;
  98. mvprintw(row, (nbCol-strlen(str))/2, str, args);
  99. refresh();
  100. }
  101. void mvprintLeft(int row, const char* fmt, ...){
  102. catchPause();
  103. char str[1000];
  104. va_list args;
  105. va_start(args, fmt);
  106. vsnprintf(str, sizeof(str), fmt, args);
  107. va_end(args);
  108. int nbRow, nbCol;
  109. getmaxyx(stdscr,nbRow,nbCol);
  110. if (row<0)
  111. row = nbRow+row;
  112. mvprintw(row, 0, str, args);
  113. refresh();
  114. }
  115. void mvprintRight(int row, const char* fmt, ...){
  116. catchPause();
  117. char str[1000];
  118. va_list args;
  119. va_start(args, fmt);
  120. vsnprintf(str, sizeof(str), fmt, args);
  121. va_end(args);
  122. int nbRow, nbCol;
  123. getmaxyx(stdscr,nbRow,nbCol);
  124. if (row<0)
  125. row = nbRow+row;
  126. mvprintw(row, nbCol-strlen(str), str, args);
  127. refresh();
  128. }
  129. void mvprintXY(int row, int col, const char* fmt, ...){
  130. catchPause();
  131. char str[1000];
  132. va_list args;
  133. va_start(args, fmt);
  134. vsnprintf(str, sizeof(str), fmt, args);
  135. va_end(args);
  136. int nbRow, nbCol;
  137. getmaxyx(stdscr,nbRow,nbCol);
  138. if (row<0)
  139. row = nbRow+row;
  140. if (col<0)
  141. col = nbCol+col;
  142. mvprintw(row, col, str, args);
  143. refresh();
  144. }
  145. void mvprintList(int row, int maxSize, std::list<char*> listStr, int colorScheme){
  146. int nbRow, nbCol;
  147. getmaxyx(stdscr,nbRow,nbCol);
  148. if (row<0)
  149. row = nbRow+row;
  150. int i=0;
  151. for (std::list<char*>::iterator it=listStr.begin(); it != listStr.end(); it++){
  152. if (i >= abs(maxSize)) break;
  153. if (colorScheme==1){
  154. if (*it == listStr.back())
  155. attron(COLOR_PAIR(2));
  156. else
  157. attron(COLOR_PAIR(1));
  158. }
  159. if (colorScheme==2){
  160. if (i%2==0)
  161. attron(COLOR_PAIR(1));
  162. }
  163. mvprintLeft(row + maxSize/abs(maxSize)*i, *it);
  164. if (colorScheme==1){
  165. if (*it == listStr.back())
  166. attroff(COLOR_PAIR(2));
  167. else
  168. attroff(COLOR_PAIR(1));
  169. }
  170. if (colorScheme==2){
  171. if (i%2==0)
  172. attroff(COLOR_PAIR(1));
  173. }
  174. i++;
  175. }
  176. while (i < abs(maxSize)) {
  177. mvfillRow(row + maxSize/abs(maxSize)*i++);
  178. }
  179. }
  180. void mvfillRow(int row, char fillWith){
  181. int nbRow, nbCol;
  182. getmaxyx(stdscr,nbRow,nbCol);
  183. if (row<0)
  184. row = nbRow+row;
  185. char toFill[1] = {fillWith};
  186. for (int k = 0; k < nbCol; k++)
  187. mvprintXY(row, k, toFill);
  188. }
  189. #else
  190. void catchPause(){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  191. void mvinit(){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  192. void mvterminate(){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  193. void mvgetScreenSize(int &nbRow, int &nbCol){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  194. void mvbold(bool on){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  195. void mvcolor(int colorScheme, bool on){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  196. void mvpause(){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  197. void mvprintCenter(int row, const char* fmt, ...){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  198. void mvprintLeft(int row, const char* fmt, ...){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  199. void mvprintRight(int row, const char* fmt, ...){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  200. void mvprintXY(int row, int col, const char* fmt, ...){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  201. void mvprintList(int row, int maxSize, std::list<char*> listStr, int colorScheme){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  202. void mvfillRow(int row, char fillWith){Msg::Fatal("Gmsh should be configured with ncurses to use enhanced interface");}
  203. #endif
  204. redirectMessage::redirectMessage(std::string logFileName, bool console){
  205. std::ofstream logFile;
  206. _logFileName = logFileName;
  207. _console = console;
  208. if(logFileName.compare("") != 0){
  209. logFile.open(_logFileName.c_str());
  210. logFile.close();
  211. }
  212. }
  213. void redirectMessage::operator()(std::string level, std::string message){
  214. std::ofstream logFile;
  215. if(_logFileName.compare("") != 0){
  216. logFile.open(_logFileName.c_str(), std::ios::app);
  217. logFile << level << " : "<< message << std::endl;
  218. logFile.close();
  219. }
  220. if (_console){
  221. fprintf(stdout, "%s : %s\n", level.c_str(), message.c_str());
  222. fflush(stdout);
  223. }
  224. }
  225. namespace {
  226. // Test intersection between sphere and segment
  227. bool testSegSphereIntersect(SPoint3 A, SPoint3 B, const SPoint3& P, const double rr)
  228. {
  229. // Test if separating plane between sphere and segment vertices
  230. // For each vertex, separation if vertex is outside sphere and P on opposite side
  231. // to other seg. vertex w.r.t plane of normal (vertex-P) through vertex
  232. const SVector3 PA(P, A), PB(P, B);
  233. const double aa = dot(PA, PA), ab = dot(PA, PB);
  234. if ((aa > rr) & (ab > aa)) return false;
  235. const double bb = dot(PB, PB);
  236. if ((bb > rr) & (ab > bb)) return false;
  237. // Test if separating plane between sphere and line
  238. // For A, separation if projection Q of P on (AB) lies outside the sphere
  239. const SVector3 AB(A, B);
  240. const double d = ab - aa, e = dot(AB, AB);
  241. const SVector3 PQ = PA * e - d * AB;
  242. if (dot(PQ, PQ) > rr * e * e) return false;
  243. // Return true (intersection) if no separation at all
  244. return true;
  245. }
  246. // Test intersection between sphere and triangle
  247. // Inspired by Christer Ericson, http://realtimecollisiondetection.net/blog/?p=103
  248. bool testTriSphereIntersect(SPoint3 A, SPoint3 B, SPoint3 C, const SPoint3& P, const double rr)
  249. {
  250. // Test if separating plane between sphere and triangle plane
  251. const SVector3 PA(P, A), AB(A, B), AC(A, C);
  252. const SVector3 V = crossprod(AB, AC); // Normal to triangle plane
  253. const double d = dot(PA, V); // Dist. from P to triangle plane times norm of V
  254. const double e = dot(V, V); // Norm of V
  255. if (d * d > rr * e) return false; // Test if separating plane between sphere and triangle plane
  256. // Test if separating plane between sphere and triangle vertices
  257. const SVector3 PB(P, B), PC(P, B);
  258. const double aa = dot(PA, PA), ab = dot(PA, PB), ac = dot(PA, PC);
  259. const double bb = dot(PB, PB), bc = dot(PB, PC), cc = dot(PC, PC);
  260. if ((aa > rr) & (ab > aa) & (ac > aa)) return false; // For each triangle vertex, separation if vertex is outside sphere
  261. if ((bb > rr) & (ab > bb) & (bc > bb)) return false; // and P on opposite side to other two triangle vertices w.r.t
  262. if ((cc > rr) & (ac > cc) & (bc > cc)) return false; // plane of normal (vertex-P) through vertex
  263. // Test if separating plane between sphere and triangle edges
  264. const SVector3 BC(B, C);
  265. const double d1 = ab - aa, d2 = bc - bb, d3 = ac - cc;
  266. const double e1 = dot(AB, AB), e2 = dot(BC, BC), e3 = dot(AC, AC);
  267. const SVector3 PQ1 = PA * e1 - d1 * AB; // Q1 projection of P on line (AB)
  268. const SVector3 PQ2 = PB * e2 - d2 * BC; // Q2 projection of P on line (BC)
  269. const SVector3 PQ3 = PC * e3 + d3 * AC; // Q3 projection of P on line (AC)
  270. const SVector3 PQC = PC * e1 - PQ1;
  271. const SVector3 PQA = PA * e2 - PQ2;
  272. const SVector3 PQB = PB * e3 - PQ3;
  273. if ((dot(PQ1, PQ1) > rr * e1 * e1) & (dot(PQ1, PQC) > 0)) return false; // For A, separation if Q lies outside the sphere and if P and C
  274. if ((dot(PQ2, PQ2) > rr * e2 * e2) & (dot(PQ2, PQA) > 0)) return false; // are on opposite sides of plane through AB with normal PQ
  275. if ((dot(PQ3, PQ3) > rr * e3 * e3) & (dot(PQ3, PQB) > 0)) return false; // Same for other two vertices
  276. // Return true (intersection) if no separation at all
  277. return true;
  278. }
  279. }
  280. // Test of intersection element with circle/sphere
  281. bool MeshOptPatchDef::testElInDist(const SPoint3 &P, double limDist,
  282. MElement *el) const
  283. {
  284. const double limDistSq = limDist*limDist;
  285. if (el->getDim() == 2) { // 2D?
  286. for (int iEd = 0; iEd < el->getNumEdges(); iEd++) { // Loop over edges of element
  287. std::vector<MVertex*> edgeVert;
  288. el->getEdgeVertices(iEd, edgeVert);
  289. const SPoint3 A = edgeVert[0]->point();
  290. const SPoint3 B = edgeVert[1]->point();
  291. if (testSegSphereIntersect(A, B, P, limDistSq)) return true;
  292. }
  293. }
  294. else { // 3D
  295. for (int iFace = 0; iFace < el->getNumFaces(); iFace++) { // Loop over faces of element
  296. std::vector<MVertex*> faceVert;
  297. el->getFaceVertices(iFace, faceVert);
  298. const SPoint3 A = faceVert[0]->point();
  299. const SPoint3 B = faceVert[1]->point();
  300. const SPoint3 C = faceVert[2]->point();
  301. if (faceVert.size() == 3) {
  302. if (testTriSphereIntersect(A, B, C, P, limDistSq)) return true;
  303. }
  304. else {
  305. const SPoint3 D = faceVert[3]->point();
  306. if (testTriSphereIntersect(A, B, C, P, limDistSq) ||
  307. testTriSphereIntersect(A, C, D, P, limDistSq)) return true;
  308. }
  309. }
  310. }
  311. return false;
  312. }