GLVis  v4.2
Accurate and flexible finite element visualization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
vssolution3d.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-443271.
4 //
5 // This file is part of the GLVis visualization tool and library. For more
6 // information and source code availability see https://glvis.org.
7 //
8 // GLVis is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 #include <cstdlib>
13 #include <iostream>
14 #include <cmath>
15 #include <limits>
16 
17 #include "mfem.hpp"
18 #include "visual.hpp"
19 #include "palettes.hpp"
20 using namespace mfem;
21 using namespace std;
22 
23 
25 extern thread_local GeometryRefiner GLVisGeometryRefiner;
26 
27 // Reference geometries with a cut in the middle, based on subdivision of
28 // GLVisGeometryRefiner in 3-4 quads. Updated when cut_lambda is updated, see
29 // keys Ctrl+F3/F4. We need these variables because the GLVisGeometryRefiner
30 // cashes its RefinedGeometry objects.
31 thread_local IntegrationRule cut_QuadPts;
32 thread_local Array<int> cut_QuadGeoms;
33 thread_local IntegrationRule cut_TriPts;
34 thread_local Array<int> cut_TriGeoms;
35 
36 // Definitions of some more keys
37 
39 {
40  std::stringstream os;
41  os << endl
42  << "+------------------------------------+" << endl
43  << "| Keys |" << endl
44  << "+------------------------------------+" << endl
45  << "| a - Displays/Hides the axes |" << endl
46  << "| A - Turns antialiasing on/off |" << endl
47  << "| c - Toggle colorbar and caption |" << endl
48  << "| C - Change the main plot caption |" << endl
49  << "| e - Displays/Hides the elements |" << endl
50  << "| E - Toggle the elements in the CP |" << endl
51  << "| f - Smooth/Flat/discont. shading |" << endl
52  << "| g - Toggle background |" << endl
53  << "| G - Export to glTF format |" << endl
54  << "| h - Displays help menu |" << endl
55  << "| i - Toggle cutting plane |" << endl
56  << "| I - Toggle cutting plane algorithm|" << endl
57  << "| j - Turn on/off perspective |" << endl
58  << "| k/K Adjust the transparency level |" << endl
59  << "| ,/< Adjust color transparency |" << endl
60  << "| l - Turns on/off the light |" << endl
61  << "| L - Toggle logarithmic scale |" << endl
62  << "| m - Displays/Hides the mesh |" << endl
63  << "| M - Toggle the mesh in the CP |" << endl
64  << "| o/O (De)refine elem, disc shading |" << endl
65  << "| p/P Cycle through color palettes |" << endl
66  << "| q - Quits |" << endl
67  << "| r - Reset the plot to 3D view |" << endl
68  << "| R - Reset the plot to 2D view |" << endl
69  << "| s - Turn on/off unit cube scaling |" << endl
70  << "| S - Take snapshot/Record a movie |" << endl
71  << "| t - Cycle materials and lights |" << endl
72  << "| u/U Move the level surface |" << endl
73  << "| v/V Add/Delete a level surface |" << endl
74  << "| w/W Move bdr elements up/down |" << endl
75  << "| x/X Rotate cutting plane (phi) |" << endl
76  << "| y/Y Rotate cutting plane (theta) |" << endl
77  << "| z/Z Translate cutting plane |" << endl
78  << "| \\ - Set light source position |" << endl
79  << "| Ctrl+o - Element ordering curve |" << endl
80  << "| Ctrl+p - Print to a PDF file |" << endl
81  << "+------------------------------------+" << endl
82  << "| Function keys |" << endl
83  << "+------------------------------------+" << endl
84  << "| F1 - X window info and keystrokes |" << endl
85  << "| F2 - Update colors, etc. |" << endl
86  << "| F3/F4 - Shrink/Zoom bdr elements |" << endl
87  << "| Ctrl+F3/F4 - Cut face bdr elements |" << endl
88  << "| F5 - Set level lines |" << endl
89  << "| F6 - Palette options |" << endl
90  << "| F7 - Manually set min/max value |" << endl
91  << "| F8 - List of subdomains to show |" << endl
92  << "| F9/F10 - Walk through subdomains |" << endl
93  << "| F11/F12 - Shrink/Zoom subdomains |" << endl
94  << "+------------------------------------+" << endl
95  << "| Keypad |" << endl
96  << "+------------------------------------+" << endl
97  << "| 1-9 Small rotation, reset with 5 |" << endl
98  << "| *,/ Scale up/down |" << endl
99  << "| +/- Change z-scaling |" << endl
100  << "| . - Start/stop spinning |" << endl
101  << "| 0/Enter - Spinning speed and dir. |" << endl
102  << "+------------------------------------+" << endl
103  << "| Mouse |" << endl
104  << "+------------------------------------+" << endl
105  << "| left btn - Rotation |" << endl
106  << "| middle btn - Translation |" << endl
107  << "| right btn - Scaling |" << endl
108  << "| left + Alt - Tilt |" << endl
109  << "| left + Shift - Spinning |" << endl
110  << "| right + Shift - Change light pos. |" << endl
111  << "| left + Ctrl - Spherical rotation |" << endl
112  << "| middle+ Ctrl - Object translation |" << endl
113  << "| right + Ctrl - Object scaling |" << endl
114  << "| left + Ctrl + Shift - z-Spinning |" << endl
115  << "+------------------------------------+" << endl;
116  return os.str();
117 }
118 
119 static void KeyiPressed()
120 {
121  vssol3d -> ToggleCuttingPlane();
122  SendExposeEvent();
123 }
124 
125 static void KeyIPressed()
126 {
127  vssol3d -> ToggleCPAlgorithm();
128  SendExposeEvent();
129 }
130 
132 {
133  bool color = draworder < 3;
134  order_buf.clear();
135  order_noarrow_buf.clear();
136  PrepareOrderingCurve1(order_buf, true, color);
137  PrepareOrderingCurve1(order_noarrow_buf, false, color);
138  updated_bufs.emplace_back(&order_buf);
139  updated_bufs.emplace_back(&order_noarrow_buf);
140 }
141 
142 
144  bool arrows,
145  bool color)
146 {
147  gl3::GlBuilder builder = buf.createBuilder();
148 
149  // make the lines of the ordering curve thicker
150  double ThicknessFactor = 2.0;
151  double MS_Thickness = 2.0;
152  double LineWidth;
153  if (GetMultisample() > 0)
154  {
155  LineWidth = GetLineWidthMS();
156  SetLineWidthMS(MS_Thickness);
157  }
158  else
159  {
160  LineWidth = GetLineWidth();
161  SetLineWidth(ThicknessFactor*LineWidth);
162  }
163 
164  DenseMatrix pointmat;
165  Array<int> vertices;
166 
167  DenseMatrix pointmat1;
168  Array<int> vertices1;
169 
170  int ne = mesh->GetNE();
171  for (int k = 0; k < ne-1; k++)
172  {
173  mesh->GetPointMatrix (k, pointmat);
174  mesh->GetElementVertices (k, vertices);
175  mesh->GetPointMatrix (k+1, pointmat1);
176  mesh->GetElementVertices (k+1, vertices1);
177  int nv = vertices.Size();
178  int nv1 = vertices1.Size();
179 
180  ShrinkPoints(pointmat, k, 0, 0);
181  ShrinkPoints(pointmat1, k+1, 0, 0);
182 
183  double xs = 0.0;
184  double ys = 0.0;
185  double zs = 0.0;
186  for (int j = 0; j < nv; j++)
187  {
188  xs += pointmat(0,j);
189  ys += pointmat(1,j);
190  zs += pointmat(2,j);
191  }
192  xs /= nv;
193  ys /= nv;
194  zs /= nv;
195 
196  double xs1 = 0.0;
197  double ys1 = 0.0;
198  double zs1 = 0.0;
199  for (int j = 0; j < nv1; j++)
200  {
201  xs1 += pointmat1(0,j);
202  ys1 += pointmat1(1,j);
203  zs1 += pointmat1(2,j);
204  }
205  xs1 /= nv1;
206  ys1 /= nv1;
207  zs1 /= nv1;
208 
209  double dx = xs1-xs;
210  double dy = ys1-ys;
211  double dz = zs1-zs;
212  double ds = sqrt(dx*dx+dy*dy+dz*dz);
213 
214  if (color)
215  {
216  double cval = minv+double(k)/ne*(maxv-minv);
217  MySetColor(builder, cval, minv, maxv);
218  }
219 
220  if (arrows)
221  {
222  Arrow3(builder,
223  xs,ys,zs,
224  dx,dy,dz,
225  ds,0.05);
226  }
227  else
228  {
229  Arrow3(builder,
230  xs,ys,zs,
231  dx,dy,dz,
232  ds,0.0);
233  }
234  }
235 
236  if (GetMultisample() > 0)
237  {
238  SetLineWidthMS(LineWidth);
239  }
240  else
241  {
242  SetLineWidth(LineWidth);
243  }
244 }
245 
247 {
248  PrepareCuttingPlane();
249  PrepareCuttingPlaneLines();
250 }
251 
253 {
254  CPPrepare();
255  if (cplane == 2)
256  {
257  Prepare();
258  PrepareLines();
259  }
260 }
261 
262 static void KeyxPressed()
263 {
264  vssol3d -> CuttingPlane -> IncreasePhi();
265  vssol3d -> FindNodePos();
266  vssol3d -> CPMoved();
267  SendExposeEvent();
268 }
269 
270 static void KeyXPressed()
271 {
272  vssol3d -> CuttingPlane -> DecreasePhi();
273  vssol3d -> FindNodePos();
274  vssol3d -> CPMoved();
275  SendExposeEvent();
276 }
277 
278 static void KeyyPressed()
279 {
280  vssol3d -> CuttingPlane -> IncreaseTheta();
281  vssol3d -> FindNodePos();
282  vssol3d -> CPMoved();
283  SendExposeEvent();
284 }
285 
286 static void KeyYPressed()
287 {
288  vssol3d -> CuttingPlane -> DecreaseTheta();
289  vssol3d -> FindNodePos();
290  vssol3d -> CPMoved();
291  SendExposeEvent();
292 }
293 
294 static void KeyzPressed()
295 {
296  vssol3d -> CuttingPlane -> IncreaseDistance();
297  vssol3d -> FindNodePos();
298  vssol3d -> CPMoved();
299  SendExposeEvent();
300 }
301 
302 static void KeyZPressed()
303 {
304  vssol3d -> CuttingPlane -> DecreaseDistance();
305  vssol3d -> FindNodePos();
306  vssol3d -> CPMoved();
307  SendExposeEvent();
308 }
309 
310 static void KeymPressed()
311 {
312  vssol3d -> ToggleDrawMesh();
313  SendExposeEvent();
314 }
315 
316 static void KeyePressed()
317 {
318  vssol3d -> ToggleDrawElems();
319  SendExposeEvent();
320 }
321 
322 static void KeyMPressed()
323 {
324  vssol3d -> ToggleCPDrawMesh();
325  SendExposeEvent();
326 }
327 
328 static void KeyEPressed()
329 {
330  vssol3d -> ToggleCPDrawElems();
331  SendExposeEvent();
332 }
333 
334 static void KeyFPressed()
335 {
336  vssol3d -> ToggleShading();
337  SendExposeEvent();
338 }
339 
340 static void KeyoPressed(GLenum state)
341 {
342  if (state & KMOD_CTRL)
343  {
344  vssol3d -> ToggleDrawOrdering();
345  vssol3d -> PrepareOrderingCurve();
346  SendExposeEvent();
347  }
348  else
349  {
350  if (vssol3d -> TimesToRefine < 32)
351  {
352  cout << "Subdivision factor = " << ++vssol3d->TimesToRefine << endl;
353  if (vssol3d -> GetShading() == 2)
354  {
355  vssol3d->DoAutoscale(false);
356  vssol3d -> Prepare();
357  vssol3d -> PrepareLines();
358  vssol3d -> CPPrepare();
359  vssol3d -> PrepareLevelSurf();
360  SendExposeEvent();
361  }
362  }
363  }
364 }
365 
366 static void KeyOPressed()
367 {
368  if (vssol3d -> TimesToRefine > 1)
369  {
370  cout << "Subdivision factor = " << --vssol3d->TimesToRefine << endl;
371  if (vssol3d -> GetShading() == 2)
372  {
373  vssol3d->DoAutoscale(false);
374  vssol3d -> Prepare();
375  vssol3d -> PrepareLines();
376  vssol3d -> CPPrepare();
377  vssol3d -> PrepareLevelSurf();
378  SendExposeEvent();
379  }
380  }
381 }
382 
383 static void KeywPressed()
384 {
385  if (vssol3d -> GetShading() == 2)
386  {
387  if ( fabs(vssol3d -> FaceShiftScale += 0.01) < 0.001 )
388  {
389  vssol3d -> FaceShiftScale = 0.0;
390  }
391  cout << "New Shift Scale: " << vssol3d -> FaceShiftScale
392  << endl;
393  vssol3d -> Prepare();
394  vssol3d -> PrepareLines();
395  vssol3d -> CPPrepare();
396  SendExposeEvent();
397  }
398 }
399 
400 static void KeyWPressed()
401 {
402  if (vssol3d -> GetShading() == 2)
403  {
404  if ( fabs(vssol3d -> FaceShiftScale -= 0.01) < 0.001 )
405  {
406  vssol3d -> FaceShiftScale = 0.0;
407  }
408  cout << "New Shift Scale: " << vssol3d -> FaceShiftScale
409  << endl;
410  vssol3d -> Prepare();
411  vssol3d -> PrepareLines();
412  vssol3d -> CPPrepare();
413  SendExposeEvent();
414  }
415 }
416 
417 static void KeyuPressed()
418 {
419  vssol3d -> MoveLevelSurf(+1);
420  SendExposeEvent();
421 }
422 
423 static void KeyUPressed()
424 {
425  vssol3d -> MoveLevelSurf(-1);
426  SendExposeEvent();
427 }
428 
429 static void KeyvPressed()
430 {
431  vssol3d -> NumberOfLevelSurf(+1);
432  SendExposeEvent();
433 }
434 
435 static void KeyVPressed()
436 {
437  vssol3d -> NumberOfLevelSurf(-1);
438  SendExposeEvent();
439 }
440 
441 static int magic_key_pressed = 0;
443 {
444  magic_key_pressed = 1-magic_key_pressed;
445 }
446 
447 static void KeyF3Pressed(GLenum state)
448 {
449  if (state & KMOD_CTRL)
450  {
451  if (vssol3d->cut_lambda <= 0.95)
452  {
453  vssol3d->cut_lambda += 0.05;
454  vssol3d->cut_updated = false;
455  }
456  if (fabs(vssol3d->cut_lambda-1.0) < 1e-12) // snap to 1
457  {
458  vssol3d->cut_lambda = 1.0;
459  }
460  vssol3d->Prepare();
461  SendExposeEvent();
462  }
463  else
464  {
465  if (vssol3d->GetShading() == 2)
466  {
467  if (vssol3d->GetMesh()->Dimension() == 3 && vssol3d->bdrc.Width() == 0)
468  {
470  }
471  if (vssol3d->GetMesh()->Dimension() == 2 && vssol3d->matc.Width() == 0)
472  {
474  }
475  vssol3d->shrink *= 0.9;
476  if (magic_key_pressed)
477  {
478  vssol3d -> Scale(1.11111111111111111111111);
479  }
480  SendExposeEvent();
481  vssol3d->Prepare();
483  SendExposeEvent();
484  }
485  }
486 }
487 
488 static void KeyF4Pressed(GLenum state)
489 {
490  if (state & KMOD_CTRL)
491  {
492  if (vssol3d->cut_lambda >= 0.05)
493  {
494  vssol3d->cut_lambda -= 0.05;
495  vssol3d->cut_updated = false;
496  }
497  if (fabs(vssol3d->cut_lambda-0.0) < 1e-12) // snap to 0
498  {
499  vssol3d->cut_lambda = 0.0;
500  }
501  vssol3d->Prepare();
502  SendExposeEvent();
503  }
504  else
505  {
506  if (vssol3d->GetShading() == 2)
507  {
508  if (vssol3d->GetMesh()->Dimension() == 3 && vssol3d->bdrc.Width() == 0)
509  {
511  }
512  if (vssol3d->GetMesh()->Dimension() == 2 && vssol3d->matc.Width() == 0)
513  {
515  }
516  vssol3d->shrink *= 1.11111111111111111111111;
517  if (magic_key_pressed)
518  {
519  vssol3d -> Scale(0.9);
520  }
521  vssol3d->Prepare();
523  SendExposeEvent();
524  }
525  }
526 }
527 
528 static void KeyF11Pressed()
529 {
530  if (vssol3d->GetShading() == 2)
531  {
532  if (vssol3d->matc.Width() == 0)
533  {
535  }
536  vssol3d->shrinkmat *= 0.9;
537  if (magic_key_pressed)
538  {
539  vssol3d -> Scale(1.11111111111111111111111);
540  }
541  vssol3d->Prepare();
543  SendExposeEvent();
544  }
545 }
546 
547 static void KeyF12Pressed()
548 {
549  if (vssol3d->GetShading() == 2)
550  {
551  if (vssol3d->matc.Width() == 0)
552  {
554  }
555  vssol3d->shrinkmat *= 1.11111111111111111111111;
556  if (magic_key_pressed)
557  {
558  vssol3d -> Scale(0.9);
559  }
560  vssol3d->Prepare();
562  SendExposeEvent();
563  }
564 }
565 
566 static void KeyF8Pressed()
567 {
568  Mesh &mesh = *vssol3d->GetMesh();
569  int dim = mesh.Dimension();
570  const Array<int> &all_attr = ((dim == 3) ? mesh.bdr_attributes :
571  mesh.attributes);
572  Array<int> &attr_marker = vssol3d->bdr_attr_to_show;
573  int attr;
574  Array<int> attr_list(&attr, 1);
575 
576  cout << ((dim == 3) ? "Bdr a" : "A") << "ttributes ON: ";
577  for (int i = 0; i < all_attr.Size(); i++)
578  if (attr_marker[all_attr[i]-1])
579  {
580  cout << " " << all_attr[i];
581  }
582  cout << endl;
583 
584  cout << ((dim == 3) ? "Bdr a" : "A") << "ttribute to toggle : " << flush;
585  cin >> attr;
586  vssol3d->ToggleAttributes(attr_list);
587  SendExposeEvent();
588 }
589 
590 static void KeyF9Pressed()
591 {
592  Mesh &mesh = *vssol3d->GetMesh();
593  int dim = mesh.Dimension();
594  const Array<int> &attr_list = ((dim == 3) ? mesh.bdr_attributes :
595  mesh.attributes);
596  Array<int> &attr_marker = vssol3d->bdr_attr_to_show;
597  int attr, n, j, i;
598 
599  if (attr_list.Size() == 0)
600  {
601  return;
602  }
603  for (i = j = n = 0; i < attr_list.Size(); i++)
604  if (attr_marker[attr_list[i]-1])
605  {
606  j = i, n++;
607  }
608  if (n == 1)
609  {
610  j = (j + 1) % (attr_list.Size() + 1);
611  }
612  else
613  {
614  j = 0;
615  }
616  if (j == attr_list.Size())
617  {
618  attr_marker = 1;
619  cout << "Showing all " << ((dim == 3) ? "bdr " : "") << "attributes "
620  << endl;
621  }
622  else
623  {
624  attr = attr_list[j];
625  attr_marker = 0;
626  attr_marker[attr-1] = 1;
627  cout << "Showing " << ((dim == 3) ? "bdr " : "") << "attribute "
628  << attr << endl;
629  }
630  vssol3d -> PrepareLines();
631  vssol3d -> Prepare();
632  SendExposeEvent();
633 }
634 
635 static void KeyF10Pressed()
636 {
637  Mesh &mesh = *vssol3d->GetMesh();
638  int dim = mesh.Dimension();
639  const Array<int> &attr_list = ((dim == 3) ? mesh.bdr_attributes :
640  mesh.attributes);
641  Array<int> &attr_marker = vssol3d->bdr_attr_to_show;
642  int attr, n, j, i;
643 
644  if (attr_list.Size() == 0)
645  {
646  return;
647  }
648  n = 0;
649  for (i = j = n = 0; i < attr_list.Size(); i++)
650  if (attr_marker[attr_list[i]-1])
651  {
652  j = i, n++;
653  }
654  if (n == 1)
655  {
656  j = (j + attr_list.Size()) % (attr_list.Size() + 1);
657  }
658  else
659  {
660  j = attr_list.Size() - 1;
661  }
662  if (j == attr_list.Size())
663  {
664  attr_marker = 1;
665  cout << "Showing all " << ((dim == 3) ? "bdr " : "") << "attributes "
666  << endl;
667  }
668  else
669  {
670  attr = attr_list[j];
671  attr_marker = 0;
672  attr_marker[attr-1] = 1;
673  cout << "Showing " << ((dim == 3) ? "bdr " : "") << "attribute "
674  << attr << endl;
675  }
676  vssol3d -> PrepareLines();
677  vssol3d -> Prepare();
678  SendExposeEvent();
679 }
680 
682 {}
683 
685 {
686  mesh = &m;
687  sol = &s;
688  GridF = NULL;
689 
690  Init();
691 }
692 
693 
695 {
696  vssol3d = this;
697 
698  cplane = 0;
699  cp_drawmesh = 0; cp_drawelems = 1;
700  drawlsurf = 0;
701  cp_algo = 0;
702 
703  drawelems = shading = 1;
704  drawmesh = 0;
705  draworder = 0;
706  scaling = 0;
707 
708  shrink = 1.0;
709  shrinkmat = 1.0;
710  bdrc.SetSize(3,0);
711  matc.SetSize(3,0);
712 
713  TimesToRefine = 1;
714  FaceShiftScale = 0.0;
715 
716  if (mesh->Dimension() == 3)
717  {
718  if (!mesh->bdr_attributes.Size())
719  {
720  MFEM_WARNING("Missing boundary attributes!");
721  }
722  bdr_attr_to_show.SetSize(mesh->bdr_attributes.Size() > 0 ?
723  mesh->bdr_attributes.Max() : 0);
724  }
725  else
726  {
727  if (!mesh->attributes.Size())
728  {
729  MFEM_WARNING("Missing element attributes!");
730  }
731  bdr_attr_to_show.SetSize(mesh->attributes.Size() > 0 ?
732  mesh->attributes.Max() : 0);
733  }
734  bdr_attr_to_show = 1;
735 
736  VisualizationSceneScalarData::Init(); // calls FindNewBox
737 
738  FindNewValueRange(false);
739 
740  node_pos = new double[mesh->GetNV()];
741 
742  palette.SetIndex(12); // use the 'vivid' palette in 3D
743 
744  double eps = 1e-6; // move the cutting plane a bit to avoid artifacts
745  CuttingPlane = new Plane(-1.0,0.0,0.0,(0.5-eps)*bb.x[0]+(0.5+eps)*bb.x[1]);
746 
747  nlevels = 1;
748 
749  FindNodePos();
750 
751  // static int init = 0;
752  // if (!init)
753  {
754  // init = 1;
755 
756  wnd->setOnKeyDown('m', KeymPressed);
757  wnd->setOnKeyDown('M', KeyMPressed);
758 
759  wnd->setOnKeyDown('e', KeyePressed);
760  wnd->setOnKeyDown('E', KeyEPressed);
761 
762  wnd->setOnKeyDown('f', KeyFPressed);
763  // wnd->setOnKeyDown('F', KeyFPressed);
764 
767 
768  wnd->setOnKeyDown('o', KeyoPressed);
769  wnd->setOnKeyDown('O', KeyOPressed);
770 
771  wnd->setOnKeyDown('w', KeywPressed);
772  wnd->setOnKeyDown('W', KeyWPressed);
773 
774  wnd->setOnKeyDown('x', KeyxPressed);
775  wnd->setOnKeyDown('X', KeyXPressed);
776 
777  wnd->setOnKeyDown('y', KeyyPressed);
778  wnd->setOnKeyDown('Y', KeyYPressed);
779 
780  wnd->setOnKeyDown('z', KeyzPressed);
781  wnd->setOnKeyDown('Z', KeyZPressed);
782 
785 
788 
789  wnd->setOnKeyDown(SDLK_F3, KeyF3Pressed);
790  wnd->setOnKeyDown(SDLK_F4, KeyF4Pressed);
791  wnd->setOnKeyDown(SDLK_NUMLOCKCLEAR, ToggleMagicKey);
792 
793  wnd->setOnKeyDown(SDLK_F8, KeyF8Pressed);
794  wnd->setOnKeyDown(SDLK_F9, KeyF9Pressed);
795  wnd->setOnKeyDown(SDLK_F10, KeyF10Pressed);
796 
797  wnd->setOnKeyDown(SDLK_F11, KeyF11Pressed);
798  wnd->setOnKeyDown(SDLK_F12, KeyF12Pressed);
799  }
800  Prepare();
801  PrepareLines();
802  CPPrepare();
803  PrepareLevelSurf();
804  PrepareOrderingCurve();
805 }
806 
808 {
809  delete [] node_pos;
810 }
811 
813  Mesh *new_m, Vector *new_sol, GridFunction *new_u)
814 {
815  if (mesh->GetNV() != new_m->GetNV())
816  {
817  delete [] node_pos;
818  node_pos = new double[new_m->GetNV()];
819  }
820  // If the number of surface elements changes, recompute the refinement factor
821  if (mesh->Dimension() != new_m->Dimension() ||
822  (mesh->Dimension() == 2 && mesh->GetNE() != new_m->GetNE()) ||
823  (mesh->Dimension() == 3 && mesh->GetNBE() != new_m->GetNBE()))
824  {
825  mesh = new_m;
826  int ref = GetAutoRefineFactor();
827  if (TimesToRefine != ref)
828  {
829  TimesToRefine = ref;
830  cout << "Subdivision factor = " << TimesToRefine << endl;
831  }
832  }
833  mesh = new_m;
834  sol = new_sol;
835  GridF = new_u;
836  FindNodePos();
837 
838  DoAutoscale(false);
839 
840  Prepare();
841  PrepareLines();
842  CPPrepare();
843  PrepareLevelSurf();
844  PrepareOrderingCurve();
845 }
846 
848 {
849  if (shading == s || s < 0)
850  {
851  return;
852  }
853 
854  if (s > 2 || (GridF == NULL && s > 1))
855  {
856  return;
857  }
858  int os = shading;
859  shading = s;
860  if (GridF != NULL && (s == 2 || os == 2))
861  {
862  DoAutoscale(false);
863  PrepareLines();
864  CPPrepare();
865  }
866  Prepare();
867  PrepareLevelSurf();
868 
869  static const char *shading_type[3] =
870  {"flat", "smooth", "non-conforming (with subdivision)"};
871  if (print)
872  {
873  cout << "Shading type : " << shading_type[shading] << endl;
874  }
875 }
876 
878 {
879  if (GridF)
880  {
881  SetShading((shading+1)%3, true);
882  }
883  else
884  {
885  SetShading(1-shading, true);
886  }
887 }
888 
890 {
891  if (TimesToRefine == f || f < 1)
892  {
893  return;
894  }
895 
896  TimesToRefine = f;
897 
898  if (shading == 2)
899  {
900  DoAutoscale(false);
901  Prepare();
902  PrepareLines();
903  CPPrepare();
904  PrepareOrderingCurve();
905  }
906 }
907 
909 {
910  int ne = mesh->GetNBE(), ref = 1;
911  if (mesh->Dimension() == 2)
912  {
913  ne = mesh->GetNE();
914  }
915 
916  while (ref < auto_ref_max && ne*(ref+1)*(ref+1) <= auto_ref_max_surf_elem)
917  {
918  ref++;
919  }
920 
921  return ref;
922 }
923 
925 {
926  int ref = GetAutoRefineFactor();
927 
928  cout << "Subdivision factor = " << ref << endl;
929 
930  SetRefineFactors(ref, 1);
931 }
932 
934 {
935  int dim = mesh->Dimension();
936  Array<int> &attr_marker = bdr_attr_to_show;
937 
938  for (int i = 0; i < attr_list.Size(); i++)
939  {
940  int attr = attr_list[i];
941  if (attr < 1)
942  {
943  cout << "Hiding all" << ((dim == 3) ? " bdr" : "") << " attributes."
944  << endl;
945  attr_marker = 0;
946  }
947  else if (attr > attr_marker.Size())
948  {
949  cout << "Showing all" << ((dim == 3) ? " bdr" : "") << " attributes."
950  << endl;
951  attr_marker = 1;
952  }
953  else
954  {
955  attr_marker[attr-1] = !attr_marker[attr-1];
956  }
957  }
958  PrepareLines();
959  Prepare();
960 }
961 
963 {
964  int nv = mesh -> GetNV();
965 
966  double *coord = mesh->GetVertex(0);
967 
968  bb.x[0] = bb.x[1] = coord[0];
969  bb.y[0] = bb.y[1] = coord[1];
970  bb.z[0] = bb.z[1] = coord[2];
971 
972  for (int i = 1; i < nv; i++)
973  {
974  coord = mesh->GetVertex(i);
975  if (coord[0] < bb.x[0]) { bb.x[0] = coord[0]; }
976  if (coord[1] < bb.y[0]) { bb.y[0] = coord[1]; }
977  if (coord[2] < bb.z[0]) { bb.z[0] = coord[2]; }
978  if (coord[0] > bb.x[1]) { bb.x[1] = coord[0]; }
979  if (coord[1] > bb.y[1]) { bb.y[1] = coord[1]; }
980  if (coord[2] > bb.z[1]) { bb.z[1] = coord[2]; }
981  }
982 
983  if (shading == 2)
984  {
985  int dim = mesh->Dimension();
986  int ne = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
987  int fn, fo;
988  DenseMatrix pointmat;
989  RefinedGeometry *RefG;
990  IntegrationRule eir;
991  FaceElementTransformations *Tr;
992  ElementTransformation *T;
993 
994  for (int i = 0; i < ne; i++)
995  {
996  if (dim == 3)
997  {
998  mesh->GetBdrElementFace(i, &fn, &fo);
999  RefG = GLVisGeometryRefiner.Refine(mesh->GetFaceBaseGeometry(fn),
1000  TimesToRefine);
1001  Tr = mesh->GetFaceElementTransformations(fn, 5);
1002  eir.SetSize(RefG->RefPts.GetNPoints());
1003  Tr->Loc1.Transform(RefG->RefPts, eir);
1004  Tr->Elem1->Transform(eir, pointmat);
1005  }
1006  else
1007  {
1008  T = mesh->GetElementTransformation(i);
1009  RefG = GLVisGeometryRefiner.Refine(mesh->GetElementBaseGeometry(i),
1010  TimesToRefine);
1011  T->Transform(RefG->RefPts, pointmat);
1012  }
1013  for (int j = 0; j < pointmat.Width(); j++)
1014  {
1015  if (pointmat(0,j) < bb.x[0]) { bb.x[0] = pointmat(0,j); }
1016  if (pointmat(1,j) < bb.y[0]) { bb.y[0] = pointmat(1,j); }
1017  if (pointmat(2,j) < bb.z[0]) { bb.z[0] = pointmat(2,j); }
1018  if (pointmat(0,j) > bb.x[1]) { bb.x[1] = pointmat(0,j); }
1019  if (pointmat(1,j) > bb.y[1]) { bb.y[1] = pointmat(1,j); }
1020  if (pointmat(2,j) > bb.z[1]) { bb.z[1] = pointmat(2,j); }
1021  }
1022  }
1023  }
1024 
1025  UpdateBoundingBox();
1026 }
1027 
1029 {
1030  if (shading < 2)
1031  {
1032  minv = sol->Min();
1033  maxv = sol->Max();
1034  }
1035  else
1036  {
1037  minv = GridF->Min();
1038  maxv = GridF->Max();
1039  }
1040  FixValueRange();
1041  UpdateValueRange(prepare);
1042 }
1043 
1045 {
1046  Prepare();
1047  PrepareCuttingPlane();
1048  PrepareLevelSurf();
1049  PrepareOrderingCurve();
1050  if (shading == 2 && drawmesh != 0 && FaceShiftScale != 0.0)
1051  {
1052  PrepareLines();
1053  }
1054 }
1055 
1057 {
1058  logscale = logscale && LogscaleRange();
1059  palette.SetUseLogscale(logscale);
1060  SetLogA();
1061  SetLevelLines(minv, maxv, nl);
1062  if (prepare)
1063  {
1064  UpdateLevelLines();
1065  EventUpdateColors();
1066  }
1067 }
1068 
1070 {
1071  int i, nnodes = mesh -> GetNV();
1072 
1073  for (i = 0; i < nnodes; i++)
1074  {
1075  node_pos[i] = CuttingPlane -> Transform (mesh -> GetVertex (i));
1076  }
1077 }
1078 
1080 {
1081  drawmesh = (drawmesh+1)%3;
1082  PrepareLines();
1083 }
1084 
1086 {
1087  if (cplane == 2 && cp_drawmesh == 3)
1088  {
1089  cp_drawmesh = 2;
1090  }
1091 
1092  cplane = (cplane+1)%3;
1093 #ifdef GLVIS_DEBUG
1094  cout << "cplane = " << cplane << endl;
1095 #endif
1096  CPPrepare();
1097  if (cplane == 0 || cplane == 2)
1098  {
1099  Prepare();
1100  PrepareLines();
1101  PrepareOrderingCurve();
1102  }
1103 }
1104 
1106 {
1107  cp_drawelems = 1-cp_drawelems;
1108  PrepareCuttingPlane();
1109 }
1110 
1112 {
1113  if (cplane == 1)
1114  {
1115  cp_drawmesh = (cp_drawmesh+1)%3;
1116  }
1117  else if (cplane == 2)
1118  {
1119  cp_drawmesh = (cp_drawmesh+1)%4;
1120  }
1121  PrepareCuttingPlaneLines();
1122 }
1123 
1125 {
1126  cp_algo = (cp_algo+1)%2;
1127  if (shading == 2 && cplane == 1)
1128  {
1129  CPPrepare();
1130  }
1131 }
1132 
1134 {
1135  drawlsurf += move;
1136  if (drawlsurf < 0)
1137  {
1138  drawlsurf = 0;
1139  }
1140  if (drawlsurf > 49)
1141  {
1142  drawlsurf = 49;
1143  }
1144  PrepareLevelSurf();
1145 }
1146 
1148 {
1149  nlevels += c;
1150  if (nlevels < 1)
1151  {
1152  nlevels = 1;
1153  }
1154  PrepareLevelSurf();
1155 }
1156 
1158  const int FaceNo, const int side, const IntegrationRule &ir,
1159  DenseMatrix &normals)
1160 {
1161  // match the way GridFunction::GetFaceValues works
1162  double aJInv[9], alnor[3];
1163  DenseMatrix JInv(aJInv, 3, 3);
1164  Vector lnor(alnor, 3), nr;
1165  IntegrationRule eir(ir.GetNPoints());
1166  FaceElementTransformations *Tr;
1167  normals.SetSize(3, ir.GetNPoints());
1168  ElementTransformation *ETr;
1169  IntegrationPointTransformation *LTr;
1170  if (side == 0)
1171  {
1172  Tr = mesh->GetFaceElementTransformations(FaceNo, 5);
1173  ETr = Tr->Elem1;
1174  LTr = &Tr->Loc1;
1175  }
1176  else
1177  {
1178  Tr = mesh->GetFaceElementTransformations(FaceNo, 10);
1179  ETr = Tr->Elem2;
1180  LTr = &Tr->Loc2;
1181  }
1182  LTr->Transform(ir, eir);
1183  for (int i = 0; i < normals.Width(); i++)
1184  {
1185  LTr->Transf.SetIntPoint(&ir.IntPoint(i));
1186  CalcOrtho(LTr->Transf.Jacobian(), lnor);
1187  ETr->SetIntPoint(&eir.IntPoint(i));
1188  const DenseMatrix &Jac = ETr->Jacobian();
1189  CalcInverse(Jac, JInv);
1190  normals.GetColumnReference(i, nr);
1191  JInv.MultTranspose(lnor, nr);
1192  }
1193  if (side)
1194  {
1195  normals *= -1.;
1196  }
1197  JInv.ClearExternalData();
1198 }
1199 
1201  int n, double *points, int elem, int func, int part)
1202 {
1203  int i, j;
1204  RefinedGeometry *RefG;
1205  IntegrationPointTransformation ip_transf;
1206 
1207  switch (n)
1208  {
1209  case 3:
1210  RefG = GLVisGeometryRefiner.Refine(Geometry::TRIANGLE, TimesToRefine);
1211  ip_transf.Transf.SetFE (&TriangleFE);
1212  break;
1213  case 4:
1214  RefG = GLVisGeometryRefiner.Refine(Geometry::SQUARE, TimesToRefine);
1215  ip_transf.Transf.SetFE (&QuadrilateralFE);
1216  break;
1217  case 5:
1218  DrawRefinedSurf (3, points, elem, func, 0); // draw (0,1,2)
1219  for (i = 0; i < 3; i++)
1220  {
1221  points[4+i] = points[i]; // move point 0 to point 1
1222  }
1223  DrawRefinedSurf (4, points+4, elem, func, 1); // draw (0,2,3,4)
1224  return;
1225  case 6:
1226  DrawRefinedSurf (4, points, elem, func, 0); // draw (0,1,2,3)
1227  for (i = 0; i < 3; i++)
1228  {
1229  points[8+i] = points[i]; // move point 0 to point 2
1230  }
1231  DrawRefinedSurf (4, points+8, elem, func, 1); // draw (0,3,4,5)
1232  return;
1233  default:
1234  return;
1235  }
1236  DenseMatrix &pm = ip_transf.Transf.GetPointMat();
1237  pm.SetSize (3, n);
1238  for (i = 0; i < n; i++)
1239  for (j = 0; j < 3; j++)
1240  {
1241  pm(j,i) = points[4*i+j];
1242  }
1243  IntegrationRule tir (RefG -> RefPts.GetNPoints());
1244  ip_transf.Transform (RefG -> RefPts, tir);
1245  DenseMatrix pointmat;
1246  Vector values;
1247  GridF -> GetValues (elem, tir, values, pointmat);
1248 
1249  LiftRefinedSurf (n, pointmat, values, NULL);
1250 
1251  switch (func)
1252  {
1253  case 1:
1254  DrawRefinedSurf (n, pointmat, values, RefG->RefGeoms);
1255  break;
1256 
1257  case 2:
1258  DrawRefinedSurfEdges (n, pointmat, values, RefG->RefEdges, part);
1259  break;
1260 
1261  case 3:
1262  DrawRefinedSurfLevelLines (n, pointmat, values, RefG->RefGeoms);
1263  break;
1264  }
1265 }
1266 
1268  int n, DenseMatrix &pointmat, Vector &values, int *RG)
1269 {
1270  int i, j;
1271 
1272  if (FaceShiftScale == 0.0)
1273  {
1274  return;
1275  }
1276 
1277  double norm[3];
1278 
1279  if (RG == NULL) // use the normal vector of the cutting plane
1280  {
1281  double *eqn = CuttingPlane -> Equation();
1282  norm[0] = -eqn[0]; norm[1] = -eqn[1]; norm[2] = -eqn[2];
1283  }
1284  else
1285  {
1286  // use the normal vector to the polygon defined by
1287  // the points with indexes given by the first n integers in RG
1288  double pts[4][3];
1289  for (i = 0; i < n; i++)
1290  for (j = 0; j < 3; j++)
1291  {
1292  pts[i][j] = pointmat(j,RG[i]);
1293  }
1294  if (n > 3)
1295  {
1296  j = Compute3DUnitNormal (pts[0], pts[1], pts[2], pts[3], norm);
1297  }
1298  else
1299  {
1300  j = Compute3DUnitNormal (pts[0], pts[1], pts[2], norm);
1301  }
1302  if (j)
1303  {
1304  // could not compute normal
1305  cerr << "WARNING: VisualizationSceneSolution3d::LiftRefinedSurf"
1306  << endl;
1307  return;
1308  }
1309  }
1310 
1311  double bbox_diam = sqrt ( (bb.x[1]-bb.x[0])*(bb.x[1]-bb.x[0]) +
1312  (bb.y[1]-bb.y[0])*(bb.y[1]-bb.y[0]) +
1313  (bb.z[1]-bb.z[0])*(bb.z[1]-bb.z[0]) );
1314  double sc = FaceShiftScale * bbox_diam;
1315 
1316  for (i = 0; i < pointmat.Width(); i++)
1317  {
1318  double val = sc * (values(i) - minv) / (maxv - minv);
1319  for (j = 0; j < 3; j++)
1320  {
1321  pointmat(j, i) += val * norm[j];
1322  }
1323  }
1324 }
1325 
1327  int n, DenseMatrix &pointmat, Vector &values, Array<int> &RefGeoms)
1328 {
1329  double norm[3], pts[4][3];
1330  gl3::GlBuilder draw = cplane_buf.createBuilder();
1331 
1332  for (int i = 0; i < RefGeoms.Size()/n; i++)
1333  {
1334  int *RG = &(RefGeoms[i*n]);
1335  int j;
1336  for (j = 0; j < n; j++)
1337  for (int l = 0; l < 3; l++)
1338  {
1339  pts[j][l] = pointmat(l, RG[j]);
1340  }
1341  if (n > 3)
1342  {
1343  j = Compute3DUnitNormal (pts[0], pts[1], pts[2], pts[3], norm);
1344  }
1345  else
1346  {
1347  j = Compute3DUnitNormal (pts[0], pts[1], pts[2], norm);
1348  }
1349  if (!j)
1350  {
1351  draw.glBegin (GL_POLYGON);
1352  draw.glNormal3dv (norm);
1353  for (j = 0; j < n; j++)
1354  {
1355  MySetColor (draw, values(RG[j]), minv, maxv);
1356  draw.glVertex3dv (pts[j]);
1357  }
1358  draw.glEnd();
1359  }
1360  /*
1361  else
1362  cerr << "WARNING: VisualizationSceneSolution3d::DrawRefinedSurf"
1363  << endl;
1364  */
1365  }
1366 }
1367 
1369  int n, DenseMatrix &pointmat, Vector &values, Array<int> &RefEdges,
1370  int part)
1371 {
1372  int k, k_start, k_end;
1373 
1374  k_start = 0;
1375  k_end = RefEdges.Size();
1376  gl3::GlBuilder line = cplines_buf.createBuilder();
1377  if (part == 0)
1378  {
1379  k_end = (k_end/n) * (n-1);
1380  }
1381  if (part == 1)
1382  {
1383  k_start = (k_end/n);
1384  }
1385 
1386  line.glBegin(GL_LINES);
1387  for (k = k_start; k < k_end; k++)
1388  {
1389  int RE = RefEdges[k];
1390 
1391  line.glVertex3d (pointmat(0, RE), pointmat(1, RE),
1392  pointmat(2, RE));
1393  }
1394  line.glEnd();
1395 }
1396 
1398  int n, DenseMatrix &pointmat, Vector &values, Array<int> &RefGeoms)
1399 {
1400  int j, k;
1401  int *RG;
1402  double point[4][4];
1403 
1404  gl3::GlBuilder line = cplines_buf.createBuilder();
1405 
1406  for (k = 0; k < RefGeoms.Size()/n; k++)
1407  {
1408  RG = &(RefGeoms[k*n]);
1409 
1410  for (j = 0; j < n; j++)
1411  {
1412  for (int i = 0; i < 3; i++)
1413  {
1414  point[j][i] = pointmat(i, RG[j]);
1415  }
1416  point[j][3] = values(RG[j]);
1417  }
1418  DrawPolygonLevelLines(line, point[0], n, level, false);
1419  }
1420 }
1421 
1423 {
1424  int i, j;
1425  disp_buf.clear();
1426  int dim = mesh->Dimension();
1427  int ne = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
1428  DenseMatrix pointmat;
1429  Array<int> vertices;
1430  double p[4][3], c[4];
1431 
1432  for (i = 0; i < ne; i++)
1433  {
1434  if (dim == 3)
1435  {
1436  if (!bdr_attr_to_show[mesh->GetBdrAttribute(i)-1]) { continue; }
1437 
1438  if (cplane == 2)
1439  {
1440  // for cplane == 2, get vertices of the volume element, not bdr
1441  int f, o, e1, e2;
1442  mesh->GetBdrElementFace(i, &f, &o);
1443  mesh->GetFaceElements(f, &e1, &e2);
1444  mesh->GetElementVertices(e1, vertices);
1445  }
1446  else
1447  {
1448  mesh->GetBdrElementVertices(i, vertices);
1449  }
1450  }
1451  else
1452  {
1453  if (!bdr_attr_to_show[mesh->GetAttribute(i)-1]) { continue; }
1454 
1455  mesh->GetElementVertices(i, vertices);
1456  }
1457 
1458  if (cplane == 2 && CheckPositions(vertices)) { continue; }
1459 
1460  if (dim == 3)
1461  {
1462  mesh->GetBdrPointMatrix(i, pointmat);
1463  }
1464  else
1465  {
1466  mesh->GetPointMatrix(i, pointmat);
1467  }
1468 
1469  for (j = 0; j < pointmat.Width(); j++)
1470  {
1471  p[j][0] = pointmat(0, j);
1472  p[j][1] = pointmat(1, j);
1473  p[j][2] = pointmat(2, j);
1474  c[j] = (*sol)(vertices[j]);
1475  }
1476  if (j == 3)
1477  {
1478  if (cut_lambda > 0)
1479  {
1480  DrawCutTriangle(disp_buf, p, c, minv, maxv);
1481  }
1482  else
1483  {
1484  DrawTriangle(disp_buf, p, c, minv, maxv);
1485  }
1486  }
1487  else
1488  {
1489  if (cut_lambda > 0)
1490  {
1491  DrawCutQuad(disp_buf, p, c, minv, maxv);
1492  }
1493  else
1494  {
1495  DrawQuad(disp_buf, p, c, minv, maxv);
1496  }
1497  }
1498  }
1499  updated_bufs.emplace_back(&disp_buf);
1500 }
1501 
1502 
1503 // Cut the reference square by subdividing it into 4 trapezoids with a central
1504 // square removed: (fl,fl)-(fr,fl)-(fr,fr)-(fl,fr). The input RefG corresponds
1505 // to the reference square. The value of lambda controls the cut: 0 = no cut, 1
1506 // = full cut. See keys Ctrl+F3/F4.
1507 static void CutReferenceSquare(RefinedGeometry *RefG, double lambda,
1508  IntegrationRule &RefPts, Array<int> &RefGeoms)
1509 {
1510  // lambda * vertex + (1-lambda) * center
1511  double fl = (1.0-lambda)/2.0; // left corner of the cut frame
1512  double fr = (1.0+lambda)/2.0; // right corner of the cut frame
1513 
1514  int np = RefG->RefPts.Size();
1515  RefPts.SetSize(4*np);
1516  for (int i = 0; i < np; i++)
1517  {
1518  double X = RefG->RefPts[i].x;
1519  double Y = RefG->RefPts[i].y;
1520 
1521  // First order unit square basis functions
1522  double phi3 = (1.0-X)*Y, phi2 = X*Y; // (0,1)-(1,1)
1523  double phi0 = (1.0-X)*(1.0-Y), phi1 = X*(1.0-Y); // (0,0)-(1,0)
1524 
1525  // bottom trapezoid: (0,0)-(1,1)-(fr,fl)-(fl,fl)
1526  RefPts[i].x = phi1 + fr * phi2 + fl * phi3;
1527  RefPts[i].y = fl * phi2 + fl * phi3;
1528 
1529  // right trapezoid: (fr,fl)-(1,0)-(1,1)-(fr,fr)
1530  RefPts[i+np].x = fr * phi0 + phi1 + phi2 + fr * phi3;
1531  RefPts[i+np].y = fl * phi0 + phi2 + fr * phi3;
1532 
1533  // top trapezoid: (fl,fr)-(fr,fr)-(1,1)-(0,1)
1534  RefPts[i+2*np].x = fl * phi0 + fr * phi1 + phi2;
1535  RefPts[i+2*np].y = fr * phi0 + fr * phi1 + phi2 + phi3;
1536 
1537  // left trapezoid: (0,0)-(fl,fl)-(fl,fr)-(0,1)
1538  RefPts[i+3*np].x = fl * phi1 + fl * phi2;
1539  RefPts[i+3*np].y = fl * phi1 + fr * phi2 + phi3;
1540 
1541  RefPts[i].z = RefG->RefPts[i].z;
1542  RefPts[i+np].z = RefG->RefPts[i].z;
1543  RefPts[i+2*np].z = RefG->RefPts[i].z;
1544  RefPts[i+3*np].z = RefG->RefPts[i].z;
1545  }
1546 
1547  int ne = RefG->RefGeoms.Size();
1548  RefGeoms.SetSize(4*ne);
1549  for (int i = 0; i < ne; i++)
1550  {
1551  RefGeoms[i] = RefG->RefGeoms[i];
1552  RefGeoms[i+ne] = RefG->RefGeoms[i] + np;
1553  RefGeoms[i+2*ne] = RefG->RefGeoms[i] + 2*np;
1554  RefGeoms[i+3*ne] = RefG->RefGeoms[i] + 3*np;
1555  }
1556 }
1557 
1558 // Cut the reference triangle by subdividing it into 3 trapezoids with a central
1559 // triangle removed: (fl,fl)-(fr,fl)-(fl,fr). Note that the input RefG
1560 // corresponds to a reference square, not reference triangle. The value of
1561 // lambda controls the cut: 0 = no cut, 1 = full cut. See keys Ctrl+F3/F4.
1562 static void CutReferenceTriangle(RefinedGeometry *RefG, double lambda,
1563  IntegrationRule &RefPts, Array<int> &RefGeoms)
1564 {
1565  // lambda * vertex + (1-lambda) * center
1566  double fl = (1.0-lambda)/3.0; // left corner of the cut frame
1567  double fr = (1.0+2.0*lambda)/3.0; // right corner of the cut frame
1568 
1569  int np = RefG->RefPts.Size();
1570  RefPts.SetSize(3*np);
1571  for (int i = 0; i < np; i++)
1572  {
1573  double X = RefG->RefPts[i].x;
1574  double Y = RefG->RefPts[i].y;
1575 
1576  // First order unit square basis functions
1577  double phi3 = (1.0-X)*Y, phi2 = X*Y; // (0,1)-(1,1)
1578  double phi0 = (1.0-X)*(1.0-Y), phi1 = X*(1.0-Y); // (0,0)-(1,0)
1579 
1580  // bottom trapezoid: (0,0)-(1,0)-(fr,fl)-(fl,fl)
1581  RefPts[i].x = phi1 + fr * phi2 + fl * phi3;
1582  RefPts[i].y = fl * phi2 + fl * phi3;
1583 
1584  // diagonal trapezoid: (fr,fl)-(1,0)-(0,1)-(fl,fr)
1585  RefPts[i+np].x = fr * phi0 + phi1 + fl * phi3;
1586  RefPts[i+np].y = fl * phi0 + phi2 + fr * phi3;
1587 
1588  // left trapezoid: (0,0)-(fl,fl)-(fl,fr)-(0,1)
1589  RefPts[i+2*np].x = fl * phi1 + fl * phi2;
1590  RefPts[i+2*np].y = fl * phi1 + fr * phi2 + phi3;
1591 
1592  RefPts[i].z = RefG->RefPts[i].z;
1593  RefPts[i+np].z = RefG->RefPts[i].z;
1594  RefPts[i+2*np].z = RefG->RefPts[i].z;
1595  }
1596 
1597  int ne = RefG->RefGeoms.Size();
1598  RefGeoms.SetSize(3*ne);
1599  for (int i = 0; i < ne; i++)
1600  {
1601  RefGeoms[i] = RefG->RefGeoms[i];
1602  RefGeoms[i+ne] = RefG->RefGeoms[i] + np;
1603  RefGeoms[i+2*ne] = RefG->RefGeoms[i] + 2*np;
1604  }
1605 }
1606 
1607 // Call CutReferenceTriangle and CutReferenceSquare to update the global
1608 // variables cut_TriPts, cut_TriGeoms, cut_QuadPts, cut_QuadGeoms.
1609 void CutReferenceElements(int TimesToRefine, double lambda)
1610 {
1611  RefinedGeometry *RefG =
1612  GLVisGeometryRefiner.Refine(Geometry::SQUARE, TimesToRefine);
1613  CutReferenceTriangle(RefG, lambda, cut_TriPts, cut_TriGeoms);
1614  CutReferenceSquare(RefG, lambda, cut_QuadPts, cut_QuadGeoms);
1615 }
1616 
1618 {
1619  int fn, fo, di, have_normals;
1620  double bbox_diam, vmin, vmax;
1621  disp_buf.clear();
1622 
1623  int dim = mesh->Dimension();
1624  int nbe = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
1625  DenseMatrix pointmat, normals;
1626  Vector values, normal;
1627  RefinedGeometry * RefG;
1628  Array<int> vertices;
1629  double norm[3];
1630  IsoparametricTransformation T;
1631 
1632  bbox_diam = sqrt ( (bb.x[1]-bb.x[0])*(bb.x[1]-bb.x[0]) +
1633  (bb.y[1]-bb.y[0])*(bb.y[1]-bb.y[0]) +
1634  (bb.z[1]-bb.z[0])*(bb.z[1]-bb.z[0]) );
1635  double sc = FaceShiftScale * bbox_diam;
1636 
1637  vmin = numeric_limits<double>::infinity();
1638  vmax = -vmin;
1639  for (int i = 0; i < nbe; i++)
1640  {
1641  int sides;
1642  switch ((dim == 3) ? mesh->GetBdrElementType(i) : mesh->GetElementType(i))
1643  {
1644  case Element::TRIANGLE:
1645  sides = 3;
1646  break;
1647 
1648  case Element::QUADRILATERAL:
1649  default:
1650  sides = 4;
1651  break;
1652  }
1653 
1654  if (dim == 3)
1655  {
1656  if (!bdr_attr_to_show[mesh->GetBdrAttribute(i)-1]) { continue; }
1657 
1658  if (cplane == 2)
1659  {
1660  // for cplane == 2, get vertices of the volume element, not bdr
1661  int f, o, e1, e2;
1662  mesh->GetBdrElementFace(i, &f, &o);
1663  mesh->GetFaceElements(f, &e1, &e2);
1664  mesh->GetElementVertices(e1, vertices);
1665  }
1666  else
1667  {
1668  mesh->GetBdrElementVertices(i, vertices);
1669  }
1670  }
1671  else
1672  {
1673  if (!bdr_attr_to_show[mesh->GetAttribute(i)-1]) { continue; }
1674  mesh->GetElementVertices(i, vertices);
1675  }
1676 
1677  if (cplane == 2 && CheckPositions(vertices)) { continue; }
1678 
1679  if (dim == 3)
1680  {
1681  mesh -> GetBdrElementFace (i, &fn, &fo);
1682  RefG = GLVisGeometryRefiner.Refine(mesh -> GetFaceBaseGeometry (fn),
1683  TimesToRefine);
1684  if (!cut_updated)
1685  {
1686  // Update the cut version of the reference geometries
1687  CutReferenceElements(TimesToRefine, cut_lambda);
1688  cut_updated = true;
1689  }
1690 
1691  // di = GridF -> GetFaceValues (fn, 2, RefG->RefPts, values, pointmat);
1692  // this assumes the interior boundary faces are properly oriented ...
1693  di = fo % 2;
1694  if (di == 1 && !mesh->FaceIsInterior(fn))
1695  {
1696  di = 0;
1697  }
1698 
1699  IntegrationRule &RefPts = (cut_lambda > 0) ?
1700  ((sides == 3) ? cut_TriPts : cut_QuadPts) :
1701  RefG->RefPts;
1702  GridF -> GetFaceValues (fn, di, RefPts, values, pointmat);
1703  GetFaceNormals(fn, di, RefPts,normals);
1704  have_normals = 1;
1705  ShrinkPoints(pointmat, i, fn, di);
1706  }
1707  else
1708  {
1709  RefG = GLVisGeometryRefiner.Refine(mesh->GetElementBaseGeometry(i),
1710  TimesToRefine);
1711  if (!cut_updated)
1712  {
1713  // Update the cut version of the reference geometries
1714  CutReferenceElements(TimesToRefine, cut_lambda);
1715  cut_updated = true;
1716  }
1717  const IntegrationRule &ir = (cut_lambda > 0) ?
1718  ((sides == 3) ? cut_TriPts : cut_QuadPts) :
1719  RefG->RefPts;
1720  GridF->GetValues(i, ir, values, pointmat);
1721  normals.SetSize(3, values.Size());
1722  mesh->GetElementTransformation(i, &T);
1723  for (int j = 0; j < values.Size(); j++)
1724  {
1725  T.SetIntPoint(&ir.IntPoint(j));
1726  const DenseMatrix &J = T.Jacobian();
1727  normals.GetColumnReference(j, normal);
1728  CalcOrtho(J, normal);
1729  normal /= normal.Norml2();
1730  }
1731  have_normals = 1;
1732  di = 0;
1733  ShrinkPoints(pointmat, i, 0, 0);
1734  }
1735 
1736  vmin = fmin(vmin, values.Min());
1737  vmax = fmax(vmax, values.Max());
1738 
1739  // compute an average normal direction for the current face
1740  if (sc != 0.0)
1741  {
1742  for (int j = 0; j < 3; j++)
1743  {
1744  norm[j] = 0.0;
1745  }
1746  Normalize(normals);
1747  for (int k = 0; k < normals.Width(); k++)
1748  for (int j = 0; j < 3; j++)
1749  {
1750  norm[j] += normals(j, k);
1751  }
1752  Normalize(norm);
1753  for (int k = 0; k < pointmat.Width(); k++)
1754  {
1755  double val = sc * (values(k) - minv) / (maxv - minv);
1756  for (int j = 0; j < 3; j++)
1757  {
1758  pointmat(j, k) += val * norm[j];
1759  }
1760  }
1761  have_normals = 0;
1762  }
1763 
1764  have_normals = have_normals ? 2 : 0;
1765  if (di)
1766  {
1767  have_normals = -1 - have_normals;
1768  }
1769  // Comment the above lines and use the below version in order to remove
1770  // the 3D dark artifacts (indicating wrong boundary element orientation)
1771  // have_normals = have_normals ? 1 : 0;
1772 
1773  Array<int> &RefGeoms = (cut_lambda > 0) ?
1774  ((sides == 3) ? cut_TriGeoms : cut_QuadGeoms) :
1775  RefG->RefGeoms;
1776  int psides = (cut_lambda > 0) ? 4 : sides;
1777  DrawPatch(disp_buf, pointmat, values, normals, psides, RefGeoms,
1778  minv, maxv, have_normals);
1779  }
1780  updated_bufs.emplace_back(&disp_buf);
1781 
1782  cout << "VisualizationSceneSolution3d::PrepareFlat2() : [min,max] = ["
1783  << vmin << "," << vmax << "]" << endl;
1784 }
1785 
1787 {
1788  int j;
1789 
1790  if (!drawelems)
1791  {
1792  return;
1793  }
1794 
1795  switch (shading)
1796  {
1797  case 0:
1798  PrepareFlat();
1799  return;
1800  case 2:
1801  PrepareFlat2();
1802  return;
1803  default:
1804  break;
1805  }
1806 
1807  disp_buf.clear();
1808  gl3::GlBuilder poly = disp_buf.createBuilder();
1809 
1810  int dim = mesh->Dimension();
1811  int ne = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
1812  int nv = mesh -> GetNV();
1813  DenseMatrix pointmat;
1814  Array<int> vertices;
1815  double nor[3];
1816 
1817  Vector nx(nv);
1818  Vector ny(nv);
1819  Vector nz(nv);
1820 
1821  Table ba_to_be; // boundary_attribute--to--boundary_element
1822  {
1823  Table be_to_ba;
1824  be_to_ba.MakeI(ne);
1825  for (int i = 0; i < ne; i++)
1826  {
1827  be_to_ba.AddAColumnInRow(i);
1828  }
1829  be_to_ba.MakeJ();
1830  if (dim == 3)
1831  {
1832  for (int i = 0; i < ne; i++)
1833  {
1834  be_to_ba.AddConnection(i, mesh->GetBdrAttribute(i)-1);
1835  }
1836  }
1837  else
1838  {
1839  for (int i = 0; i < ne; i++)
1840  {
1841  be_to_ba.AddConnection(i, mesh->GetAttribute(i)-1);
1842  }
1843  }
1844  be_to_ba.ShiftUpI();
1845 
1846  Transpose(be_to_ba, ba_to_be);
1847  }
1848 
1849  const Array<int> &attributes =
1850  ((dim == 3) ? mesh->bdr_attributes : mesh->attributes);
1851  for (int d = 0; d < attributes.Size(); d++)
1852  {
1853  const int attr = attributes[d]-1;
1854 
1855  if (!bdr_attr_to_show[attr]) { continue; }
1856 
1857  const int nelem = ba_to_be.RowSize(attr);
1858  const int *elem = ba_to_be.GetRow(attr);
1859 
1860  for (int i = 0; i < nelem; i++)
1861  {
1862  if (dim == 3)
1863  {
1864  mesh->GetBdrElementVertices(elem[i], vertices);
1865  }
1866  else
1867  {
1868  mesh->GetElementVertices(elem[i], vertices);
1869  }
1870  for (j = 0; j < vertices.Size(); j++)
1871  {
1872  nx(vertices[j]) = ny(vertices[j]) = nz(vertices[j]) = 0.;
1873  }
1874  }
1875  for (int i = 0; i < nelem; i++)
1876  {
1877  if (dim == 3)
1878  {
1879  mesh->GetBdrPointMatrix(elem[i], pointmat);
1880  mesh->GetBdrElementVertices(elem[i], vertices);
1881  }
1882  else
1883  {
1884  mesh->GetPointMatrix(elem[i], pointmat);
1885  mesh->GetElementVertices(elem[i], vertices);
1886  }
1887 
1888  if (pointmat.Width() == 3)
1889  j = Compute3DUnitNormal(&pointmat(0,0), &pointmat(0,1),
1890  &pointmat(0,2), nor);
1891  else
1892  j = Compute3DUnitNormal(&pointmat(0,0), &pointmat(0,1),
1893  &pointmat(0,2), &pointmat(0,3), nor);
1894  if (j == 0)
1895  for (j = 0; j < pointmat.Size(); j++)
1896  {
1897  nx(vertices[j]) += nor[0];
1898  ny(vertices[j]) += nor[1];
1899  nz(vertices[j]) += nor[2];
1900  }
1901  }
1902 
1903  for (int i = 0; i < nelem; i++)
1904  {
1905  if (dim == 3)
1906  {
1907  if (cplane == 2)
1908  {
1909  // for cplane == 2, get vertices of the volume element, not bdr
1910  int f, o, e1, e2;
1911  mesh->GetBdrElementFace(i, &f, &o);
1912  mesh->GetFaceElements(f, &e1, &e2);
1913  mesh->GetElementVertices(e1, vertices);
1914 
1915  if (CheckPositions(vertices)) { continue; }
1916  }
1917  else
1918  {
1919  mesh->GetBdrElementVertices(elem[i], vertices);
1920  }
1921  }
1922  else
1923  {
1924  mesh->GetElementVertices(elem[i], vertices);
1925  }
1926 
1927  GLenum elemType = GL_NONE;
1928  switch ((dim == 3) ? mesh->GetBdrElementType(elem[i]) :
1929  mesh->GetElementType(elem[i]))
1930  {
1931  case Element::TRIANGLE:
1932  elemType = GL_TRIANGLES;
1933  break;
1934  case Element::QUADRILATERAL:
1935  elemType = GL_QUADS;
1936  break;
1937  default:
1938  MFEM_ABORT("Invalid boundary element type");
1939  break;
1940  }
1941  poly.glBegin(elemType);
1942  if (dim == 3)
1943  {
1944  mesh->GetBdrPointMatrix(elem[i], pointmat);
1945  }
1946  else
1947  {
1948  mesh->GetPointMatrix(elem[i], pointmat);
1949  }
1950 
1951  for (j = 0; j < pointmat.Size(); j++)
1952  {
1953  MySetColor(poly, (*sol)(vertices[j]), minv, maxv);
1954  poly.glNormal3d(nx(vertices[j]), ny(vertices[j]), nz(vertices[j]));
1955  poly.glVertex3dv(&pointmat(0, j));
1956  }
1957  poly.glEnd();
1958  }
1959  }
1960  updated_bufs.emplace_back(&disp_buf);
1961 }
1962 
1964 {
1965  if (!drawmesh)
1966  {
1967  return;
1968  }
1969 
1970  if (shading == 2)
1971  {
1972  PrepareLines2();
1973  return;
1974  }
1975 
1976  int dim = mesh->Dimension();
1977  int ne = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
1978  int i, j, k;
1979  DenseMatrix pointmat;
1980 
1981  line_buf.clear();
1982 
1983  Array<int> vertices;
1984 
1985  for (i = 0; i < ne; i++)
1986  {
1987  if (dim == 3)
1988  {
1989  if (!bdr_attr_to_show[mesh->GetBdrAttribute(i)-1]) { continue; }
1990 
1991  if (cplane == 2)
1992  {
1993  // for cplane == 2, get vertices of the volume element, not bdr
1994  int f, o, e1, e2;
1995  mesh->GetBdrElementFace(i, &f, &o);
1996  mesh->GetFaceElements(f, &e1, &e2);
1997  mesh->GetElementVertices(e1, vertices);
1998  }
1999  else
2000  {
2001  mesh->GetBdrElementVertices(i, vertices);
2002  }
2003  }
2004  else
2005  {
2006  if (!bdr_attr_to_show[mesh->GetAttribute(i)-1]) { continue; }
2007 
2008  mesh->GetElementVertices(i, vertices);
2009  }
2010 
2011  if (cplane == 2 && CheckPositions(vertices)) { continue; }
2012 
2013  double point[4][4];
2014  if (dim == 3)
2015  {
2016  mesh->GetBdrPointMatrix(i, pointmat);
2017  }
2018  else
2019  {
2020  mesh->GetPointMatrix(i, pointmat);
2021  }
2022 
2023  gl3::GlBuilder line = line_buf.createBuilder();
2024  switch (drawmesh)
2025  {
2026  case 1:
2027  line.glBegin(GL_LINE_LOOP);
2028 
2029  for (j = 0; j < pointmat.Size(); j++)
2030  {
2031  line.glVertex3d (pointmat(0, j), pointmat(1, j), pointmat(2, j));
2032  }
2033  line.glEnd();
2034  break;
2035 
2036  case 2:
2037  for (j = 0; j < pointmat.Size(); j++)
2038  {
2039  for (k = 0; k < 3; k++)
2040  {
2041  point[j][k] = pointmat(k,j);
2042  }
2043  point[j][3] = (*sol)(vertices[j]);
2044  }
2045  DrawPolygonLevelLines(line, point[0], pointmat.Size(), level, false);
2046  break;
2047  }
2048  }
2049  updated_bufs.emplace_back(&line_buf);
2050 }
2051 
2053 {
2054  int fn, fo, di = 0;
2055  double bbox_diam;
2056 
2057  line_buf.clear();
2058 
2059  int dim = mesh->Dimension();
2060  int nbe = (dim == 3) ? mesh->GetNBE() : mesh->GetNE();
2061  DenseMatrix pointmat, normals;
2062  Vector values, normal;
2063  RefinedGeometry * RefG;
2064  Array<int> vertices;
2065  IsoparametricTransformation T;
2066 
2067  bbox_diam = sqrt ( (bb.x[1]-bb.x[0])*(bb.x[1]-bb.x[0]) +
2068  (bb.y[1]-bb.y[0])*(bb.y[1]-bb.y[0]) +
2069  (bb.z[1]-bb.z[0])*(bb.z[1]-bb.z[0]) );
2070  double sc = FaceShiftScale * bbox_diam;
2071 
2072  for (int i = 0; i < nbe; i++)
2073  {
2074  if (dim == 3)
2075  {
2076  if (!bdr_attr_to_show[mesh->GetBdrAttribute(i)-1]) { continue; }
2077 
2078  if (cplane == 2)
2079  {
2080  // for cplane == 2, get vertices of the volume element, not bdr
2081  int f, o, e1, e2;
2082  mesh->GetBdrElementFace(i, &f, &o);
2083  mesh->GetFaceElements(f, &e1, &e2);
2084  mesh->GetElementVertices(e1, vertices);
2085  }
2086  else
2087  {
2088  mesh->GetBdrElementVertices(i, vertices);
2089  }
2090  }
2091  else
2092  {
2093  if (!bdr_attr_to_show[mesh->GetAttribute(i)-1]) { continue; }
2094 
2095  mesh->GetElementVertices(i, vertices);
2096  }
2097 
2098  if (cplane == 2 && CheckPositions(vertices)) { continue; }
2099 
2100  if (dim == 3)
2101  {
2102  mesh -> GetBdrElementFace (i, &fn, &fo);
2103  RefG = GLVisGeometryRefiner.Refine(mesh -> GetFaceBaseGeometry (fn),
2104  TimesToRefine);
2105  // di = GridF -> GetFaceValues (fn, 2, RefG->RefPts, values, pointmat);
2106  di = fo % 2;
2107  if (di == 1 && !mesh->FaceIsInterior(fn))
2108  {
2109  di = 0;
2110  }
2111  GridF -> GetFaceValues (fn, di, RefG->RefPts, values, pointmat);
2112  ShrinkPoints(pointmat, i, fn, di);
2113  }
2114  else
2115  {
2116  RefG = GLVisGeometryRefiner.Refine(mesh->GetElementBaseGeometry(i),
2117  TimesToRefine);
2118  GridF->GetValues(i, RefG->RefPts, values, pointmat);
2119  ShrinkPoints(pointmat, i, 0, 0);
2120  }
2121 
2122  if (sc != 0.0)
2123  {
2124  if (dim == 3)
2125  {
2126  GetFaceNormals(fn, di, RefG->RefPts, normals);
2127  }
2128  else
2129  {
2130  normals.SetSize(3, values.Size());
2131  mesh->GetElementTransformation(i, &T);
2132  for (int j = 0; j < values.Size(); j++)
2133  {
2134  T.SetIntPoint(&RefG->RefPts.IntPoint(j));
2135  const DenseMatrix &J = T.Jacobian();
2136  normals.GetColumnReference(j, normal);
2137  CalcOrtho(J, normal);
2138  normal /= normal.Norml2();
2139  }
2140  }
2141  double norm[3];
2142  for (int j = 0; j < 3; j++)
2143  {
2144  norm[j] = 0.0;
2145  }
2146  for (int k = 0; k < normals.Width(); k++)
2147  {
2148  for (int j = 0; j < 3; j++)
2149  {
2150  norm[j] += normals(j, k);
2151  }
2152  }
2153  double len = sqrt(InnerProd(norm, norm));
2154  if (len > 0.0)
2155  {
2156  len = 1.0 / len;
2157  }
2158  for (int j = 0; j < 3; j++)
2159  {
2160  norm[j] *= len;
2161  }
2162  for (int k = 0; k < pointmat.Width(); k++)
2163  {
2164  double val = sc * (values(k) - minv) / (maxv - minv);
2165  for (int j = 0; j < 3; j++)
2166  {
2167  pointmat(j, k) += val * norm[j];
2168  }
2169  }
2170  }
2171  gl3::GlBuilder line = line_buf.createBuilder();
2172  if (drawmesh == 1)
2173  {
2174  Array<int> &REdges = RefG->RefEdges;
2175 
2176  line.glBegin(GL_LINES);
2177  for (int k = 0; k < REdges.Size(); k++)
2178  {
2179  line.glVertex3dv(&pointmat(0, REdges[k]));
2180  }
2181  line.glEnd();
2182  }
2183  else if (drawmesh == 2)
2184  {
2185  double point[4][4];
2186  int sides;
2187  switch ((dim == 3) ? mesh->GetBdrElementType(i) :
2188  mesh->GetElementType(i))
2189  {
2190  case Element::TRIANGLE:
2191  sides = 3;
2192  break;
2193 
2194  case Element::QUADRILATERAL:
2195  default:
2196  sides = 4;
2197  break;
2198  }
2199  for (int k = 0; k < RefG->RefGeoms.Size()/sides; k++)
2200  {
2201  int *RG = &(RefG->RefGeoms[k*sides]);
2202 
2203  for (int j = 0; j < sides; j++)
2204  {
2205  for (int ii = 0; ii < 3; ii++)
2206  {
2207  point[j][ii] = pointmat(ii, RG[j]);
2208  }
2209  point[j][3] = values(RG[j]);
2210  }
2211  DrawPolygonLevelLines(line, point[0], sides, level, false);
2212  }
2213  }
2214  }
2215  updated_bufs.emplace_back(&line_buf);
2216 }
2217 
2218 static void CutElement(const Geometry::Type geom, const int *vert_flags,
2219  const int **edge_vert_ptr, int *cut_edges,
2220  int *num_cut_edges, int *n2_cut_edges)
2221 {
2222  static const int tet_edges[12]= {0,3, 0,2, 0,1, 1,2, 1,3, 2,3};
2223  static const int pyr_edges[16] =
2224  {0,1, 1,2, 3,2, 0,3, 0,4, 1,4, 2,4, 3,4};
2225  static const int pyr_cutting[16][3] =
2226  {
2227  { 3, 4, 6}, { 9, -1, 10}, { 4, 6, 1}, {11, -1, 12},
2228  {13, -1, 14}, { 6, 1, 3}, {15, -1, 8}, { 1, 3, 4},
2229  {-1, 10, 0}, { 7, 15, -1}, {-1, 12, 2}, { 0, 9, -1},
2230  {-1, 14, 5}, { 2, 11, -1}, {-1, 8, 7}, { 5, 13, -1}
2231  };
2232  static const int pri_edges[18] =
2233  {0,1, 1,2, 2,0, 3,4, 4,5, 5,3, 0,3, 1,4, 2,5};
2234  static const int pri_cutting[18][3] =
2235  {
2236  { 3, -1, 5}, {13, 7, 14}, { 5, -1, 1}, {15, 9, 16},
2237  { 1, -1, 3}, {17, 11, 12},
2238  {14, 0, 13}, {10, -1, 8}, {16, 2, 15}, { 6, -1, 10},
2239  {12, 4, 17}, { 8, -1, 6},
2240  { 7, 14, 0}, { 4, 17, 11}, { 9, 16, 2}, { 0, 13, 7},
2241  {11, 12, 4}, { 2, 15, 9}
2242  };
2243  static const int hex_edges[24] =
2244  { 0,1, 1,2, 3,2, 0,3, 4,5, 5,6, 7,6, 4,7, 0,4, 1,5, 2,6, 3,7 };
2245  static const int hex_cutting[24][3] =
2246  {
2247  { 3, 4, 6}, {17, 9, 18}, { 4, 6, 1}, {19, 11, 20},
2248  {21, 12, 22}, { 6, 1, 3}, {23, 14, 16}, { 1, 3, 4},
2249  {18, 0, 17}, {15, 13, 10}, {20, 2, 19}, { 8, 15, 13},
2250  {10, 8, 15}, {22, 5, 21}, {13, 10, 8}, {16, 7, 23},
2251  { 9, 18, 0}, { 7, 23, 14}, {11, 20, 2}, { 0, 17, 9},
2252  {12, 22, 5}, { 2, 19, 11}, {14, 16, 7}, { 5, 21, 12}
2253  };
2254  const int *ev;
2255  int n, n2;
2256 
2257  n = n2 = 0;
2258  switch (geom)
2259  {
2260  case Geometry::TETRAHEDRON:
2261  {
2262  ev = tet_edges;
2263  for (int j = 0; j < 6; j++, ev += 2)
2264  if (vert_flags[ev[0]] != vert_flags[ev[1]])
2265  {
2266  cut_edges[n++] = j;
2267  }
2268  ev = tet_edges;
2269  }
2270  break;
2271 
2272  case Geometry::PYRAMID:
2273  {
2274  int emark[8];
2275  ev = pyr_edges;
2276  for (int j = 0; j < 8; j++, ev += 2)
2277  {
2278  emark[j] = vert_flags[ev[1]] - vert_flags[ev[0]];
2279  }
2280  do
2281  {
2282  int j;
2283  for (j = 0; j < 8; j++)
2284  {
2285  if (emark[j]) { break; }
2286  }
2287  if (j == 8)
2288  {
2289  break;
2290  }
2291  int k = 2 * j;
2292  if (emark[j] > 0)
2293  {
2294  k++;
2295  }
2296  do
2297  {
2298  int m;
2299  for (j = 0; j < 3; j++)
2300  {
2301  m = pyr_cutting[k][j];
2302  if (m >= 0)
2303  {
2304  ev = pyr_edges + 2 * (m / 2);
2305  if ((m%2 == 0 && vert_flags[ev[0]] > vert_flags[ev[1]]) ||
2306  (m%2 == 1 && vert_flags[ev[1]] > vert_flags[ev[0]]))
2307  {
2308  break;
2309  }
2310  }
2311  }
2312  cut_edges[n2++] = k/2;
2313  emark[k/2] = 0;
2314  k = m;
2315  }
2316  while (k/2 != cut_edges[n]);
2317  if (n == 0)
2318  {
2319  n = n2;
2320  }
2321  else
2322  {
2323  break;
2324  }
2325  }
2326  while (1);
2327  n2 -= n;
2328  ev = pyr_edges;
2329  }
2330  break;
2331 
2332  case Geometry::PRISM:
2333  {
2334  int emark[9];
2335  ev = pri_edges;
2336  for (int j = 0; j < 9; j++, ev += 2)
2337  {
2338  emark[j] = vert_flags[ev[1]] - vert_flags[ev[0]];
2339  }
2340  do
2341  {
2342  int j;
2343  for (j = 0; j < 9; j++)
2344  {
2345  if (emark[j]) { break; }
2346  }
2347  if (j == 9)
2348  {
2349  break;
2350  }
2351  int k = 2 * j;
2352  if (emark[j] > 0)
2353  {
2354  k++;
2355  }
2356  do
2357  {
2358  int m;
2359  for (j = 0; j < 3; j++)
2360  {
2361  m = pri_cutting[k][j];
2362  if (m >= 0)
2363  {
2364  ev = pri_edges + 2 * (m / 2);
2365  if ((m%2 == 0 && vert_flags[ev[0]] > vert_flags[ev[1]]) ||
2366  (m%2 == 1 && vert_flags[ev[1]] > vert_flags[ev[0]]))
2367  {
2368  break;
2369  }
2370  }
2371  }
2372  cut_edges[n2++] = k/2;
2373  emark[k/2] = 0;
2374  k = m;
2375  }
2376  while (k/2 != cut_edges[n]);
2377  if (n == 0)
2378  {
2379  n = n2;
2380  }
2381  else
2382  {
2383  break;
2384  }
2385  }
2386  while (1);
2387  n2 -= n;
2388  ev = pri_edges;
2389  }
2390  break;
2391 
2392  case Geometry::CUBE:
2393  {
2394  int emark[12];
2395  ev = hex_edges;
2396  for (int j = 0; j < 12; j++, ev += 2)
2397  {
2398  emark[j] = vert_flags[ev[1]] - vert_flags[ev[0]];
2399  }
2400  do
2401  {
2402  int j;
2403  for (j = 0; j < 12; j++)
2404  {
2405  if (emark[j]) { break; }
2406  }
2407  if (j == 12)
2408  {
2409  break;
2410  }
2411  int k = 2 * j;
2412  if (emark[j] > 0)
2413  {
2414  k++;
2415  }
2416  do
2417  {
2418  int m;
2419  for (j = 0; j < 3; j++)
2420  {
2421  m = hex_cutting[k][j];
2422  ev = hex_edges + 2 * (m / 2);
2423  if ((m%2 == 0 && vert_flags[ev[0]] > vert_flags[ev[1]]) ||
2424  (m%2 == 1 && vert_flags[ev[1]] > vert_flags[ev[0]]))
2425  {
2426  break;
2427  }
2428  }
2429  cut_edges[n2++] = k/2;
2430  emark[k/2] = 0;
2431  k = m;
2432  }
2433  while (k/2 != cut_edges[n]);
2434  if (n == 0)
2435  {
2436  n = n2;
2437  }
2438  else
2439  {
2440  break;
2441  }
2442  }
2443  while (1);
2444  n2 -= n;
2445  ev = hex_edges;
2446  }
2447  break;
2448 
2449  default:
2450  ev = NULL; // suppress a warning
2451  break;
2452  }
2453 
2454  *edge_vert_ptr = ev;
2455  *num_cut_edges = n;
2456  *n2_cut_edges = n2;
2457 }
2458 
2460 {
2461  int m, n, n2;
2462  int flag[8], cut_edges[6];
2463  const int *ev;
2464  double t, point[6][4], norm[3];
2465 
2466  DenseMatrix pointmat;
2467 
2468  Array<int> nodes;
2469  for (int i = 0; i < mesh -> GetNE(); i++)
2470  {
2471  n = n2 = 0; // n will be the number of intersection points
2472  mesh -> GetElementVertices(i, nodes);
2473  for (int j = 0; j < nodes.Size(); j++)
2474  {
2475  if (node_pos[nodes[j]] >= 0.0)
2476  {
2477  flag[j] = 1;
2478  }
2479  else
2480  {
2481  flag[j] = -1;
2482  }
2483  }
2484 
2485  CutElement(mesh->GetElementBaseGeometry(i), flag,
2486  &ev, cut_edges, &n, &n2);
2487 
2488  while (n > 2)
2489  {
2490  if (shading != 2)
2491  {
2492  mesh -> GetPointMatrix (i, pointmat);
2493  }
2494  else
2495  {
2496  const IntegrationRule *ir;
2497  ir = Geometries.GetVertices (mesh -> GetElementBaseGeometry(i));
2498  pointmat.SetSize (3, ir -> GetNPoints());
2499  for (int j = 0; j < ir -> GetNPoints(); j++)
2500  {
2501  const IntegrationPoint &ip = ir -> IntPoint (j);
2502  pointmat(0,j) = ip.x;
2503  pointmat(1,j) = ip.y;
2504  pointmat(2,j) = ip.z;
2505  }
2506  }
2507  for (int j = 0; j < n; j++)
2508  {
2509  const int *en = ev + 2*cut_edges[j];
2510  t = node_pos[ nodes[en[1]] ];
2511  t = t / ( t - node_pos[ nodes[en[0]] ] );
2512  for (int k = 0; k < 3; k++)
2513  {
2514  point[j][k] = t*pointmat(k,en[0]) + (1-t)*pointmat(k,en[1]);
2515  }
2516  point[j][3] = t*(*sol)(nodes[en[0]]) + (1-t)*(*sol)(nodes[en[1]]);
2517  }
2518 
2519  switch (func)
2520  {
2521  case 1: // PrepareCuttingPlane()
2522  {
2523  if (shading == 2)
2524  {
2525  // changes point for n > 4
2526  DrawRefinedSurf(n, point[0], i, 1);
2527  }
2528  else
2529  {
2530  m = n;
2531  int no_norm;
2532  while (1)
2533  {
2534  if (m > 3)
2535  {
2536  no_norm = Compute3DUnitNormal(point[0], point[1], point[2],
2537  point[3], norm);
2538  if (no_norm && m > 4)
2539  {
2540  for (int j = 3; j < m; j++)
2541  for (int k = 0; k < 4; k++)
2542  {
2543  point[j-2][k] = point[j][k];
2544  }
2545  m -= 2;
2546  continue;
2547  }
2548  }
2549  else
2550  no_norm = Compute3DUnitNormal(point[0], point[1], point[2],
2551  norm);
2552  break;
2553  }
2554 
2555  gl3::GlBuilder draw = cplane_buf.createBuilder();
2556  if (!no_norm)
2557  {
2558  draw.glBegin(GL_POLYGON);
2559  draw.glNormal3dv(norm);
2560  for (int j = 0; j < m; j++)
2561  {
2562  MySetColor(draw, point[j][3], minv, maxv);
2563  draw.glVertex3dv(point[j]);
2564  }
2565  draw.glEnd();
2566  }
2567  }
2568  }
2569  break;
2570 
2571  case 2: // PrepareCuttingPlaneLines() with mesh
2572  {
2573  if (shading == 2)
2574  {
2575  // changes point for n > 4
2576  DrawRefinedSurf(n, point[0], i, 2);
2577  }
2578  else
2579  {
2580  // glBegin (GL_POLYGON);
2581  gl3::GlBuilder line = cplines_buf.createBuilder();
2582  line.glBegin(GL_LINE_LOOP);
2583  for (int j = 0; j < n; j++)
2584  {
2585  line.glVertex3dv(point[j]);
2586  }
2587  line.glEnd();
2588  }
2589  }
2590  break;
2591 
2592  case 3: // PrepareCuttingPlaneLines() with level lines
2593  {
2594  if (shading == 2)
2595  {
2596  // changes point for n > 4
2597  DrawRefinedSurf(n, point[0], i, 3);
2598  }
2599  else
2600  {
2601  gl3::GlBuilder line = cplines_buf.createBuilder();
2602  DrawPolygonLevelLines(line, point[0], n, level, false);
2603  }
2604  }
2605  break;
2606  }
2607 
2608  for (int j = 0; j < n2; j++)
2609  {
2610  cut_edges[j] = cut_edges[j+n];
2611  }
2612  n = n2;
2613  n2 = 0;
2614  }
2615  }
2616 }
2617 
2619  gl3::GlDrawable& target,
2620  const DenseMatrix &verts, const Vector &vert_dist, const Vector &vals,
2621  const Geometry::Type geom, const int *elems, int num_elems, int func)
2622 {
2623  double sc = 0.0;
2624  if (FaceShiftScale != 0.0)
2625  {
2626  double bbox_diam = sqrt ( (bb.x[1]-bb.x[0])*(bb.x[1]-bb.x[0]) +
2627  (bb.y[1]-bb.y[0])*(bb.y[1]-bb.y[0]) +
2628  (bb.z[1]-bb.z[0])*(bb.z[1]-bb.z[0]) );
2629  sc = FaceShiftScale * bbox_diam;
2630  }
2631  const int nv = Geometry::NumVerts[geom];
2632 
2633  gl3::GlBuilder bld = target.createBuilder();
2634 
2635  for (int i = 0; i < num_elems; i++)
2636  {
2637  Geometry::Type egeom = geom;
2638  int vert_flag[8], cut_edges[8];
2639  const int *elem = elems + i*nv;
2640  const int *edge_vert;
2641  int n = 0, n2, nev = 0;
2642  for (int j = 0; j < nv; j++)
2643  {
2644  if (elem[j] < 0)
2645  {
2646  // This appears to be a tetrahedral subelement of a refined pyramid
2647  egeom = Geometry::TETRAHEDRON;
2648  break;
2649  }
2650  nev++;
2651  vert_flag[j] = (vert_dist(elem[j]) >= 0.0) ? n++, 1 : 0;
2652  }
2653  if (n == 0 || n == nev) { continue; }
2654 
2655  CutElement(egeom, vert_flag, &edge_vert, cut_edges, &n, &n2);
2656  // n = number of intersected edges
2657  // n2 = number of intersected edges, second polygon
2658 
2659  while (n > 2)
2660  {
2661  // 'pts' describe the intersecting polygon: triangle, quad, etc
2662  double pts[6][4]; // up to 6 points x (3 coordinates + 1 value)
2663 
2664  for (int j = 0; j < n; j++)
2665  {
2666  const int *ev = edge_vert + 2*cut_edges[j];
2667  double t = vert_dist(elem[ev[0]]);
2668  t = t / (t - vert_dist(elem[ev[1]]));
2669  for (int d = 0; d < 3; d++)
2670  {
2671  pts[j][d] = (1-t)*verts(d,elem[ev[0]]) + t*verts(d,elem[ev[1]]);
2672  }
2673  pts[j][3] = (1-t)*vals(elem[ev[0]]) + t*vals(elem[ev[1]]);
2674  }
2675  if (sc != 0.0)
2676  {
2677  const double *dir = CuttingPlane->Equation();
2678  for (int j = 0; j < n; j++)
2679  {
2680  // dir points into the visible side, so we add a minus to val:
2681  const double val = -sc * (pts[j][3] - minv) / (maxv - minv);
2682  for (int d = 0; d < 3; d++)
2683  {
2684  pts[j][d] += val*dir[d];
2685  }
2686  }
2687  }
2688 
2689  if (func == 0) // draw surface
2690  {
2691  double norm[3];
2692  int no_norm, m = n;
2693  while (1)
2694  {
2695  if (m > 3)
2696  {
2697  no_norm = Compute3DUnitNormal(pts[0], pts[1], pts[2], pts[3],
2698  norm);
2699  if (no_norm && m > 4)
2700  {
2701  for (int j = 3; j < m; j++)
2702  {
2703  for (int k = 0; k < 4; k++)
2704  {
2705  pts[j-2][k] = pts[j][k];
2706  }
2707  }
2708  m -= 2;
2709  continue;
2710  }
2711  }
2712  else
2713  {
2714  no_norm = Compute3DUnitNormal(pts[0], pts[1], pts[2], norm);
2715  }
2716  break;
2717  }
2718  if (!no_norm)
2719  {
2720  bld.glBegin(GL_POLYGON);
2721  bld.glNormal3dv(norm);
2722  for (int j = 0; j < m; j++)
2723  {
2724  MySetColor(bld, pts[j][3], minv, maxv);
2725  bld.glVertex3dv(pts[j]);
2726  }
2727  bld.glEnd();
2728  }
2729  }
2730  else // draw level lines
2731  {
2732  DrawPolygonLevelLines(bld, pts[0], n, level, false);
2733  }
2734 
2735  for (int j = 0; j < n2; j++)
2736  {
2737  cut_edges[j] = cut_edges[j+n];
2738  }
2739  n = n2;
2740  n2 = 0;
2741  }
2742  }
2743 }
2744 
2746  gl3::GlDrawable& target,
2747  const DenseMatrix &verts, const Vector &vert_dist, const Vector &vals,
2748  const Geometry::Type geom, const int *faces, int num_faces)
2749 {
2750  double sc = 0.0;
2751  if (FaceShiftScale != 0.0)
2752  {
2753  double bbox_diam = sqrt ( (bb.x[1]-bb.x[0])*(bb.x[1]-bb.x[0]) +
2754  (bb.y[1]-bb.y[0])*(bb.y[1]-bb.y[0]) +
2755  (bb.z[1]-bb.z[0])*(bb.z[1]-bb.z[0]) );
2756  sc = FaceShiftScale * bbox_diam;
2757  }
2758  const int nv = Geometry::NumVerts[geom];
2759 
2760  for (int i = 0; i < num_faces; i++)
2761  {
2762  int vert_flag[4], cut_edges[4];
2763  const int *face = faces + i*nv;
2764  int n = 0;
2765  for (int j = 0; j < nv; j++)
2766  {
2767  vert_flag[j] = (vert_dist(face[j]) >= 0.0) ? n++, 1 : 0;
2768  }
2769  if (n == 0 || n == nv) { continue; }
2770  n = 0;
2771  for (int j = 0; j < nv; j++)
2772  {
2773  const int j1 = (j+1)%nv;
2774  if (vert_flag[j] != vert_flag[j1])
2775  {
2776  cut_edges[n++] = j;
2777  }
2778  }
2779  // n = number of intersected edges (2, or 4)
2780  double pts[4][4]; // up to 4 points x (3 coordinates + 1 value)
2781  for (int j = 0; j < n; j++)
2782  {
2783  const int v0 = cut_edges[j];
2784  const int v1 = (v0+1)%nv;
2785  double t = vert_dist(face[v0]);
2786  t = t / (t - vert_dist(face[v1]));
2787  for (int d = 0; d < 3; d++)
2788  {
2789  pts[j][d] = (1-t)*verts(d,face[v0]) + t*verts(d,face[v1]);
2790  }
2791  if (sc != 0.0)
2792  {
2793  pts[j][3] = (1-t)*vals(face[v0]) + t*vals(face[v1]);
2794  }
2795  }
2796  if (sc != 0.0)
2797  {
2798  const double *dir = CuttingPlane->Equation();
2799  for (int j = 0; j < n; j++)
2800  {
2801  // dir points into the visible side, so we add a minus to val:
2802  const double val = -sc * (pts[j][3] - minv) / (maxv - minv);
2803  for (int d = 0; d < 3; d++)
2804  {
2805  pts[j][d] += val*dir[d];
2806  }
2807  }
2808  }
2809 
2810  target.addLine(gl3::Vertex::create(pts[0]), gl3::Vertex::create(pts[1]));
2811  if (n == 4)
2812  {
2813  target.addLine(gl3::Vertex::create(pts[2]), gl3::Vertex::create(pts[3]));
2814  }
2815  }
2816 }
2817 
2819 {
2820  cplane_buf.clear();
2821  if (cp_drawelems && cplane && mesh->Dimension() == 3)
2822  {
2823  if (cplane == 2)
2824  {
2825  PrepareCuttingPlane2();
2826  }
2827  else if (cp_algo == 1)
2828  {
2829  CuttingPlaneFunc(1);
2830  }
2831  else
2832  {
2833  Vector vals, vert_dist;
2834  DenseMatrix pointmat;
2835  for (int i = 0; i < mesh->GetNE(); i++)
2836  {
2837  const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
2838  RefinedGeometry *RefG =
2839  GLVisGeometryRefiner.Refine(geom, TimesToRefine);
2840  GridF->GetValues(i, RefG->RefPts, vals, pointmat);
2841  vert_dist.SetSize(pointmat.Width());
2842  for (int j = 0; j < pointmat.Width(); j++)
2843  {
2844  vert_dist(j) = CuttingPlane->Transform(&pointmat(0,j));
2845  }
2846  Array<int> &RG = RefG->RefGeoms;
2847 
2848  const int func = 0; // draw surface
2849  CutRefinedElement(cplane_buf, pointmat, vert_dist, vals, geom,
2850  RG, RG.Size()/Geometry::NumVerts[geom], func);
2851  }
2852  }
2853  }
2854  updated_bufs.emplace_back(&cplane_buf);
2855 }
2856 
2858 {
2859  int i, j, n = 0;
2860  double p[4][3], c[4], *coord;
2861  DenseMatrix pointmat, normals;
2862  Vector values;
2863  RefinedGeometry *RefG;
2864 
2865  Array<int> nodes;
2866  Array<int> partition (mesh -> GetNE());
2867 
2868  for (i = 0; i < mesh -> GetNE(); i++)
2869  {
2870  n = 0; // n will be the number of nodes behind the cutting plane
2871  mesh -> GetElementVertices(i, nodes);
2872  for (j = 0; j < nodes.Size(); j++)
2873  {
2874  if (node_pos[nodes[j]] >= 0.0) { n++; }
2875  }
2876  partition[i] = (n == nodes.Size()) ? 0 : 1;
2877  }
2878 
2879  for (i = 0; i < mesh -> GetNFaces(); i++)
2880  {
2881  int e1, e2;
2882  mesh -> GetFaceElements (i, &e1, &e2);
2883  if (e2 >= 0 && partition[e1] != partition[e2])
2884  {
2885  if (shading != 2)
2886  {
2887  mesh -> GetFaceVertices (i, nodes);
2888  for (j = 0; j < nodes.Size(); j++)
2889  {
2890  coord = mesh -> GetVertex(nodes[j]);
2891  p[j][0] = coord[0];
2892  p[j][1] = coord[1];
2893  p[j][2] = coord[2];
2894  c[j] = (*sol)(nodes[j]);
2895  }
2896 
2897  if (nodes.Size() == 3)
2898  {
2899  DrawTriangle(cplane_buf, p, c, minv, maxv);
2900  }
2901  else
2902  {
2903  DrawQuad(cplane_buf, p, c, minv, maxv);
2904  }
2905  }
2906  else // shading == 2
2907  {
2908  RefG = GLVisGeometryRefiner.Refine(mesh -> GetFaceBaseGeometry (i),
2909  TimesToRefine);
2910  // partition[e1] is 0 if e1 is behind the cutting plane
2911  // and 1 otherwise
2912  int dir = partition[e1];
2913  GridF -> GetFaceValues (i, dir, RefG->RefPts, values, pointmat);
2914  GetFaceNormals(i, dir, RefG->RefPts, normals);
2915  switch (mesh -> GetFaceBaseGeometry (i))
2916  {
2917  case Geometry::TRIANGLE: n = 3; break;
2918  case Geometry::SQUARE: n = 4; break;
2919  default:
2920  MFEM_ABORT("Invalid element type");
2921  break;
2922  }
2923  // DrawRefinedSurf (n, pointmat, values, RefG->RefGeoms);
2924  DrawPatch(cplane_buf, pointmat, values, normals, n, RefG->RefGeoms,
2925  minv, maxv, dir ? -3 : 2);
2926  } // end shading == 2
2927  }
2928  }
2929 }
2930 
2932 {
2933  cplines_buf.clear();
2934 
2935  if (cp_drawmesh && cplane && mesh->Dimension() == 3)
2936  {
2937  if (cplane == 2 && cp_drawmesh != 3)
2938  {
2939  PrepareCuttingPlaneLines2();
2940  }
2941  else
2942  {
2943  if (cp_drawmesh == 1 && cp_algo == 1)
2944  {
2945  CuttingPlaneFunc(2);
2946  }
2947  else if (cp_drawmesh == 1)
2948  {
2949  Vector vert_dist, vals;
2950  DenseMatrix pointmat;
2951  int num_faces = mesh->GetNFaces();
2952  if (mesh->NURBSext)
2953  {
2954  // Note: for NURBS meshes, the methods
2955  // Mesh::GetFaceTransformation() and
2956  // GridFunction::GetFaceValues() are not supported.
2957  cout << _MFEM_FUNC_NAME
2958  << ": NURBS mesh: cut faces will not be drawn!" << endl;
2959  num_faces = 0;
2960  }
2961  for (int i = 0; i < num_faces; i++)
2962  {
2963  const Geometry::Type geom = mesh->GetFaceBaseGeometry(i);
2964  RefinedGeometry *RefG =
2965  GLVisGeometryRefiner.Refine(geom, TimesToRefine);
2966  if (FaceShiftScale == 0.0)
2967  {
2968  ElementTransformation *T = mesh->GetFaceTransformation(i);
2969  T->Transform(RefG->RefPts, pointmat);
2970  }
2971  else
2972  {
2973  const int side = 2;
2974  GridF->GetFaceValues(i, side, RefG->RefPts, vals, pointmat);
2975  // For discontinuous grid function, we should draw two edges.
2976  }
2977  vert_dist.SetSize(pointmat.Width());
2978  for (int j = 0; j < pointmat.Width(); j++)
2979  {
2980  vert_dist(j) = CuttingPlane->Transform(&pointmat(0,j));
2981  }
2982  Array<int> &RG = RefG->RefGeoms;
2983 
2984  CutRefinedFace(cplines_buf, pointmat, vert_dist, vals, geom,
2985  RG, RG.Size()/Geometry::NumVerts[geom]);
2986  }
2987  }
2988  else if (cp_algo == 1)
2989  {
2990  CuttingPlaneFunc(3);
2991  }
2992  else
2993  {
2994  Vector vals, vert_dist;
2995  DenseMatrix pointmat;
2996  for (int i = 0; i < mesh->GetNE(); i++)
2997  {
2998  const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
2999  RefinedGeometry *RefG =
3000  GLVisGeometryRefiner.Refine(geom, TimesToRefine);
3001  GridF->GetValues(i, RefG->RefPts, vals, pointmat);
3002  vert_dist.SetSize(pointmat.Width());
3003  for (int j = 0; j < pointmat.Width(); j++)
3004  {
3005  vert_dist(j) = CuttingPlane->Transform(&pointmat(0,j));
3006  }
3007  Array<int> &RG = RefG->RefGeoms;
3008 
3009  const int func = 1; // draw level lines
3010  CutRefinedElement(cplines_buf, pointmat, vert_dist, vals, geom,
3011  RG, RG.Size()/Geometry::NumVerts[geom], func);
3012  }
3013  }
3014  }
3015  }
3016 
3017  updated_bufs.emplace_back(&cplines_buf);
3018 }
3019 
3021 {
3022  int i, j, n = 0;
3023  double point[4][4], *coord;
3024  DenseMatrix pointmat;
3025  Vector values;
3026  RefinedGeometry *RefG;
3027 
3028  Array<int> nodes;
3029  Array<int> partition (mesh -> GetNE());
3030  for (i = 0; i < mesh -> GetNE(); i++)
3031  {
3032  n = 0; // n will be the number of nodes behind the cutting plane
3033  mesh -> GetElementVertices(i,nodes);
3034  for (j=0; j<nodes.Size(); j++)
3035  {
3036  if (node_pos[nodes[j]] >= 0.0) { n++; }
3037  }
3038  partition[i] = (n == nodes.Size()) ? 0 : 1;
3039  }
3040 
3041  for (i = 0; i < mesh -> GetNFaces(); i++)
3042  {
3043  int e1, e2;
3044  mesh -> GetFaceElements (i, &e1, &e2);
3045  if (e2 >= 0 && partition[e1] != partition[e2])
3046  {
3047  if (shading != 2)
3048  {
3049  mesh -> GetFaceVertices (i, nodes);
3050  for (j = 0; j < nodes.Size(); j++)
3051  {
3052  coord = mesh -> GetVertex(nodes[j]);
3053  point[j][0] = coord[0];
3054  point[j][1] = coord[1];
3055  point[j][2] = coord[2];
3056  point[j][3] = (*sol)(nodes[j]);
3057  }
3058  gl3::GlBuilder line = cplines_buf.createBuilder();
3059  switch (cp_drawmesh)
3060  {
3061  case 1:
3062  // glBegin(GL_POLYGON);
3063  line.glBegin(GL_LINE_LOOP);
3064  for (j = 0; j < nodes.Size(); j++)
3065  {
3066  line.glVertex3dv (point[j]);
3067  }
3068  line.glEnd();
3069  break;
3070  case 2:
3071  DrawPolygonLevelLines(line, point[0], nodes.Size(), level, false);
3072  break;
3073  }
3074  }
3075  else // shading == 2
3076  {
3077  RefG = GLVisGeometryRefiner.Refine(mesh -> GetFaceBaseGeometry (i),
3078  TimesToRefine);
3079  // partition[e1] is 0 if e1 is behind the cutting plane
3080  // and 1 otherwise
3081  int di = partition[e1];
3082  GridF -> GetFaceValues (i, di, RefG->RefPts, values, pointmat);
3083  switch (mesh -> GetFaceBaseGeometry (i))
3084  {
3085  case Geometry::TRIANGLE: n = 3; break;
3086  case Geometry::SQUARE: n = 4; break;
3087  default:
3088  MFEM_ABORT("Invalid element type");
3089  break;
3090  }
3091  switch (cp_drawmesh)
3092  {
3093  case 1:
3094  DrawRefinedSurfEdges (n, pointmat, values, RefG->RefEdges);
3095  break;
3096  case 2:
3097  DrawRefinedSurfLevelLines (n, pointmat, values,
3098  RefG->RefGeoms);
3099  break;
3100  }
3101  } // end shading == 2
3102  }
3103  }
3104 }
3105 
3106 thread_local int triangle_counter;
3107 thread_local int quad_counter;
3108 
3110  gl3::GlDrawable& target,
3111  const DenseMatrix &verts, const Vector &vals, const int *ind,
3112  const Array<double> &surf_levels, const DenseMatrix *grad)
3113 {
3114  double t, lvl, normal[3], vert[4][3], norm[4][3];
3115  int i, j, l, pos[4];
3116  bool flipped;
3117 
3118  gl3::GlBuilder draw = target.createBuilder();
3119 
3120  for (l = 0; l < surf_levels.Size(); l++)
3121  {
3122  lvl = surf_levels[l];
3123 
3124  for (i = 0; i < 4; i++)
3125  {
3126  pos[i] = ind[i];
3127  }
3128  i = 0;
3129  j = 4;
3130  flipped = false;
3131  do
3132  {
3133  // (i < j) is true
3134  while (vals(pos[i]) < lvl)
3135  {
3136  i++;
3137  if (i == j)
3138  {
3139  goto step_one;
3140  }
3141  }
3142  // (i < j) && (vals[pos[i]] >= lvl) is true
3143  do
3144  {
3145  j--;
3146  if (i == j)
3147  {
3148  goto step_one;
3149  }
3150  }
3151  while (vals(pos[j]) >= lvl);
3152  // (i < j) && (vals[pos[i]] >= lvl) && (vals[pos[j]] < lvl) is true
3153  Swap<int>(pos[i], pos[j]);
3154  flipped = !flipped;
3155  i++;
3156  }
3157  while (i < j);
3158  step_one:
3159  if (flipped)
3160  {
3161  if (i >= 2)
3162  {
3163  Swap<int>(pos[0], pos[1]);
3164  }
3165  else
3166  {
3167  Swap<int>(pos[2], pos[3]);
3168  }
3169  }
3170 
3171  if (j == 3)
3172  {
3173  Swap<int>(pos[0], pos[3]);
3174  j = 1;
3175  }
3176  if (j == 1)
3177  {
3178  for (int k = 0; k < 3; k++)
3179  {
3180  int p0 = pos[0];
3181  int p1 = pos[k+1];
3182  t = (lvl - vals(p0)) / (vals(p1) - vals(p0));
3183  for (int d = 0; d < 3; d++)
3184  {
3185  vert[k][d] = (1.0 - t) * verts(d, p0) + t * verts(d, p1);
3186  }
3187  if (grad)
3188  for (int d = 0; d < 3; d++)
3189  {
3190  norm[k][d] = (1.0 - t) * (*grad)(d, p0) + t * (*grad)(d, p1);
3191  }
3192  }
3193 
3194  if (grad == NULL)
3195  {
3196  if (!Compute3DUnitNormal(vert[0], vert[1], vert[2], normal))
3197  {
3198  MySetColor(draw, lvl, minv, maxv);
3199  draw.glNormal3dv(normal);
3200  draw.glBegin(GL_TRIANGLES);
3201  for (int k = 0; k < 3; k++)
3202  {
3203  draw.glVertex3dv(vert[k]);
3204  }
3205  draw.glEnd();
3206  triangle_counter++;
3207  }
3208  }
3209  else
3210  {
3211  MySetColor(draw, lvl, minv, maxv);
3212  draw.glBegin(GL_TRIANGLES);
3213  for (int k = 0; k < 3; k++)
3214  {
3215  Normalize(norm[k]);
3216  draw.glNormal3dv(norm[k]);
3217  draw.glVertex3dv(vert[k]);
3218  }
3219  draw.glEnd();
3220  triangle_counter++;
3221  }
3222  }
3223  else if (j == 2)
3224  {
3225  static const int idx[4][2] = { {0, 2}, {0, 3}, {1, 3}, {1, 2} };
3226 
3227  for (int k = 0; k < 4; k++)
3228  {
3229  int p0 = pos[idx[k][0]];
3230  int p1 = pos[idx[k][1]];
3231  t = (lvl - vals(p0)) / (vals(p1) - vals(p0));
3232  for (int d = 0; d < 3; d++)
3233  {
3234  vert[k][d] = (1.0 - t) * verts(d, p0) + t * verts(d, p1);
3235  }
3236  if (grad)
3237  for (int d = 0; d < 3; d++)
3238  {
3239  norm[k][d] = (1.0 - t) * (*grad)(d, p0) + t * (*grad)(d, p1);
3240  }
3241  }
3242 
3243  if (grad == NULL)
3244  {
3245  if (!Compute3DUnitNormal(vert[0], vert[1], vert[2], vert[3],
3246  normal))
3247  {
3248  MySetColor(draw, lvl, minv, maxv);
3249  draw.glNormal3dv(normal);
3250  draw.glBegin(GL_QUADS);
3251  for (int k = 0; k < 4; k++)
3252  {
3253  draw.glVertex3dv(vert[k]);
3254  }
3255  draw.glEnd();
3256  quad_counter++;
3257  }
3258  }
3259  else
3260  {
3261  MySetColor(draw, lvl, minv, maxv);
3262  draw.glBegin(GL_QUADS);
3263  for (int k = 0; k < 4; k++)
3264  {
3265  Normalize(norm[k]);
3266  draw.glNormal3dv(norm[k]);
3267  draw.glVertex3dv(vert[k]);
3268  }
3269  draw.glEnd();
3270  quad_counter++;
3271  }
3272  }
3273  }
3274 }
3275 
3276 // static method
3278  const Array<bool> &quad_diag, const Array<int> &faces,
3279  const Array<int> &ofaces)
3280 {
3281  int fs = 0;
3282  bool diag = quad_diag[faces[0]];
3283  if ((ofaces[0]/2)%2) // orientations 2,3,6,7
3284  {
3285  diag = !diag;
3286  }
3287  fs = 2*fs + diag;
3288  return fs;
3289 }
3290 
3292  gl3::GlDrawable& target,
3293  const DenseMatrix &verts, const Vector &vals, const int *RG, const int np,
3294  const int face_splits, const DenseMatrix *grad)
3295 {
3296 #if 1
3297  static const int pyr_tets[2][4] =
3298  {
3299  { 0, 1, 2, 4 }, { 0, 2, 3, 4 }
3300  };
3301  for (int k = 0; k < np; k++)
3302  {
3303  const int *hv = &RG[5*k];
3304  if (hv[4] > 0)
3305  {
3306  for (int j = 0; j < 2; j++)
3307  {
3308  int m_ind[4];
3309  for (int i = 0; i < 4; i++)
3310  {
3311  m_ind[i] = hv[pyr_tets[j][i]];
3312  }
3313  DrawTetLevelSurf(target, verts, vals, m_ind, levels, grad);
3314  }
3315  }
3316  else
3317  {
3318  DrawTetLevelSurf(target, verts, vals, hv, levels, grad);
3319  }
3320  }
3321 #else
3322  // MLS: Not sure how to adapt this to Pyramids so skip it for now
3323  static const int pri_tets[8-2][3][4] =
3324  {
3325  // 0 = 000 (see below; prism is split into 6 tets)
3326  { { 0, 1, 2, 5 }, { 0, 1, 5, 4 }, { 0, 3, 4, 5 } }, // 1 = 001
3327  { { 0, 1, 2, 4 }, { 0, 2, 3, 4 }, { 2, 3, 4, 5 } }, // 2 = 010
3328  { { 0, 1, 2, 4 }, { 0, 2, 5, 4 }, { 0, 3, 4, 5 } }, // 3 = 011
3329  { { 0, 1, 2, 3 }, { 1, 2, 3, 5 }, { 1, 3, 4, 5 } }, // 4 = 100
3330  { { 0, 1, 2, 5 }, { 0, 1, 5, 3 }, { 1, 3, 4, 5 } }, // 5 = 101
3331  { { 0, 1, 2, 3 }, { 1, 2, 3, 4 }, { 2, 3, 4, 5 } } // 6 = 110
3332  // 7 = 111 (see below; prism is split into 6 tets)
3333  };
3334  static const int pri_tets_0[6][4] =
3335  { {0,1,2,6}, {0,1,6,4}, {0,2,3,6}, {0,6,3,4}, {2,3,6,5}, {3,4,6,5} };
3336  static const int pri_tets_7[6][4] =
3337  { {0,1,2,6}, {0,2,5,6}, {0,1,6,3}, {0,3,6,5}, {1,3,4,6}, {3,4,6,5} };
3338  const int fs2 = (~face_splits&7)/2 + 4*((~face_splits&7)%2);
3339  const int n = (np == 1) ? 1 : TimesToRefine;
3340 
3341  double vs_data[7], pm_data[3*7], gd_data[3*7];
3342  Vector vs(vs_data, 7);
3343  DenseMatrix pm(pm_data, 3, 7), gd(gd_data, 3, 7);
3344 
3345  for (int k = 0, l0 = -1, l1 = -1; k < np; k++)
3346  {
3347  const int pk = k % (n*n);
3348  if (pk == 0)
3349  {
3350  l0 = 0; l1 = 2*n-1;
3351  }
3352  else if (pk == l1)
3353  {
3354  const int s = l1-l0;
3355  l0 = l1;
3356  l1 += (s-2);
3357  }
3358  const int fsl = ((pk-l0)%2 == 0) ? face_splits : fs2;
3359  // The algorithm for choosing 'fsl' used above assumes the refined prisms
3360  // are listed in certain order -- see the prism case in
3361  // mfem::GeometryRefiner::Refine.
3362  const int *pv = &RG[6*k];
3363  if (fsl == 0)
3364  {
3365  for (int j = 0; j < 6; j++)
3366  {
3367  const int idx = pv[j];
3368  for (int d = 0; d < 3; d++)
3369  {
3370  pm(d,j) = verts(d,idx);
3371  if (grad) { gd(d,j) = (*grad)(d,idx); }
3372  }
3373  vs(j) = vals(idx);
3374  }
3375  for (int d = 0; d < 3; d++)
3376  {
3377  pm(d,6) = 0.5*(pm(d,1) + pm(d,5));
3378  if (grad) { gd(d,6) = 0.5*(gd(d,1) + gd(d,5)); }
3379  }
3380  vs(6) = 0.5*(vs(1) + vs(5));
3381  const DenseMatrix *gd_ = grad ? &gd : NULL;
3382  for (int k = 0; k < 6; k++)
3383  {
3384  DrawTetLevelSurf(pm, vs, pri_tets_0[k], levels, gd_);
3385  }
3386  }
3387  else if (fsl == 7)
3388  {
3389  for (int j = 0; j < 6; j++)
3390  {
3391  const int idx = pv[j];
3392  for (int d = 0; d < 3; d++)
3393  {
3394  pm(d,j) = verts(d,idx);
3395  if (grad) { gd(d,j) = (*grad)(d,idx); }
3396  }
3397  vs(j) = vals(idx);
3398  }
3399  for (int d = 0; d < 3; d++)
3400  {
3401  pm(d,6) = 0.5*(pm(d,2) + pm(d,4));
3402  if (grad) { gd(d,6) = 0.5*(gd(d,2) + gd(d,4)); }
3403  }
3404  vs(6) = 0.5*(vs(2) + vs(4));
3405  const DenseMatrix *gd_ = grad ? &gd : NULL;
3406  for (int k = 0; k < 6; k++)
3407  {
3408  DrawTetLevelSurf(pm, vs, pri_tets_7[k], levels, gd_);
3409  }
3410  }
3411  else
3412  {
3413  int m_ind[4];
3414  for (int j = 0; j < 3; j++)
3415  {
3416  for (int i = 0; i < 4; i++)
3417  {
3418  m_ind[i] = pv[pri_tets[fsl-1][j][i]];
3419  }
3420  DrawTetLevelSurf(verts, vals, m_ind, levels, grad);
3421  }
3422  }
3423  }
3424 #endif
3425 }
3426 
3427 // static method
3429  const Array<bool> &quad_diag, const Array<int> &faces,
3430  const Array<int> &ofaces)
3431 {
3432  int fs = 0;
3433  for (int lf = 2; lf < 5; lf++)
3434  {
3435  bool diag = quad_diag[faces[lf]];
3436  if ((ofaces[lf]/2)%2) // orientations 2,3,6,7
3437  {
3438  diag = !diag;
3439  }
3440  fs = 2*fs + diag;
3441  }
3442  return fs;
3443 }
3444 
3446  gl3::GlDrawable& target,
3447  const DenseMatrix &verts, const Vector &vals, const int *RG, const int np,
3448  const int face_splits, const DenseMatrix *grad)
3449 {
3450 #if 0
3451  static const int pri_tets[3][4] =
3452  {
3453  { 0, 1, 2, 5 }, { 0, 1, 5, 3 }, { 1, 3, 4, 5 }
3454  };
3455  for (int k = 0; k < np; k++)
3456  {
3457  const int *hv = &RG[6*k];
3458  for (int j = 0; j < 3; j++)
3459  {
3460  int m_ind[4];
3461  for (int i = 0; i < 4; i++)
3462  {
3463  m_ind[i] = hv[pri_tets[j][i]];
3464  }
3465  DrawTetLevelSurf(verts, vals, m_ind, levels, grad);
3466  }
3467  }
3468 #else
3469  static const int pri_tets[8-2][3][4] =
3470  {
3471  // 0 = 000 (see below; prism is split into 6 tets)
3472  { { 0, 1, 2, 5 }, { 0, 1, 5, 4 }, { 0, 3, 4, 5 } }, // 1 = 001
3473  { { 0, 1, 2, 4 }, { 0, 2, 3, 4 }, { 2, 3, 4, 5 } }, // 2 = 010
3474  { { 0, 1, 2, 4 }, { 0, 2, 5, 4 }, { 0, 3, 4, 5 } }, // 3 = 011
3475  { { 0, 1, 2, 3 }, { 1, 2, 3, 5 }, { 1, 3, 4, 5 } }, // 4 = 100
3476  { { 0, 1, 2, 5 }, { 0, 1, 5, 3 }, { 1, 3, 4, 5 } }, // 5 = 101
3477  { { 0, 1, 2, 3 }, { 1, 2, 3, 4 }, { 2, 3, 4, 5 } } // 6 = 110
3478  // 7 = 111 (see below; prism is split into 6 tets)
3479  };
3480  static const int pri_tets_0[6][4] =
3481  { {0,1,2,6}, {0,1,6,4}, {0,2,3,6}, {0,6,3,4}, {2,3,6,5}, {3,4,6,5} };
3482  static const int pri_tets_7[6][4] =
3483  { {0,1,2,6}, {0,2,5,6}, {0,1,6,3}, {0,3,6,5}, {1,3,4,6}, {3,4,6,5} };
3484  const int fs2 = (~face_splits&7)/2 + 4*((~face_splits&7)%2);
3485  const int n = (np == 1) ? 1 : TimesToRefine;
3486 
3487  double vs_data[7], pm_data[3*7], gd_data[3*7];
3488  Vector vs(vs_data, 7);
3489  DenseMatrix pm(pm_data, 3, 7), gd(gd_data, 3, 7);
3490 
3491  for (int k = 0, l0 = -1, l1 = -1; k < np; k++)
3492  {
3493  const int pk = k % (n*n);
3494  if (pk == 0)
3495  {
3496  l0 = 0; l1 = 2*n-1;
3497  }
3498  else if (pk == l1)
3499  {
3500  const int s = l1-l0;
3501  l0 = l1;
3502  l1 += (s-2);
3503  }
3504  const int fsl = ((pk-l0)%2 == 0) ? face_splits : fs2;
3505  // The algorithm for choosing 'fsl' used above assumes the refined prisms
3506  // are listed in certain order -- see the prism case in
3507  // mfem::GeometryRefiner::Refine.
3508  const int *pv = &RG[6*k];
3509  if (fsl == 0)
3510  {
3511  for (int j = 0; j < 6; j++)
3512  {
3513  const int idx = pv[j];
3514  for (int d = 0; d < 3; d++)
3515  {
3516  pm(d,j) = verts(d,idx);
3517  if (grad) { gd(d,j) = (*grad)(d,idx); }
3518  }
3519  vs(j) = vals(idx);
3520  }
3521  for (int d = 0; d < 3; d++)
3522  {
3523  pm(d,6) = 0.5*(pm(d,1) + pm(d,5));
3524  if (grad) { gd(d,6) = 0.5*(gd(d,1) + gd(d,5)); }
3525  }
3526  vs(6) = 0.5*(vs(1) + vs(5));
3527  const DenseMatrix *gd_ = grad ? &gd : NULL;
3528  for (int j = 0; j < 6; j++)
3529  {
3530  DrawTetLevelSurf(target, pm, vs, pri_tets_0[j], levels, gd_);
3531  }
3532  }
3533  else if (fsl == 7)
3534  {
3535  for (int j = 0; j < 6; j++)
3536  {
3537  const int idx = pv[j];
3538  for (int d = 0; d < 3; d++)
3539  {
3540  pm(d,j) = verts(d,idx);
3541  if (grad) { gd(d,j) = (*grad)(d,idx); }
3542  }
3543  vs(j) = vals(idx);
3544  }
3545  for (int d = 0; d < 3; d++)
3546  {
3547  pm(d,6) = 0.5*(pm(d,2) + pm(d,4));
3548  if (grad) { gd(d,6) = 0.5*(gd(d,2) + gd(d,4)); }
3549  }
3550  vs(6) = 0.5*(vs(2) + vs(4));
3551  const DenseMatrix *gd_ = grad ? &gd : NULL;
3552  for (int j = 0; j < 6; j++)
3553  {
3554  DrawTetLevelSurf(target, pm, vs, pri_tets_7[j], levels, gd_);
3555  }
3556  }
3557  else
3558  {
3559  int m_ind[4];
3560  for (int j = 0; j < 3; j++)
3561  {
3562  for (int i = 0; i < 4; i++)
3563  {
3564  m_ind[i] = pv[pri_tets[fsl-1][j][i]];
3565  }
3566  DrawTetLevelSurf(target, verts, vals, m_ind, levels, grad);
3567  }
3568  }
3569  }
3570 #endif
3571 }
3572 
3573 // static method
3575  const Array<bool> &quad_diag, const Array<int> &faces,
3576  const Array<int> &ofaces)
3577 {
3578  int fs = 0;
3579  for (int lf = 0; lf < 6; lf++)
3580  {
3581  bool diag = quad_diag[faces[lf]];
3582  if ((ofaces[lf]/2)%2) // orientations 2,3,6,7
3583  {
3584  diag = !diag;
3585  }
3586  fs = 2*fs + diag;
3587  }
3588  return fs;
3589 }
3590 
3592  gl3::GlDrawable& target,
3593  const DenseMatrix &verts, const Vector &vals, const int *RG, const int nh,
3594  const int face_splits, const DenseMatrix *grad)
3595 {
3596 #if 0
3597  static const int hex_tets[6][4] =
3598  {
3599  { 0, 1, 2, 6 }, { 0, 5, 1, 6 }, { 0, 4, 5, 6 },
3600  { 0, 2, 3, 6 }, { 0, 3, 7, 6 }, { 0, 7, 4, 6 }
3601  };
3602  for (int k = 0; k < nh; k++)
3603  {
3604  const int *hv = &RG[8*k];
3605  for (int j = 0; j < 6; j++)
3606  {
3607  int m_ind[4];
3608  for (int i = 0; i < 4; i++)
3609  {
3610  m_ind[i] = hv[hex_tets[j][i]];
3611  }
3612  DrawTetLevelSurf(verts, vals, m_ind, levels, grad);
3613  }
3614  }
3615 #else
3616  const int n = (nh == 1) ? 1 : TimesToRefine;
3617 
3618  double vs_data[9], pm_data[3*9], gd_data[3*9];
3619  Vector vs(vs_data, 9);
3620  DenseMatrix pm(pm_data, 3, 9), gd(gd_data, 3, 9);
3621 
3622  for (int k = 0; k < nh; k++)
3623  {
3624  const int ix = k%n, iy = (k/n)%n, iz = k/(n*n);
3625  int fsl = face_splits;
3626  if (ix != 0)
3627  {
3628  // Copy the right face bit (face 2, bit mask 8) to the left face bit
3629  // (face 4, bit mask 2) and flip it.
3630  fsl = (fsl&(63-2)) + (2-(fsl&8)/4);
3631  }
3632  if (iy != 0)
3633  {
3634  // Copy the back face bit (face 3, bit mask 4) to the front face bit
3635  // (face 1, bit mask 16) and flip it.
3636  fsl = (fsl&(63-16)) + (16-(fsl&4)*4);
3637  }
3638  if (iz != 0)
3639  {
3640  // Copy the top face bit (face 5, bit mask 1) to the bottom face bit
3641  // (face 0, bit mask 32) and flip it.
3642  fsl = (fsl&(63-32)) + (32-(fsl&1)*32);
3643  }
3644 
3645  const int *hv_orig = &RG[8*k], *hv;
3646  int hv1[8], hv2[8];
3647 #if 1
3648  // Find a pair of opposite faces that are split into triangles using
3649  // two parallel diagonals (if such pair exists).
3650  if (1-(fsl&1) == (fsl&32)/32)
3651  {
3652  // The bottom and top faces are split in the same direction.
3653  hv = hv_orig;
3654  }
3655  else if (4-(fsl&4) == (fsl&16)/4)
3656  {
3657  // The front and back faces are split in the same direction.
3658  // Rotate the hex around the x-axis to bring front-back to bottom-top.
3659  static const int rot_x[8] = { 4, 5, 1, 0, 7, 6, 2, 3 };
3660  for (int j = 0; j < 8; j++)
3661  {
3662  hv1[j] = hv_orig[rot_x[j]];
3663  }
3664  hv = hv1;
3665  // fsl bits change: a|b|c|d|e|f -> b|f|1-c|a|1-e|d
3666  fsl = (fsl&16)*2 + (fsl&1)*16 + (8-(fsl&8)) + (fsl&32)/8 +
3667  (2-(fsl&2)) + (fsl&4)/4;
3668  }
3669  else if (2-(fsl&2) == (fsl&8)/4)
3670  {
3671  // The left and right faces are split in the same direction.
3672  // Rotate the hex around the y-axis to bring left-right to top-bottom.
3673  static const int rot_y[8] = { 1, 5, 6, 2, 0, 4, 7, 3 };
3674  for (int j = 0; j < 8; j++)
3675  {
3676  hv1[j] = hv_orig[rot_y[j]];
3677  }
3678  hv = hv1;
3679  // fsl bit change: a|b|c|d|e|f -> 1-c|1-b|1-f|1-d|1-a|1-e
3680  fsl = ~fsl&63;
3681  fsl = (fsl&8)*4 + (fsl&16) + (fsl&1)*8 + (fsl&4) + (fsl&32)/16 +
3682  (fsl&2)/2;
3683  }
3684  else
3685 #endif
3686  {
3687  // All opposite faces are split in opposite directions.
3688  // Split the hex into 12 tets using the hex center as a vertex in all
3689  // 12 tets.
3690  for (int j = 0; j < 8; j++)
3691  {
3692  const int idx = hv_orig[j];
3693  for (int d = 0; d < 3; d++)
3694  {
3695  pm(d,j) = verts(d,idx);
3696  if (grad) { gd(d,j) = (*grad)(d,idx); }
3697  }
3698  vs(j) = vals(idx);
3699  }
3700  for (int d = 0; d < 3; d++)
3701  {
3702  pm(d,8) = 0.0;
3703  if (grad) { gd(d,8) = 0.0; }
3704  }
3705  vs(8) = 0.0;
3706  for (int j = 0; j < 8; j++)
3707  {
3708  for (int d = 0; d < 3; d++)
3709  {
3710  pm(d,8) += pm(d,j);
3711  if (grad) { gd(d,8) += gd(d,j); }
3712  }
3713  vs(8) += vs(j);
3714  }
3715  for (int d = 0; d < 3; d++)
3716  {
3717  pm(d,8) *= 0.125;
3718  if (grad) { gd(d,8) *= 0.125; }
3719  }
3720  vs(8) *= 0.125;
3721 
3722  typedef Mesh::hex_t hex_t;
3723  for (int j = 0; j < hex_t::NumFaces; j++)
3724  {
3725  int tv[8];
3726  const int *fv = hex_t::FaceVert[j];
3727  const bool diag = fsl&(32>>j);
3728  if (diag == 0)
3729  {
3730  tv[0] = fv[2];
3731  tv[1] = fv[1];
3732  tv[2] = fv[0];
3733  tv[3] = 8;
3734  tv[4] = fv[0];
3735  tv[5] = fv[3];
3736  tv[6] = fv[2];
3737  tv[7] = 8;
3738  }
3739  else
3740  {
3741  tv[0] = fv[1];
3742  tv[1] = fv[0];
3743  tv[2] = fv[3];
3744  tv[3] = 8;
3745  tv[4] = fv[3];
3746  tv[5] = fv[2];
3747  tv[6] = fv[1];
3748  tv[7] = 8;
3749  }
3750  const DenseMatrix *gp = grad ? &gd : NULL;
3751  DrawTetLevelSurf(target, pm, vs, &tv[0], levels, gp);
3752  DrawTetLevelSurf(target, pm, vs, &tv[4], levels, gp);
3753  }
3754 
3755  continue;
3756  }
3757 
3758  // Rotate the hex so that the diagonal edge splitting the bottom face is
3759  // the edge 0-2.
3760  if ((fsl&32) == 0)
3761  {
3762  // Rotate the hex around the z-axis -- left-right becomes front-back.
3763  static const int rot_z[8] = { 3, 0, 1, 2, 7, 4, 5, 6 };
3764  for (int j = 0; j < 8; j++)
3765  {
3766  hv2[j] = hv[rot_z[j]];
3767  }
3768  hv = hv2;
3769  // fsl bit change: a|b|c|d|e|f -> 1-a|e|b|c|d|1-f
3770  fsl = (32-(fsl&32)) + (fsl&2)*8 + (fsl&(16+8+4))/2 + (1-(fsl&1));
3771  }
3772 
3773  // Split the hex into two prisms using the diagonal face 0-2-6-4.
3774  const int pv[2][6] =
3775  {
3776  { hv[0], hv[1], hv[2], hv[4], hv[5], hv[6] },
3777  { hv[2], hv[3], hv[0], hv[6], hv[7], hv[4] }
3778  };
3779  // Choose the shorter diagonal on the face 0-2-6-4.
3780  const double l06 = Distance(&verts(0,hv[0]), &verts(0,hv[6]), 3);
3781  const double l24 = Distance(&verts(0,hv[2]), &verts(0,hv[4]), 3);
3782  const bool diag = (l06 > 1.01*l24);
3783  const int fs1 = (fsl&(16+8))/4 + !diag; // a|b|c|d|e|f -> b|c|1-diag
3784  const int fs2 = (fsl&(4+2)) + diag; // a|b|c|d|e|f -> d|e|diag
3785  DrawRefinedWedgeLevelSurf(target, verts, vals, pv[0], 1, fs1, grad);
3786  DrawRefinedWedgeLevelSurf(target, verts, vals, pv[1], 1, fs2, grad);
3787  }
3788 #endif
3789 }
3790 
3792 {
3793  static const int ident[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
3794 
3795  Vector vals;
3796  DenseMatrix pointmat, grad;
3797  Array<int> vertices;
3798 
3799  lsurf_buf.clear();
3800  if (drawlsurf == 0 || mesh->Dimension() != 3)
3801  {
3802  // Create empty list
3803  return;
3804  }
3805 
3807 
3808  levels.SetSize(nlevels);
3809  for (int l = 0; l < nlevels; l++)
3810  {
3811  double lvl = ((double)(50*l+drawlsurf) / (nlevels*50));
3812  levels[l] = ULogVal(lvl);
3813  }
3814 
3815  // For every quad face, choose the shorter diagonal to split the quad into
3816  // two triangles. Elements adjacent to that quad face (wedge or hex) will use
3817  // the same diagonal when subdividing the element.
3818  Array<bool> quad_diag;
3819  if (mesh->HasGeometry(Geometry::SQUARE))
3820  {
3821  quad_diag.SetSize(mesh->GetNFaces());
3822  for (int fi = 0; fi < mesh->GetNFaces(); fi++)
3823  {
3824  const Element *face = mesh->GetFace(fi);
3825  if (face->GetType() != Element::QUADRILATERAL) { continue; }
3826  ElementTransformation *T = mesh->GetFaceTransformation(fi);
3827  T->Transform(*Geometries.GetVertices(Geometry::SQUARE), pointmat);
3828  const double l02 = Distance(&pointmat(0,0), &pointmat(0,2), 3);
3829  const double l13 = Distance(&pointmat(0,1), &pointmat(0,3), 3);
3830  quad_diag[fi] = (l02 > 1.01*l13);
3831  }
3832  }
3833 
3834  Array<int> faces, ofaces;
3835 
3836  if (shading != 2)
3837  {
3838  for (int ie = 0; ie < mesh->GetNE(); ie++)
3839  {
3840  mesh->GetPointMatrix(ie, pointmat);
3841  mesh->GetElementVertices(ie, vertices);
3842  vals.SetSize(vertices.Size());
3843  for (int j = 0; j < vertices.Size(); j++)
3844  {
3845  vals(j) = (*sol)(vertices[j]);
3846  }
3847 
3848  switch (mesh->GetElementType(ie))
3849  {
3850  case Element::TETRAHEDRON:
3851  DrawTetLevelSurf(lsurf_buf, pointmat, vals, ident, levels);
3852  break;
3853  case Element::PYRAMID:
3854  {
3855  mesh->GetElementFaces(ie, faces, ofaces);
3856  const int fs = GetPyramidFaceSplits(quad_diag, faces, ofaces);
3857  DrawRefinedPyramidLevelSurf(lsurf_buf, pointmat, vals, ident, 1, fs);
3858  }
3859  case Element::WEDGE:
3860  {
3861  mesh->GetElementFaces(ie, faces, ofaces);
3862  const int fs = GetWedgeFaceSplits(quad_diag, faces, ofaces);
3863  DrawRefinedWedgeLevelSurf(lsurf_buf, pointmat, vals, ident, 1, fs);
3864  }
3865  break;
3866  case Element::HEXAHEDRON:
3867  {
3868  mesh->GetElementFaces(ie, faces, ofaces);
3869  const int fs = GetHexFaceSplits(quad_diag, faces, ofaces);
3870  DrawRefinedHexLevelSurf(lsurf_buf, pointmat, vals, ident, 1, fs);
3871  }
3872  break;
3873  default:
3874  MFEM_ABORT("Unrecognized 3D element type \""
3875  << mesh->GetElementType(ie) << "\"");
3876  }
3877  }
3878  }
3879  else // shading == 2
3880  {
3881  RefinedGeometry *RefG;
3882 #define GLVIS_SMOOTH_LEVELSURF_NORMALS
3883 #ifdef GLVIS_SMOOTH_LEVELSURF_NORMALS
3884  const DenseMatrix *gp = &grad;
3885 #else
3886  const DenseMatrix *gp = NULL;
3887 #endif
3888 
3889  for (int ie = 0; ie < mesh->GetNE(); ie++)
3890  {
3891  const Geometry::Type geom = mesh->GetElementBaseGeometry(ie);
3892 
3893  RefG = GLVisGeometryRefiner.Refine(geom, TimesToRefine);
3894  GridF->GetValues(ie, RefG->RefPts, vals, pointmat);
3895 #ifdef GLVIS_SMOOTH_LEVELSURF_NORMALS
3896  GridF->GetGradients(ie, RefG->RefPts, grad);
3897 #endif
3898 
3899  Array<int> &RG = RefG->RefGeoms;
3900  const int nv = mesh->GetElement(ie)->GetNVertices();
3901  const int nre = RG.Size()/nv;
3902 
3903  if (geom == Geometry::TETRAHEDRON)
3904  {
3905  for (int k = 0; k < nre; k++)
3906  {
3907  DrawTetLevelSurf(lsurf_buf, pointmat, vals, &RG[nv*k], levels, gp);
3908  }
3909  }
3910  else if (geom == Geometry::PYRAMID)
3911  {
3912  mesh->GetElementFaces(ie, faces, ofaces);
3913  const int fs = GetPyramidFaceSplits(quad_diag, faces, ofaces);
3914  DrawRefinedPyramidLevelSurf(lsurf_buf, pointmat, vals, RG, nre, fs, gp);
3915  }
3916  else if (geom == Geometry::PRISM)
3917  {
3918  mesh->GetElementFaces(ie, faces, ofaces);
3919  const int fs = GetWedgeFaceSplits(quad_diag, faces, ofaces);
3920  DrawRefinedWedgeLevelSurf(lsurf_buf, pointmat, vals, RG, nre, fs, gp);
3921  }
3922  else if (geom == Geometry::CUBE)
3923  {
3924  mesh->GetElementFaces(ie, faces, ofaces);
3925  const int fs = GetHexFaceSplits(quad_diag, faces, ofaces);
3926  DrawRefinedHexLevelSurf(lsurf_buf, pointmat, vals, RG, nre, fs, gp);
3927  }
3928  }
3929  }
3930 
3931  updated_bufs.emplace_back(&lsurf_buf);
3932 
3933 #ifdef GLVIS_DEBUG
3934  cout << "VisualizationSceneSolution3d::PrepareLevelSurf() : "
3935  << triangle_counter << " triangles + " << quad_counter
3936  << " quads used" << endl;
3937 #endif
3938 }
3939 
3941 {
3942  if (colorbar)
3943  {
3944  Array<double>* cb_level = nullptr,
3945  * cb_levels = nullptr;
3946  if (drawlsurf) { cb_levels = &levels; }
3947  if (drawmesh == 2 || cp_drawmesh >= 2) { cb_level = &level; }
3948  PrepareColorBar(minv, maxv, cb_level, cb_levels);
3949  }
3951  gl3::RenderParams params = GetMeshDrawParams();
3952  params.use_clip_plane = cplane;
3953  double* cp_eqn = CuttingPlane->Equation();
3954  params.clip_plane_eqn = {cp_eqn[0], cp_eqn[1], cp_eqn[2], cp_eqn[3]};
3955  params.contains_translucent = matAlpha < 1.0;
3956 
3957  if (drawlsurf)
3958  {
3959  scene.queue.emplace_back(params, &lsurf_buf);
3960  }
3961  if (drawelems)
3962  {
3963  scene.queue.emplace_back(params, &disp_buf);
3964  }
3965  if (cplane && cp_drawelems)
3966  {
3967  params.use_clip_plane = false;
3968  scene.queue.emplace_back(params, &cplane_buf);
3969  params.use_clip_plane = true;
3970  }
3971  params.contains_translucent = false;
3972  // draw orderings -- color modes
3973  if (draworder == 1)
3974  {
3975  scene.queue.emplace_back(params, &order_noarrow_buf);
3976  }
3977  else if (draworder == 2)
3978  {
3979  scene.queue.emplace_back(params, &order_buf);
3980  }
3982  // everything below will be drawn in "black"
3983  params.static_color = GetLineColor();
3984  params.num_pt_lights = 0;
3985  if (drawmesh)
3986  {
3987  scene.queue.emplace_back(params, &line_buf);
3988  }
3989  if (cp_drawmesh)
3990  {
3991  params.use_clip_plane = false;
3992  scene.queue.emplace_back(params, &cplines_buf);
3993  }
3994  // draw orderings -- "black" modes
3995  if (draworder == 3)
3996  {
3997  scene.queue.emplace_back(params, &order_noarrow_buf);
3998  }
3999  else if (draworder == 4)
4000  {
4001  scene.queue.emplace_back(params, &order_buf);
4002  }
4003  return scene;
4004 }
4005 
4007 {
4008  string name = "GLVis_scene_000";
4009 
4010  glTF_Builder bld(name);
4011 
4012  auto palette_mat = AddPaletteMaterial(bld);
4013  auto black_mat = AddBlackMaterial(bld);
4014  auto buf = bld.addBuffer("buffer");
4015  if (drawelems) { glTF_ExportElements(bld, buf, palette_mat, disp_buf); }
4016  if (drawmesh) { glTF_ExportMesh(bld, buf, black_mat, line_buf); }
4017  if (cplane && cp_drawelems)
4018  {
4019  auto cp_elems_node = AddModelNode(bld, "CP Elements");
4020  auto cp_elems_mesh = bld.addMesh("CP Elements Mesh");
4021  bld.addNodeMesh(cp_elems_node, cp_elems_mesh);
4022 
4023  int ntria = AddTriangles(
4024  bld,
4025  cp_elems_mesh,
4026  buf,
4027  palette_mat,
4028  cplane_buf);
4029  if (ntria == 0)
4030  {
4031  cout << "glTF export: no cp elements found to export!" << endl;
4032  }
4033  }
4034  if (cp_drawmesh)
4035  {
4036  auto cp_lines_node = AddModelNode(bld, "CP Lines");
4037  auto cp_lines_mesh = bld.addMesh("CP Lines Mesh");
4038  bld.addNodeMesh(cp_lines_node, cp_lines_mesh);
4039 
4040  int nlines = AddLines(
4041  bld,
4042  cp_lines_mesh,
4043  buf,
4044  black_mat,
4045  cplines_buf);
4046  if (nlines == 0)
4047  {
4048  cout << "glTF export: no cp mesh/level lines found to export!" << endl;
4049  }
4050  }
4051  if (drawlsurf)
4052  {
4053  auto lsurf_node = AddModelNode(bld, "Level Surface");
4054  auto lsurf_mesh = bld.addMesh("Level Surface Mesh");
4055  bld.addNodeMesh(lsurf_node, lsurf_mesh);
4056 
4057  int ntria = AddTriangles(
4058  bld,
4059  lsurf_mesh,
4060  buf,
4061  palette_mat,
4062  lsurf_buf);
4063  if (ntria == 0)
4064  {
4065  cout << "glTF export: no level surface elements found to export!"
4066  << endl;
4067  }
4068  }
4069  if (drawaxes) { glTF_ExportBox(bld, buf, black_mat); }
4070  bld.writeFile();
4071 
4072  cout << "Exported glTF -> " << name << ".gltf" << endl;
4073 }
double cut_lambda
Amount of face cutting with keys Ctrl-F3/F4 (0: no cut, 1: cut to edges)
Definition: openglvis.hpp:187
void SendExposeEvent()
Send expose event. In our case MyReshape is executed and Draw after it.
Definition: aux_vis.cpp:346
bool cut_updated
Have the reference geometries been updated for the cut?
Definition: openglvis.hpp:189
thread_local int quad_counter
void KeyvPressed()
Definition: vsvector.cpp:141
thread_local GeometryRefiner GLVisGeometryRefiner
Definition: glvis.cpp:71
static int GetWedgeFaceSplits(const Array< bool > &quad_diag, const Array< int > &faces, const Array< int > &ofaces)
void glVertex3d(double x, double y, double z)
Definition: types.hpp:332
float GetLineWidth()
Definition: aux_vis.cpp:1609
int Normalize(double v[])
Definition: geom_utils.hpp:38
virtual void FindNewBox(bool prepare)
thread_local Array< int > cut_TriGeoms
void DrawRefinedPyramidLevelSurf(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vals, const int *RG, const int np, const int face_splits, const DenseMatrix *grad=NULL)
void LiftRefinedSurf(int n, DenseMatrix &pointmat, Vector &values, int *RG)
thread_local SdlWindow * wnd
Definition: aux_vis.cpp:50
static int GetPyramidFaceSplits(const Array< bool > &quad_diag, const Array< int > &faces, const Array< int > &ofaces)
float GetLineWidthMS()
Definition: aux_vis.cpp:1614
void SetLineWidthMS(float width_ms)
Definition: aux_vis.cpp:1599
thread_local IntegrationRule cut_QuadPts
void glEnd()
Definition: types.hpp:309
virtual void ToggleAttributes(Array< int > &attr_list)
void GetFaceNormals(const int FaceNo, const int side, const IntegrationRule &ir, DenseMatrix &normals)
virtual gl3::SceneInfo GetSceneObjs()
Definition: vsdata.cpp:984
void addLine(const Vert &v1, const Vert &v2)
Definition: types.hpp:672
virtual void UpdateValueRange(bool prepare)
static Vertex create(double *d)
Definition: types.hpp:207
void ComputeBdrAttrCenter()
Compute the center of gravity for each boundary attribute.
Definition: vsdata.cpp:1612
void glNormal3dv(const double *d)
Definition: types.hpp:407
Definition: vsdata.hpp:25
buffer_id addBuffer(const std::string &bufferName)
Definition: gltf.cpp:24
void DrawRefinedSurfLevelLines(int n, DenseMatrix &pointmat, Vector &values, Array< int > &RefGeoms)
void glBegin(GLenum e)
Definition: types.hpp:295
int Compute3DUnitNormal(const double p1[], const double p2[], const double p3[], double nor[])
Definition: geom_utils.hpp:101
virtual void PrepareOrderingCurve1(gl3::GlDrawable &buf, bool arrows, bool color)
void DrawRefinedWedgeLevelSurf(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vals, const int *RG, const int np, const int face_splits, const DenseMatrix *grad=NULL)
void DrawRefinedSurfEdges(int n, DenseMatrix &pointmat, Vector &values, Array< int > &RefEdges, int part=-1)
void CutReferenceElements(int TimesToRefine, double lambda)
int GetMultisample()
Definition: aux_vis.cpp:1573
thread_local VisualizationSceneSolution3d * vssol3d
double shrinkmat
Shrink factor with respect to the element (material) attributes centers.
Definition: vsdata.hpp:136
thread_local VisualizationSceneScalarData * vs
Definition: glvis.cpp:67
void glNormal3d(double nx, double ny, double nz)
Definition: types.hpp:401
GlBuilder createBuilder()
Definition: types.hpp:731
thread_local Array< int > cut_QuadGeoms
static int GetHexFaceSplits(const Array< bool > &quad_diag, const Array< int > &faces, const Array< int > &ofaces)
mesh_id addMesh(const std::string &meshName)
Definition: gltf.cpp:322
double InnerProd(const double a[], const double b[])
Definition: geom_utils.hpp:26
void DrawTetLevelSurf(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vals, const int *ind, const Array< double > &levels, const DenseMatrix *grad=NULL)
virtual void SetShading(int, bool)
void DrawRefinedSurf(int n, double *points, int elem, int func, int part=-1)
void SetLineWidth(float width)
Definition: aux_vis.cpp:1590
thread_local int triangle_counter
virtual gl3::SceneInfo GetSceneObjs()
void CutRefinedFace(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vert_dist, const Vector &vals, const Geometry::Type geom, const int *faces, int num_faces)
Crude fixed-function OpenGL emulation helper.
Definition: types.hpp:261
int writeFile()
Definition: gltf.cpp:472
void KeyiPressed()
Definition: vssolution.cpp:317
void addNodeMesh(node_id node, mesh_id mesh)
Definition: gltf.cpp:433
void CutRefinedElement(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vert_dist, const Vector &vals, const Geometry::Type geom, const int *elems, int num_elems, int func)
void KeyIPressed()
Definition: vssolution.cpp:323
void ToggleMagicKey()
void DrawRefinedHexLevelSurf(gl3::GlDrawable &target, const DenseMatrix &verts, const Vector &vals, const int *RG, const int nh, const int face_splits, const DenseMatrix *grad=NULL)
virtual void PrepareOrderingCurve()
void KeyUPressed()
Definition: vsvector.cpp:203
thread_local IntegrationRule cut_TriPts
virtual void SetRefineFactors(int, int)
void glVertex3dv(const double *d)
Definition: types.hpp:396
bool contains_translucent
Definition: renderer.hpp:55
void KeyVPressed()
Definition: vsvector.cpp:147
void KeyuPressed()
Definition: vsvector.cpp:158
std::array< float, 4 > static_color
Definition: renderer.hpp:48
virtual std::string GetHelpString() const
void setOnKeyDown(int key, Delegate func)
Definition: sdl.hpp:188
RenderQueue queue
Definition: renderer.hpp:63
void ComputeElemAttrCenter()
Compute the center of gravity for each element attribute.
Definition: vsdata.cpp:1641
virtual void FindNewValueRange(bool prepare)
Material mesh_material
Definition: renderer.hpp:44
std::array< double, 4 > clip_plane_eqn
Definition: renderer.hpp:52
void DoAutoscale(bool prepare)
Definition: vsdata.cpp:48
void NewMeshAndSolution(Mesh *new_m, Vector *new_sol, GridFunction *new_u=NULL)
const Material BLK_MAT
Definition: openglvis.hpp:78