LCOV - code coverage report
Current view: top level - ugbase/lib_grid/algorithms/remeshing - delaunay_triangulation.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 239 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Sebastian Reiter
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include <algorithm>
      34              : #include "delaunay_triangulation.h"
      35              : #include "lib_grid/algorithms/grid_generation/triangle_fill_sweep_line.h"
      36              : #include "lib_grid/algorithms/subset_util.h"
      37              : #include "lib_grid/algorithms/polychain_util.h"
      38              : //temporary
      39              : #include "lib_grid/file_io/file_io.h"
      40              : 
      41              : using namespace std;
      42              : 
      43              : namespace ug{
      44              : 
      45              : ////////////////////////////////////////////////////////////////////////////////
      46              : class DelaunayDebugSaver
      47              : {
      48              :         public:
      49            0 :                 static DelaunayDebugSaver& inst()
      50              :                 {
      51            0 :                         static DelaunayDebugSaver dds;
      52            0 :                         return dds;
      53              :                 }
      54              : 
      55              :                 void save(Grid& g, const char* msg)
      56              :                 {
      57              :                         if(m_saveEnabled){
      58              :                                 std::stringstream ss;
      59              :                                 ss << "dbg" << m_counter++ << ".ugx";
      60              : 
      61              :                                 UG_LOG(msg << ": debug-save to " << ss.str() << std::endl);
      62              :                                 SubsetHandler sh(g);
      63              :                                 AssignGridToSubset(g, sh, 0);
      64              :                                 SaveGridToFile(g, sh, ss.str().c_str());
      65              :                         }
      66              :                 }
      67              : 
      68              :                 template <class TAAPos>
      69            0 :                 void save(Grid& g, const char* msg, DelaunayInfo<TAAPos>& dinfo)
      70              :                 {
      71            0 :                         if(m_saveEnabled){
      72            0 :                                 std::stringstream ss;
      73            0 :                                 ss << "dbg" << m_counter++ << ".ugx";
      74              : 
      75            0 :                                 UG_LOG(msg << ": debug-save to " << ss.str() << std::endl);
      76            0 :                                 SubsetHandler sh(g);
      77              : 
      78              :                                 for(VertexIterator iter = g.begin<Vertex>();
      79            0 :                                         iter != g.end<Vertex>(); ++iter)
      80              :                                 {
      81            0 :                                         sh.assign_subset(*iter, dinfo.mark(*iter));
      82              :                                 }
      83              : 
      84              :                                 for(EdgeIterator iter = g.begin<Edge>();
      85            0 :                                         iter != g.end<Edge>(); ++iter)
      86              :                                 {
      87            0 :                                         sh.assign_subset(*iter, dinfo.mark(*iter));
      88              :                                 }
      89              : 
      90              :                                 for(FaceIterator iter = g.begin<Face>();
      91            0 :                                         iter != g.end<Face>(); ++iter)
      92              :                                 {
      93            0 :                                         sh.assign_subset(*iter, dinfo.mark(*iter));
      94              :                                 }
      95              : 
      96            0 :                                 sh.subset_info(0).name = "none";
      97            0 :                                 sh.subset_info(1).name = "inner";
      98            0 :                                 sh.subset_info(2).name = "new-inner";
      99            0 :                                 sh.subset_info(3).name = "segment";
     100            0 :                                 sh.subset_info(4).name = "new-segment";
     101            0 :                                 sh.subset_info(5).name = "dart";
     102            0 :                                 sh.subset_info(6).name = "shell";
     103              : 
     104            0 :                                 AssignSubsetColors(sh);
     105            0 :                                 SaveGridToFile(g, sh, ss.str().c_str());
     106            0 :                         }
     107            0 :                 }
     108              : 
     109            0 :                 void enable_save(bool enable = true)    {m_saveEnabled = enable;}
     110              : 
     111              :         private:
     112            0 :                 DelaunayDebugSaver() : m_saveEnabled(false), m_counter(0) {}
     113              : 
     114              :                 bool    m_saveEnabled;
     115              :                 int             m_counter;
     116              : };
     117              : 
     118              : static void EnableDelaunayDebugSave(bool enable = true)
     119              : {
     120            0 :         DelaunayDebugSaver::inst().enable_save(enable);
     121              : }
     122              : 
     123              : // static void DelaunayDebugSave(Grid& g, const char* msg)
     124              : // {
     125              : //      DelaunayDebugSaver::inst().save(g, msg);
     126              : // }
     127              : 
     128              : template <class TAAPos>
     129              : static void DelaunayDebugSave(Grid& g, const char* msg, DelaunayInfo<TAAPos>& dinfo)
     130              : {
     131            0 :         DelaunayDebugSaver::inst().save(g, msg, dinfo);
     132            0 : }
     133              : 
     134              : 
     135              : 
     136              : ////////////////////////////////////////////////////////////////////////////////
     137              : template <class TAAPos>
     138            0 : bool MakeDelaunay(DelaunayInfo<TAAPos>& info)
     139              : {
     140              :         using namespace std;
     141              :         typedef typename TAAPos::ValueType vector_t;
     142              : 
     143              :         Grid& grid = info.grid();
     144              :         Face* nbrFaces[2];
     145              :         vector<Edge*> edges;
     146              : 
     147              :         TAAPos& aaPos = info.position_accessor();
     148              : 
     149            0 :         while(info.candidates_left()){
     150            0 :                 Edge* e = info.pop_candidate();
     151              : 
     152              :         //      we only perform swaps on regular manifolds.
     153            0 :                 if(GetAssociatedFaces(nbrFaces, grid, e, 2) == 2){
     154              :                 //      make sure that both neighbors are triangles
     155            0 :                         if(nbrFaces[0]->num_vertices() != 3 || nbrFaces[1]->num_vertices() != 3)
     156            0 :                                 continue;
     157              : 
     158            0 :                         Vertex* conVrt0 = GetConnectedVertex(e, nbrFaces[0]);
     159            0 :                         Vertex* conVrt1 = GetConnectedVertex(e, nbrFaces[1]);
     160              : 
     161            0 :                         vector_t& v0 = aaPos[e->vertex(0)];
     162            0 :                         vector_t& v1 = aaPos[e->vertex(1)];
     163              :                         vector_t& v2 = aaPos[conVrt0];
     164              :                         vector_t& v3 = aaPos[conVrt1];
     165              : 
     166              :                         vector_t cc1, cc2;
     167              : 
     168            0 :                         bool cc1_ok = TriangleCircumcenter(cc1, v0, v1, v2);
     169            0 :                         bool cc2_ok = TriangleCircumcenter(cc2, v1, v0, v3);
     170              : 
     171            0 :                         number r1Sq = VecDistanceSq(cc1, v0);
     172            0 :                         number r2Sq = VecDistanceSq(cc2, v0);
     173              : 
     174              :                 //      for stability reasons, we're checking against the smaller circle
     175            0 :                         if(cc1_ok){
     176            0 :                                 if(cc2_ok){
     177            0 :                                         if(r1Sq <= r2Sq){
     178            0 :                                                 if(r1Sq <= VecDistanceSq(cc1, v3))
     179            0 :                                                         continue; //the edge is fine
     180              :                                         }
     181              :                                         else{
     182            0 :                                                 if(r2Sq <= VecDistanceSq(cc2, v2))
     183            0 :                                                         continue; //the edge is fine
     184              :                                         }
     185              :                                 }
     186              :                                 else{
     187            0 :                                         if(r1Sq <= VecDistanceSq(cc1, v3))
     188            0 :                                                 continue; //the edge is fine
     189              :                                 }
     190              :                         }
     191            0 :                         else if(cc2_ok){
     192            0 :                                 if(r2Sq <= VecDistanceSq(cc2, v2))
     193            0 :                                         continue; //the edge is fine
     194              :                         }
     195              :                         else{
     196              :                                 UG_LOG("TriangleCircumcenter failed! Excpect non-delaunay output!\n");
     197              :                                 UG_LOG("  This is most likely caused by two degenerated triangles which "
     198              :                                                 "share an edge.\n");
     199            0 :                                 UG_LOG("edge center: " << CalculateCenter(e, aaPos) << endl);
     200            0 :                                 return false;
     201              :                                 //continue;
     202              :                         }
     203              : 
     204              : //                      UG_LOG("  swap-it!\n");
     205              : 
     206              :                 //      before swapping, we have to make sure, that the generated triangle
     207              :                 //      won't be degenerated.
     208              :                 //      this is a costly operation... we check whether both circumcenters
     209              :                 //      of the new triangles can be calculated...
     210              : /*
     211              :                         if(!(TriangleCircumcenter(cc1, v0, v2, v3)
     212              :                                  && TriangleCircumcenter(cc2, v2, v1, v3)))
     213              :                         {
     214              :                         //      we have to abort the swap
     215              :                                 continue;
     216              :                         }
     217              : */
     218              :                 //      ok - everything is fine. Now swap the edge
     219            0 :                         Edge* eNew = SwapEdge(grid,  e);
     220              : 
     221            0 :                         if(!eNew){
     222              :                                 UG_LOG("An edge-swap failed. Expect degenerated or flipped triangles "
     223              :                                                 "and a non-delaunay output!\n");
     224            0 :                                 UG_LOG("edge center: " << CalculateCenter(e, aaPos) << endl);
     225            0 :                                 return false;
     226              :                                 //continue;
     227              :                         }
     228              : 
     229              :                         e = eNew;
     230              : 
     231              :                         //DelaunayDebugSave(grid, "Edge Swapped", info);
     232              : 
     233              :                 //      all edges of associated triangles are candidates again (except e)
     234            0 :                         GetAssociatedFaces(nbrFaces, grid, e, 2);
     235            0 :                         for(size_t i = 0; i < 2; ++i){
     236            0 :                                 CollectAssociated(edges, grid, nbrFaces[i]);
     237            0 :                                 for(size_t j = 0; j < edges.size(); ++j){
     238            0 :                                         if((edges[j] != e) && !(info.is_segment(edges[j])
     239            0 :                                                                                     || info.is_candidate(edges[j])))
     240              :                                         {
     241            0 :                                                 info.push_candidate(edges[j]);
     242              :                                         }
     243              :                                 }
     244              :                         }
     245              :                 }
     246              :         }
     247              :         return true;
     248            0 : }
     249              : 
     250              : 
     251              : static bool
     252            0 : DelaunayLineLineIntersection(vector3& vOut,
     253              :                                                          const vector3& lineFrom, const vector3& lineTo,
     254              :                                                          const vector3& edgeVrt1, const vector3& edgeVrt2,
     255              :                                                          vector3 areaNormal,
     256              :                                                          number smallsq = SMALL_SQ)
     257              : {
     258              :         number t;
     259              : 
     260              :         vector3 lineDir, edgeDir, planeNormal;
     261              :         VecSubtract(lineDir, lineTo, lineFrom);
     262            0 :         VecNormalize(lineDir, lineDir);
     263              :         VecSubtract(edgeDir, edgeVrt2, edgeVrt1);
     264            0 :         number threshold = smallsq * VecLengthSq(edgeDir);
     265            0 :         VecNormalize(edgeDir, edgeDir);
     266            0 :         VecCross(planeNormal, edgeDir, areaNormal);
     267            0 :         if(RayPlaneIntersection(vOut, t, lineFrom, lineDir, edgeVrt1, planeNormal)){
     268            0 :                 if(t > 0 && (VecDistanceSq(lineFrom, vOut) < VecDistanceSq(lineFrom, lineTo) + threshold)){
     269            0 :                         return true;
     270              :                 }
     271              :         }
     272              :         return false;
     273              : }
     274              : 
     275              : 
     276              : 
     277              : template <class TAAPos>
     278            0 : bool QualityGridGeneration(Grid& grid, DelaunayInfo<TAAPos>& info,
     279              :                                                    number minAngle, int maxSteps)
     280              : {
     281              :         EnableDelaunayDebugSave(false);
     282            0 :         minAngle = max<number>(minAngle, 0);
     283            0 :         minAngle = min<number>(minAngle, 60);
     284              : 
     285              :         // maxSteps = 20;
     286              :         // UG_LOG("DEBUG: Setting maxSteps to " << maxSteps << "\n");
     287              : 
     288              :         using namespace std;
     289              : 
     290              :         typedef typename TAAPos::ValueType vector_t;
     291              :         typedef DelaunayInfo<TAAPos> DI;
     292              : 
     293              :         TAAPos aaPos = info.position_accessor();
     294              : 
     295              :         int stepCount = 0;
     296              : 
     297              : //      helper to collect neighbors
     298              :         Face* nbrFaces[2];
     299              :         queue<Vertex*> qvrts; // used during splits
     300              :         vector<Vertex*> vrts;
     301              :         vector<Edge*> edges;
     302              :         vector<Edge*> closeEdges; // used during splits
     303              :         vector<Face*> faces;
     304              : 
     305            0 :         MakeDelaunay(info);
     306              : 
     307            0 :         if(minAngle > 0 && maxSteps != 0){
     308            0 :                 const number offCenterThresholdAngle = 1.1 * minAngle;
     309            0 :                 const number offCenterATan = atan(deg_to_rad(0.5 * offCenterThresholdAngle));
     310              :                 // UG_LOG("off-center atan: " << offCenterATan << endl);
     311              : 
     312            0 :                 info.enable_face_classification(minAngle);
     313              : 
     314              :         //      while there are faces left which have to be improved
     315            0 :                 while(info.classified_faces_left()){
     316              :                         /*if(stepCount == 488){
     317              :                                 EnableDelaunayDebugSave();
     318              :                         }*/
     319              : 
     320            0 :                         Face* f = info.pop_classified_face();
     321            0 :                         if(f->num_vertices() != 3)
     322            0 :                                 continue;
     323              : 
     324              :                 //todo: the normal is only required for 3d-types. indeed this will crash
     325              :                 //              for 2d. This should be moved to a Ray-Line_Intersection3d test.
     326              :                         vector3 faceNormal;
     327            0 :                         CalculateNormal(faceNormal, f, aaPos);
     328              :                 //      we can't operate on degenerated faces. Let's hope, that this face
     329              :                 //      will improve during improvement of some non-degenerated face.
     330            0 :                         if(VecLengthSq(faceNormal) < SMALL)
     331            0 :                                 return false;
     332              : 
     333            0 :                         vector_t faceCenter = CalculateCenter(f, aaPos);
     334              : 
     335              :                 //      calculate triangle-circumcenter
     336            0 :                         vector_t vpos[3] = {aaPos[f->vertex(0)], aaPos[f->vertex(1)], aaPos[f->vertex(2)]};
     337              :                         vector_t cc;
     338              : 
     339            0 :                         if(!TriangleCircumcenter(cc, vpos[0], vpos[1], vpos[2])){
     340              :                                 UG_LOG("Couldn't calculate triangle-circumcenter. Expect unexpected results!\n");
     341            0 :                                 UG_LOG("triangle: " << faceCenter << "\n");
     342              :                                 //SaveGridToFile(grid, "delaunay_debug.ugx");
     343              :                                 return false;
     344              :                                 //continue;
     345              :                         }
     346              : 
     347              :                 //      Test whether an off-center would be more appropriate ('Alper Üngörs Off-Centers')
     348            0 :                         if(offCenterATan > 0)
     349              :                         {
     350            0 :                                 number edgeLenSq[3] = {VecDistanceSq(vpos[0], vpos[1]),
     351            0 :                                                                            VecDistanceSq(vpos[1], vpos[2]),
     352            0 :                                                                            VecDistanceSq(vpos[2], vpos[0])};
     353              :                                 size_t shortestEdge = 0;
     354            0 :                                 for(size_t iedge = 1; iedge < 3; ++iedge){
     355            0 :                                         if(edgeLenSq[iedge] < edgeLenSq[shortestEdge])
     356              :                                                 shortestEdge = iedge;
     357              :                                 }
     358              : 
     359            0 :                                 size_t vrtInd[2] = {shortestEdge, (shortestEdge + 1) % 3};
     360            0 :                                 vector_t dir[2];
     361            0 :                                 for(size_t ivrt = 0; ivrt < 2 ; ++ivrt){
     362            0 :                                         VecSubtract(dir[ivrt], vpos[vrtInd[ivrt]], cc);
     363              :                                 }
     364              : 
     365            0 :                                 number angle = rad_to_deg(VecAngle(dir[0], dir[1]));
     366              : 
     367            0 :                                 if(angle < offCenterThresholdAngle){
     368              :                                         vector_t base;
     369              :                                         VecScaleAdd(base, 0.5, vpos[vrtInd[0]], 0.5, vpos[vrtInd[1]]);
     370              :                                         vector_t ndir;
     371              :                                         VecSubtract(ndir, cc, base);
     372            0 :                                         VecNormalize(ndir, ndir);
     373            0 :                                         VecScale(ndir, ndir, 0.5 * sqrt(edgeLenSq[shortestEdge]) / offCenterATan);
     374              :                                         // UG_LOG("Adjusting cc from: " << cc << " to: ");
     375              :                                         VecAdd(cc, base, ndir);
     376              :                                         // UG_LOG(cc << endl);
     377              :                                 }
     378              :                         }
     379              : 
     380              :                 //      locate the triangle which contains cc. Do this by traversing edges
     381              :                 //      as required. Note that since the delaunay property holds, we're only
     382              :                 //      traversing edges in a circle, which does not contain any vertices.
     383              :                         Edge* lastTraversedEdge = NULL;
     384              :                         Face* curFace = f;
     385              :                         //vector_t startPos = CalculateCenter(f, aaPos);
     386              :                         vector_t rayDir;
     387              :                         VecSubtract(rayDir, cc, faceCenter);
     388            0 :                         Vertex* pointInserted = NULL;
     389              : 
     390              :                         // UG_LOG("curFace: " << faceCenter << "\n");
     391            0 :                         while(pointInserted == NULL){
     392              :                                 //UG_LOG("curTri: " << CalculateCenter(curFace, aaPos) << "\n");
     393              :                         //      to make things as robust as possible, we'll always intersect the
     394              :                         //      same line with each edge
     395              :                                 Edge* nextEdge = NULL;
     396              :                                 bool split = false;
     397              : 
     398              :                                 CollectAssociated(edges, grid, curFace);
     399            0 :                                 for(size_t i = 0; i < edges.size(); ++i){
     400            0 :                                         Edge* e = edges[i];
     401            0 :                                         if(e == lastTraversedEdge)
     402            0 :                                                 continue;
     403              : 
     404              :                                         vector_t a;
     405            0 :                                         if(DelaunayLineLineIntersection(a, faceCenter, cc,
     406            0 :                                                         aaPos[e->vertex(0)], aaPos[e->vertex(1)], faceNormal, SMALL_SQ))
     407              :                                         {
     408              :                                         //      this edge will be traversed next.
     409              :                                                 nextEdge = e;
     410            0 :                                                 number threshold =      VecDistanceSq(faceCenter, cc)
     411            0 :                                                                                         - SMALL_SQ * EdgeLengthSq(e, aaPos);
     412              : 
     413              :                                         //      check whether e has to be split, to avoid bad aspect ratios
     414            0 :                                                 split = (VecDistanceSq(faceCenter, a) > threshold);
     415            0 :                                                 break;
     416              :                                         }/*
     417              :                                         // This else-condition is not necessary - if they are parallel, that's not a problem...
     418              :                                         else{
     419              :                                                 UG_LOG("Ray-Plane intersection failed in step " << stepCount << "... aborting.\n");
     420              :                                                 UG_LOG("  curTri: " << CalculateCenter(curFace, aaPos)
     421              :                                                                 << ", curEdge: " << CalculateCenter(e, aaPos) << endl);
     422              :                                                 UG_LOG("  face-normal: " << faceNormal << ", plane-normal: " << planeNormal
     423              :                                                                 << "  ray-dir: " << rayDir << endl);
     424              :                                                 return false;
     425              :                                         }*/
     426              :                                 }
     427              : 
     428            0 :                                 if(nextEdge){
     429              :                                 //      check whether the edge has to be splitted
     430              :                                         const bool isSegment = info.is_segment(nextEdge);
     431            0 :                                         split |= isSegment;
     432            0 :                                         if(!split){
     433            0 :                                                 int numNbrs = GetAssociatedFaces(nbrFaces, grid, nextEdge, 2);
     434            0 :                                                 if(numNbrs != 2)
     435              :                                                         split = true;
     436              :                                                 else{
     437              :                                                 //      get the next face
     438            0 :                                                         if(nbrFaces[0] == curFace)
     439            0 :                                                                 curFace = nbrFaces[1];
     440              :                                                         else
     441              :                                                                 curFace = nbrFaces[0];
     442              :                                                 //      and set the last traversed edge
     443              :                                                         lastTraversedEdge = nextEdge;
     444              :                                                 }
     445              :                                         }
     446              : 
     447            0 :                                         if(split){
     448            0 :                                                 vector_t center = CalculateCenter(nextEdge, aaPos);
     449              : 
     450            0 :                                                 Vertex* vrt0 = nextEdge->vertex(0);
     451            0 :                                                 Vertex* vrt1 = nextEdge->vertex(1);
     452            0 :                                                 Vertex* edgeVrts[2] = {vrt0, vrt1};
     453            0 :                                                 number radiusSq = VecDistanceSq(center, aaPos[vrt0]);
     454            0 :                                                 number radius = sqrt(radiusSq);
     455            0 :                                                 pointInserted = SplitEdge<RegularVertex>(grid, nextEdge, false);
     456              : 
     457            0 :                                                 if(isSegment){
     458              :                                                 //      depending on the marks of the corners of nextEdge,
     459              :                                                 //      we may have to place the new point at a circular shell
     460              :                                                         int dartInd = -1;
     461            0 :                                                         for(int ivrt = 0; ivrt < 2; ++ivrt){
     462            0 :                                                                 if(info.mark(edgeVrts[ivrt]) == DI::DART){
     463              :                                                                         dartInd = ivrt;
     464              :                                                                         break;
     465              :                                                                 }
     466              :                                                         }
     467            0 :                                                         if(dartInd != -1){
     468            0 :                                                                 Vertex* dartVrt = edgeVrts[dartInd];
     469            0 :                                                                 Vertex* otherVrt = edgeVrts[(dartInd + 1) % 2];
     470              :                                                                 typename DI::Mark m = info.mark(otherVrt);
     471            0 :                                                                 if((m == DI::NEW_SEGMENT) || (m == DI::SHELL)){
     472              :                                                                 //      the new vertex has to be placed on a circular shell!
     473              :                                                                         info.set_mark(pointInserted, DI::SHELL);
     474              :                                                                         number dist = VecDistance(center, aaPos[dartVrt]);
     475              :                                                                         number csCur = 1;
     476              :                                                                         number csNext;
     477              : 
     478            0 :                                                                         if(dist >= 1){
     479              :                                                                                 csNext = 2;
     480            0 :                                                                                 while(csNext < dist){
     481              :                                                                                         csCur = csNext;
     482            0 :                                                                                         csNext *= 2.;
     483              :                                                                                 }
     484              :                                                                         }
     485              :                                                                         else{
     486              :                                                                                 csNext = 0.5;
     487            0 :                                                                                 while(csNext > dist){
     488              :                                                                                         csCur = csNext;
     489            0 :                                                                                         csNext *= 0.5;
     490              :                                                                                 }
     491              :                                                                         }
     492              : 
     493              :                                                                         vector_t dir;
     494              :                                                                         VecSubtract(dir, center, aaPos[dartVrt]);
     495            0 :                                                                         VecNormalize(dir, dir);
     496              : 
     497            0 :                                                                         if(fabs(dist - csCur) < fabs(dist - csNext))
     498              :                                                                                 VecScale(dir, dir, csCur);
     499              :                                                                         else
     500              :                                                                                 VecScale(dir, dir, csNext);
     501              : 
     502              :                                                                         VecAdd(center, aaPos[dartVrt], dir);
     503              :                                                                 
     504              :                                                                 //      we have to adjust the critical radius
     505            0 :                                                                         radiusSq = min(VecDistanceSq(center, aaPos[vrt0]),
     506            0 :                                                                                                    VecDistanceSq(center, aaPos[vrt1]));
     507            0 :                                                                         radius = sqrt(radiusSq);
     508              :                                                                 }
     509              :                                                         }
     510              : 
     511              :                                                         aaPos[pointInserted] = center;
     512              : 
     513              :                                                 //      we have to erase all vertices, which are marked and
     514              :                                                 //      which are closer to the inserted point than the
     515              :                                                 //      radius calculated above.
     516              :                                                 //todo: And which are visible (not hidden by constrained edges)
     517              :                                                         assert(qvrts.empty());
     518              :                                                         qvrts.push(pointInserted);
     519              : 
     520              :                                                         vrts.clear();
     521              :                                                         closeEdges.clear();
     522              : 
     523            0 :                                                         grid.begin_marking();
     524            0 :                                                         while(!qvrts.empty()){
     525            0 :                                                                 Vertex* vrt = qvrts.front();
     526              :                                                                 qvrts.pop();
     527              : 
     528              :                                                         //      collect all edges connected to vrt
     529              :                                                                 CollectAssociated(edges, grid, vrt);
     530              :                                                         //      if the edge is not yet marked, we'll add it to the
     531              :                                                         //      closeEdges list.
     532            0 :                                                                 for(size_t i_edge = 0; i_edge < edges.size(); ++i_edge){
     533            0 :                                                                         Edge* e = edges[i_edge];
     534            0 :                                                                         if(!grid.is_marked(e)){
     535              :                                                                         //      check whether the edge intersects the critical circle
     536            0 :                                                                                 if(DistancePointToLine(center, aaPos[e->vertex(0)], aaPos[e->vertex(1)])
     537              :                                                                                         < radius)
     538              :                                                                                 {
     539              :                                                                                 //      if the edge is a constrained edge, we'll push it to
     540              :                                                                                 //      closeEdges
     541            0 :                                                                                         if(info.is_segment(e) && !EdgeContains(e, pointInserted))
     542            0 :                                                                                                 closeEdges.push_back(e);
     543              : 
     544              :                                                                                         grid.mark(e);
     545              : 
     546              :                                                                                 //      the connected vertex has to be pushed to
     547              :                                                                                 //      the queue, regardless whether it lies in the circle
     548              :                                                                                 //      or not, since an edge from this vertex could
     549              :                                                                                 //      reenter the circle
     550            0 :                                                                                         Vertex* vcon = GetConnectedVertex(e, vrt);
     551            0 :                                                                                         if(grid.is_marked(vcon))
     552            0 :                                                                                                 continue;
     553              :                                                                                         grid.mark(vcon);
     554              :                                                                                         qvrts.push(vcon);
     555              : 
     556              :                                                                                 //      vrt0 and vrt1 won't be removed anyways
     557            0 :                                                                                         if(vcon == vrt0 || vcon == vrt1)
     558            0 :                                                                                                 continue;
     559              : 
     560              :                                                                                 //      if the vertrex was created during remeshing
     561              :                                                                                 //      and lies in the circle, then we'll push it to vrts
     562              :                                                                                         if((info.mark(vcon) == DI::NEW_INNER)
     563            0 :                                                                                                 && (VecDistanceSq(aaPos[vcon], center) < radiusSq))
     564              :                                                                                         {
     565            0 :                                                                                                 vrts.push_back(vcon);
     566              :                                                                                         }
     567              :                                                                                 }
     568              :                                                                         }
     569              :                                                                 }
     570              :                                                         }
     571            0 :                                                         grid.end_marking();
     572              : 
     573              :                                                         //UG_LOG(vrts.size() << " vertices have to be deleted!\n");
     574              : 
     575              :                                                 //      vrts now contains all vertices which lie in a circle of radius
     576              :                                                 //      'radiusSq' around the center. We now have to check for each,
     577              :                                                 //      whether it is visible from the center, by checking whether
     578              :                                                 //      the line of sight intersects a constrained edge in
     579              :                                                 //      closeEdges.
     580              :                                                 //      if it is visible, then we'll delete it and locally remesh
     581              :                                                 //      the grid.
     582              :                                                 //      We want to record all new edges that are created during remeshing,
     583              :                                                 //      since they have to be considered as candidates for MakeDelaunay.
     584              :                                                 //      However, since some of them will possibly be deleted during
     585              :                                                 //      following erasures, we have to be careful here. This is
     586              :                                                 //      all handled by info.start/stop_candidate_recording
     587            0 :                                                         info.start_candidate_recording();
     588            0 :                                                         for(size_t i_vrts = 0; i_vrts < vrts.size(); ++i_vrts){
     589            0 :                                                                 Vertex* vrt = vrts[i_vrts];
     590              :                                                                 vector_t& v = aaPos[vrt];
     591              :                                                                 //UG_LOG("ERASING VRT at " << v << "...\n");
     592              :                                                                 bool intersects = false;
     593              :                                                                 //UG_LOG("  checking for intersections\n");
     594            0 :                                                                 for(size_t i_edge = 0; i_edge < closeEdges.size(); ++i_edge){
     595            0 :                                                                         vector_t& ev0 = aaPos[closeEdges[i_edge]->vertex(0)];
     596            0 :                                                                         vector_t& ev1 = aaPos[closeEdges[i_edge]->vertex(1)];
     597              :                                                                         vector_t a;
     598            0 :                                                                         if(DelaunayLineLineIntersection(a, faceCenter, v, ev0, ev1, faceNormal)){
     599              :                                                                         //if(LineLineIntersection3d(a, b, center, v, ev0, ev1)){
     600              :                                                                                 //UG_LOG("  intersection!\n");
     601              :                                                                                 intersects = true;
     602            0 :                                                                                 break;
     603              :                                                                         }
     604              :                                                                 }
     605              : 
     606            0 :                                                                 if(intersects)
     607            0 :                                                                         continue;
     608              : 
     609              :                                                                 //UG_LOG("  gathering surrounding edges\n");
     610              :                                                         //      no intersection detected. erase the vertex and perform
     611              :                                                         //      local retriangulation. Add surrounding edges to
     612              :                                                         //      the 'edges' array
     613              :                                                         //      Store one face, which will be the parent for all new faces
     614              :                                                                 Face* parent = NULL;
     615              :                                                                 edges.clear();
     616              :                                                                 CollectAssociated(faces, grid, vrt);
     617            0 :                                                                 for(size_t i_face = 0; i_face < faces.size(); ++i_face){
     618            0 :                                                                         Face* f = faces[i_face];
     619              :                                                                         parent = f;
     620            0 :                                                                         for(size_t i = 0; i < f->num_edges(); ++i){
     621            0 :                                                                                 Edge* e = grid.get_edge(f, i);
     622            0 :                                                                                 if(!EdgeContains(e, vrt)){
     623            0 :                                                                                         edges.push_back(e);
     624              :                                                                                         //UG_LOG("surrounding edge: " << CalculateCenter(e, aaPos) << endl);
     625              :                                                                                 }
     626              :                                                                         }
     627              :                                                                 }
     628              :                                                                 assert(parent);
     629              : 
     630              :                                                                 //UG_LOG("  retriangulation\n");
     631              :                                                         //      perform retriangulation
     632              :                                                         //      get the vertices of the poly-chain
     633              :                                                                 //UG_LOG("1");
     634              :                                                                 std::vector<Vertex*> vrtPolyChain;
     635            0 :                                                                 CreatePolyChain(vrtPolyChain, grid, edges.begin(), edges.end());
     636              :                                                                 //UG_LOG("2");
     637            0 :                                                                 std::vector<vector_t> posPolyChain(vrtPolyChain.size());
     638              :                                                                 std::vector<int> edgeChain, faceIndices;
     639            0 :                                                                 edgeChain.reserve(vrtPolyChain.size() * 2);
     640              :                                                                 //UG_LOG("3");
     641              :                                                                 size_t numVrts = vrtPolyChain.size();
     642            0 :                                                                 for(size_t i = 0; i < numVrts; ++i){
     643              :                                                                         //UG_LOG(aaPos[vrtPolyChain[i]]);
     644            0 :                                                                         posPolyChain[i] = aaPos[vrtPolyChain[i]];
     645            0 :                                                                         edgeChain.push_back(i);
     646            0 :                                                                         edgeChain.push_back((i+1) % numVrts);
     647              :                                                                 }
     648              : /*
     649              :                                                                 ("edges.size: " << edges.size() << ", posPolyChain.size: " << posPolyChain.size());
     650              :                                                                 for(size_t i = 0; i < edgeChain.size(); i+=2){
     651              :                                                                         UG_LOG(" (" << edgeChain[i] << ", " << edgeChain[i+1] << ")");
     652              :                                                                 }
     653              :                                                                 UG_LOG(endl);
     654              : */
     655              : 
     656              :                                                                 //UG_LOG("4");
     657              : 
     658            0 :                                                                 if(!TriangleFill_SweepLine(faceIndices, posPolyChain, edgeChain)){
     659            0 :                                                                         UG_LOG("Sweepline failed in step " << stepCount << "... aborting\n");
     660            0 :                                                                         UG_LOG("  While examining face " << faceCenter << endl);
     661              :                                                                         return false;
     662              :                                                                 }
     663              :                                                                 //UG_LOG("5");
     664              :                                                         //      create the faces
     665            0 :                                                                 for(size_t i = 0; i < faceIndices.size(); i+=3){
     666            0 :                                                                         grid.create<Triangle>(
     667            0 :                                                                                         TriangleDescriptor(vrtPolyChain[faceIndices[i]],
     668              :                                                                                                                            vrtPolyChain[faceIndices[i+1]],
     669              :                                                                                                                            vrtPolyChain[faceIndices[i+2]]),
     670              :                                                                                         parent);
     671              :                                                                 }
     672              :                                                                 //UG_LOG("6\n");
     673              : 
     674              :                                                                 //UG_LOG("  erase\n");
     675              :                                                         //      now erase vrt
     676            0 :                                                                 grid.erase(vrt);
     677              : 
     678              :                                                                 //DelaunayDebugSave(grid, "After TriangleFill", info);
     679              :                                                         }
     680              : 
     681            0 :                                                         info.stop_candidate_recording();
     682              :                                                 }
     683              :                                                 else{
     684              :                                                         aaPos[pointInserted] = cc;
     685              :                                                 }
     686              :                                         }
     687              :                                 }
     688              :                                 else{
     689              :                                 //      we found the triangle, which contains cc. Insert the point
     690              :                                 //      and perform local delaunay (not necessarily local...).
     691              :                                 //...
     692              :                                 //      But first we have to check whether an edge of the triangle
     693              :                                 //      would be encroached.
     694              :                                 //      If this is the case, we'll insert the new vertex at the triangle's
     695              :                                 //      center instead of the circum-center, to avoid skinny triangles
     696              :                                         CollectAssociated(edges, grid, curFace);
     697            0 :                                         for(size_t i = 0; i < edges.size(); ++i){
     698            0 :                                                 Edge* e = edges[i];
     699            0 :                                                 if(info.is_segment(e)){
     700            0 :                                                         vector_t eCenter = CalculateCenter(e, aaPos);
     701            0 :                                                         number eLenSq = EdgeLengthSq(e, aaPos);
     702            0 :                                                         if(VecDistanceSq(eCenter, cc) < eLenSq / 4.){
     703            0 :                                                                 cc = CalculateCenter(curFace, aaPos);
     704            0 :                                                                 break;
     705              :                                                         }
     706              :                                                 }
     707              :                                         }
     708              : 
     709            0 :                                         Vertex* vrt0 = curFace->vertex(0);
     710            0 :                                         Vertex* vrt1 = curFace->vertex(1);
     711            0 :                                         Vertex* vrt2 = curFace->vertex(2);
     712              : 
     713              :                                         //UG_LOG("creating new elements...\n");
     714            0 :                                         Vertex* vrt = *grid.create<RegularVertex>(curFace);
     715              :                                         aaPos[vrt] = cc;
     716            0 :                                         grid.create<Triangle>(TriangleDescriptor(vrt0, vrt1, vrt), curFace);
     717            0 :                                         grid.create<Triangle>(TriangleDescriptor(vrt1, vrt2, vrt), curFace);
     718            0 :                                         grid.create<Triangle>(TriangleDescriptor(vrt2, vrt0, vrt), curFace);
     719              :                                         //UG_LOG("erasing old face\n");
     720            0 :                                         grid.erase(curFace);
     721              : 
     722              :                                         //DelaunayDebugSave(grid, "After InsertPoint", info);
     723              : 
     724            0 :                                         pointInserted = vrt;
     725              :                                 }
     726              : 
     727            0 :                                 if(pointInserted){
     728              :                                         //UG_LOG("temp-save to delaunay_debug.ugx\n");
     729              :                                         //SaveGridToFile(grid, "delaunay_debug.ugx");
     730              : 
     731              :                                         //UG_LOG("inserted point\n");
     732              :                                 //      if a vertex was inserted, we'll have to perform a delaunay step.
     733              :                                 //      Find new candidates by examining edges of associated triangles of vrt.
     734              :                                 //      If an edge of such a triangle is connected to exactly 2
     735              :                                 //      triangles, both marked, then it is a new candidate.
     736              :                                         CollectAssociated(faces, grid, pointInserted);
     737            0 :                                         for(size_t i_face = 0; i_face < faces.size(); ++i_face){
     738            0 :                                                 if(!info.is_inner(faces[i_face]))
     739            0 :                                                         continue;
     740              : 
     741              :                                                 CollectAssociated(edges, grid, faces[i_face]);
     742            0 :                                                 for(size_t i_edge = 0; i_edge < edges.size(); ++i_edge){
     743            0 :                                                         Edge* e = edges[i_edge];
     744            0 :                                                         if(info.is_candidate(e) || info.is_segment(e))
     745            0 :                                                                 continue;
     746              : 
     747              :                                                         Face* nbrs[2];
     748            0 :                                                         if(GetAssociatedFaces(nbrs, grid, e, 2) == 2){
     749            0 :                                                                 if(info.is_inner(nbrs[0])
     750            0 :                                                                    && info.is_inner(nbrs[1]))
     751              :                                                                 {
     752            0 :                                                                         info.push_candidate(e);
     753              :                                                                 }
     754              :                                                         }
     755              :                                                 }
     756              :                                         }
     757              : 
     758              :                                         // DelaunayDebugSave(grid, "Candidates Adjusted After Insert Point", info);
     759              : 
     760              :                                         //UG_LOG("redelaunaylizing\n");
     761              :                                         // UG_LOG("MakeDelaunay after InsertPoint\n");
     762            0 :                                         if(!MakeDelaunay(info)){
     763            0 :                                                 UG_LOG("Make Delaunay failed in step " << stepCount << ".\n");
     764            0 :                                                 UG_LOG("  While examining face " << faceCenter << endl);
     765              :                                                 return false;
     766              :                                         }
     767              :                                         // UG_LOG("MakeDelaunay done\n");
     768              :                                         // UG_LOG("adaption step completed!\n");
     769              :                                 }
     770              :                         }
     771              : 
     772              : /*
     773              :                 //      check whether an illegal triangle has been inserted
     774              :                         for(TriangleIterator iter = grid.begin<Triangle>();
     775              :                                 iter != grid.end<Triangle>(); ++iter)
     776              :                         {
     777              :                                 vector3 n;
     778              :                                 CalculateNormal(n, *iter, aaPos);
     779              :                                 if(n.z() <= 0){
     780              :                                         UG_LOG("ATTENTION: Illegal triangle created in step " << stepCount << "\n");
     781              :                                         return false;
     782              :                                 }
     783              :                         }
     784              : */
     785            0 :                         ++stepCount;
     786              :                         DelaunayDebugSave(grid, "", info);
     787            0 :                         if(stepCount == maxSteps)
     788              :                                 break;
     789              : /*
     790              :                         if((stepCount % 1000) == 0){
     791              :                                 UG_LOG("temp-save to delaunay_debug.ugx in step " << stepCount << endl);
     792              :                                 //DelaunayDebugSave(grid, "", info);
     793              :                                 SaveGridToFile(grid, "delaunay_debug.ugx");
     794              :                         }
     795              : */
     796              :                 }
     797              :         }
     798              :         return true;
     799            0 : }
     800              : 
     801              : 
     802              : 
     803              : template bool MakeDelaunay(DelaunayInfo<Grid::VertexAttachmentAccessor<AVector3> >&);
     804              : 
     805              : template bool QualityGridGeneration(Grid&,
     806              :                                                    DelaunayInfo<Grid::VertexAttachmentAccessor<AVector3> >&,
     807              :                                                    number, int);
     808              : 
     809              : }//     end of namespace
        

Generated by: LCOV version 2.0-1