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

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-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 <queue>
      34              : #include <algorithm>
      35              : #include "triangle_fill.h"
      36              : #include "common/math/ugmath.h"
      37              : #include "lib_grid/algorithms/geom_obj_util/geom_obj_util.h"
      38              : #include "lib_grid/algorithms/polychain_util.h"
      39              : 
      40              : using namespace std;
      41              : 
      42              : namespace ug
      43              : {
      44              : 
      45              : /**     Make sure that edgeNormalsOut has the same size as poly-chain.
      46              :  *      The poly-chain is treated as a closed poly-chain where an edge
      47              :  *      between the last and the first entry exists.*/
      48            0 : void CalculatePolychainEdgeNormals(vector2* edgeNormalsOut, vector2* polyChain,
      49              :                                                         size_t polyChainSize, bool bOuterNormals)
      50              : {
      51            0 :         if(polyChainSize < 2)
      52            0 :                 return;
      53              : 
      54              : //      perform a first guess
      55              : //      in order to check whether those normals are inner or outer normals,
      56              : //      we're building the sum of the normal of an edge with the following edge.
      57              :         number dot = 0;
      58              :         
      59              : //      the edge to which we will calculate the normal
      60              :         vector2 e;
      61              :         VecSubtract(e, polyChain[1], polyChain[0]);
      62            0 :         VecNormalize(e, e);
      63              :         
      64            0 :         for(size_t i = 0; i < polyChainSize; ++i){
      65            0 :                 edgeNormalsOut[i].x() = e.y();
      66            0 :                 edgeNormalsOut[i].y() = -e.x();
      67              :                 
      68              :         //      calculate the next edge (the normal in the next iteration
      69              :         //      will be calculated for this edge)
      70            0 :                 VecSubtract(e, polyChain[(i+2)%polyChainSize],
      71            0 :                                            polyChain[(i+1)%polyChainSize]);
      72            0 :                 VecNormalize(e, e);
      73              :                 
      74              :         //      Build the dot-product with the last normal
      75            0 :                 dot += VecDot(edgeNormalsOut[i], e);
      76              :         }
      77              :         
      78              : //      if the dot-product is smaller than 0, the normal is an outer normal
      79              : //      if it is bigger than 0, the normal is an inner normal.
      80            0 :         if((dot < 0 && (!bOuterNormals)) ||
      81            0 :            (dot > 0 && bOuterNormals))
      82              :         {
      83              :         //      we have to invert the normals
      84            0 :                 for(size_t i = 0; i < polyChainSize; ++i){
      85            0 :                         edgeNormalsOut[i].x() = -edgeNormalsOut[i].x();
      86            0 :                         edgeNormalsOut[i].y() = -edgeNormalsOut[i].y();
      87              :                 }
      88              :         }
      89              : }
      90              : 
      91              : ////////////////////////////////////////////////////////////////////////
      92              : struct ChainInfo{
      93            0 :         ChainInfo()     {}
      94              :         ChainInfo(int vrtInd, int vrtIndIn, int vrtIndOut) :
      95            0 :                 myVrt(vrtInd), inVrt(vrtIndIn), outVrt(vrtIndOut),
      96              :                 isCandidate(false), associatedDistanceSq(0)     {}
      97              :                 
      98              :         bool operator == (const ChainInfo& ci){
      99            0 :                 return myVrt == ci.myVrt && inVrt == ci.inVrt && outVrt == ci.outVrt
     100            0 :                                 && isCandidate == ci.isCandidate
     101            0 :                                 && associatedDistanceSq == ci.associatedDistanceSq;
     102              :                 }
     103              :         
     104              :         bool operator < (const ChainInfo& ci) const      {return associatedDistanceSq > 
     105              :                                                                                                         ci.associatedDistanceSq;}
     106              : 
     107              :         size_t myVrt;
     108              :         size_t inVrt;
     109              :         size_t outVrt;
     110              :         bool isCandidate;
     111              :         number associatedDistanceSq;
     112              : };
     113              : 
     114            0 : void UpdateChainInfo(ChainInfo& ci, vector2* polyChain, vector2* edgeNormals)
     115              : {
     116              :         vector2 outEdge;
     117            0 :         VecSubtract(outEdge, polyChain[ci.outVrt], polyChain[ci.myVrt]);
     118            0 :         ci.isCandidate = VecDot(edgeNormals[ci.inVrt], outEdge) < -SMALL; //ci.inVrt == inEdgeIndex.
     119              : 
     120              : //      calculate relative length
     121            0 :         number l = VecDistance(polyChain[ci.inVrt], polyChain[ci.outVrt]);
     122            0 :         number t1 = VecDistance(polyChain[ci.inVrt], polyChain[ci.myVrt]); 
     123            0 :         number t2 = VecDistance(polyChain[ci.outVrt], polyChain[ci.myVrt]);
     124              :         number relLen = 1;
     125            0 :         if(t1 + t2 > SMALL)
     126            0 :                 relLen = l / (t1 + t2);
     127              : 
     128              : //      if the relative length is small we'll calculate the squared length as the indiceator    
     129            0 :         if(relLen < 0.9)
     130              :         {
     131            0 :                 ci.associatedDistanceSq = VecDistanceSq(polyChain[ci.inVrt],
     132              :                                                                                                 polyChain[ci.outVrt]);
     133              :         }
     134              :         else{
     135              :         //      set it to a very big value
     136            0 :                 ci.associatedDistanceSq = 1e+12;
     137              :         }
     138            0 : }
     139              : 
     140              : ////////////////////////////////////////////////////////////////////////
     141            0 : bool TriangleFill(std::vector<int>& vTriIndsOut, vector2* polyChain,
     142              :                                         size_t polyChainSize, bool bTriangulateInside)
     143              : {
     144              :         vTriIndsOut.clear();
     145              :         
     146            0 :         if(polyChainSize < 2)
     147              :                 return false;
     148              :                 
     149              : //      calculate the normals
     150            0 :         vector<vector2> vNormals(polyChainSize);
     151            0 :         CalculatePolychainEdgeNormals(&vNormals.front(), polyChain,
     152              :                                                                         polyChainSize, bTriangulateInside);
     153              : 
     154              : //tmp. create edges from the edges mid-point along their normals
     155              : 
     156              : //      set up a chain that holds the in- and out- edges of each point
     157              : //      together with a value that determines the priority.
     158              : //      The closer to 0, the higher the priority
     159              : 
     160              : //      chain infos are stored in a vector
     161              : //      this chain always holds valid and up to date elements
     162            0 :         vector<ChainInfo> chainInfos(polyChainSize);
     163              :         
     164              : //      create a priority queue that holds pointers to the chain-infos.
     165              : //      warning: this queue will contain invalid entries later on.
     166              : //      this is handled by a special check before an element is used.
     167              :         //priority_queue<ChainInfo> qChainInfos;
     168              :         queue<ChainInfo> qChainInfos;
     169            0 :         for(size_t i = 0; i < polyChainSize; ++i){
     170            0 :                 int inVrtInd = (polyChainSize + i - 1) % polyChainSize;//avoid negativity in %
     171            0 :                 int outVrtInd = (i + 1) % polyChainSize;
     172            0 :                 chainInfos[i] = ChainInfo(i, inVrtInd, outVrtInd);
     173            0 :                 UpdateChainInfo(chainInfos[i], polyChain, &vNormals.front());
     174            0 :                 if(chainInfos[i].isCandidate)
     175              :                         qChainInfos.push(chainInfos[i]);
     176              :         }
     177              :         
     178              : //      iterate until all triangles have been created.
     179            0 :         int counter = polyChainSize - 2;
     180            0 :         while(counter > 0 && (!qChainInfos.empty()))
     181              :         {
     182              :         //      get the element with top priority
     183              :                 //ChainInfo ci = qChainInfos.top();
     184            0 :                 ChainInfo ci = qChainInfos.front();
     185              :                 qChainInfos.pop();
     186            0 :                 if(!ci.isCandidate){
     187              :                         continue;
     188              :                 }
     189              :         
     190              :         //      we have to make sure that the chain info in the 
     191              :         //      priority queue matches the actual chain-entry.
     192              :                 if(ci == chainInfos[ci.myVrt])
     193              :                 {
     194              :                 //      check whether the triangle is a valid triangle or not.
     195              :                 //      do this by checking for all points whether they lie on the triangle.
     196            0 :                         vector2& p0 = polyChain[ci.inVrt];
     197            0 :                         vector2& p1 = polyChain[ci.myVrt];
     198            0 :                         vector2& p2 = polyChain[ci.outVrt];
     199              :                         
     200              :                 //      the bounding rect of the points
     201              :                         vector2 vMin;
     202              :                         vector2 vMax;
     203            0 :                         vMin.x() = min(p0.x(), min(p1.x(), p2.x()));
     204            0 :                         vMin.y() = min(p0.y(), min(p1.y(), p2.y()));
     205            0 :                         vMax.x() = max(p0.x(), max(p1.x(), p2.x()));
     206            0 :                         vMax.y() = max(p0.y(), max(p1.y(), p2.y()));
     207              :                         
     208              :                 //      only consider points that lie in the box
     209              : //TODO: replace this with a tree lookup.
     210              :                         bool badTri = false;
     211            0 :                         for(size_t i = 0; i < polyChainSize; ++i){
     212            0 :                                 if(i != ci.inVrt && i != ci.outVrt && i != ci.myVrt){
     213            0 :                                         vector2& p = polyChain[i];
     214            0 :                                         if(BoxBoundProbe(p, vMin, vMax))
     215              :                                         {
     216            0 :                                                 if(PointIsInsideTriangle(p, p0, p1, p2)){
     217              :                                                         //UG_LOG(" bad tri in " << ci.myVrt << " - ");
     218              :                                                         badTri = true;
     219              :                                                         break;
     220              :                                                 }
     221              :                                         }
     222              :                                 }
     223              :                         }
     224              :                         
     225              :                 //      if no points lie in the triangle we can create it.
     226            0 :                         if(!badTri){
     227            0 :                                 --counter;
     228            0 :                                 if(bTriangulateInside){
     229            0 :                                         vTriIndsOut.push_back(ci.inVrt);
     230            0 :                                         vTriIndsOut.push_back(ci.myVrt);
     231            0 :                                         vTriIndsOut.push_back(ci.outVrt);
     232              :                                 }
     233              :                                 else{
     234            0 :                                         vTriIndsOut.push_back(ci.outVrt);
     235            0 :                                         vTriIndsOut.push_back(ci.myVrt);
     236            0 :                                         vTriIndsOut.push_back(ci.inVrt);
     237              :                                 }
     238              :                                 
     239              :                         //      calculate the new normal of the edge
     240              :                                 vector2 eNew;
     241              :                                 VecSubtract(eNew, polyChain[ci.outVrt], polyChain[ci.inVrt]);
     242              :                                 vector2 nNew;
     243            0 :                                 nNew.x() = eNew.y();
     244            0 :                                 nNew.y() = -eNew.x();
     245              :                         //      make sure that the normal points into the right direction.
     246              :                                 vector2 vTestNorm;
     247              :                                 VecAdd(vTestNorm, vNormals[ci.inVrt], vNormals[ci.myVrt]);
     248            0 :                                 if(VecDot(nNew, vTestNorm) < 0)
     249              :                                         VecScale(nNew, nNew, -1.);
     250            0 :                                 VecNormalize(vNormals[ci.inVrt], nNew);
     251              :                                 
     252              :                                 
     253              :                         //      we have to update the chain-infos and the queue
     254            0 :                                 chainInfos[ci.myVrt].isCandidate = false;
     255              :                                 ChainInfo& ciIn = chainInfos[ci.inVrt];
     256              :                                 ChainInfo& ciOut = chainInfos[ci.outVrt];
     257            0 :                                 ciIn.outVrt = ci.outVrt;
     258            0 :                                 ciOut.inVrt = ci.inVrt;
     259            0 :                                 UpdateChainInfo(ciIn, polyChain, &vNormals.front());
     260            0 :                                 UpdateChainInfo(ciOut, polyChain, &vNormals.front());
     261            0 :                                 if(ciIn.isCandidate)
     262              :                                         qChainInfos.push(ciIn);
     263            0 :                                 if(ciOut.isCandidate)
     264              :                                         qChainInfos.push(ciOut);
     265              :                         }
     266              :                 }
     267              :         }
     268              : /*
     269              :         if(counter == 0){
     270              :                 UG_LOG("  counter is empty. ");
     271              :         }
     272              :         if(qChainInfos.empty()){
     273              :                 UG_LOG("  queue is empty. ");
     274              :         }
     275              : */
     276              : //      done. return true
     277              :         return true;
     278            0 : }
     279              : 
     280            0 : bool TriangleFill(Grid& grid, EdgeIterator edgesBegin,
     281              :                                 EdgeIterator edgesEnd, bool bTriangulateInside)
     282              : {
     283            0 :         if(edgesBegin == edgesEnd)
     284              :                 return false;
     285              : 
     286            0 :         if(!grid.has_vertex_attachment(aPosition))
     287              :                 return false;
     288              :                 
     289              :         Grid::VertexAttachmentAccessor<APosition> aaPos(grid, aPosition);
     290              :         
     291              : //      get the vertices of the poly-chain
     292              :         std::vector<Vertex*> vrtPolyChain;
     293            0 :         CreatePolyChain(vrtPolyChain, grid, edgesBegin, edgesEnd);
     294              : 
     295              : //      a poly-chain that stores positions
     296            0 :         std::vector<vector3> polyChain3D(vrtPolyChain.size());
     297            0 :         for(size_t i = 0; i < vrtPolyChain.size(); ++i)
     298            0 :                 polyChain3D[i] = aaPos[vrtPolyChain[i]];
     299              :                 
     300              : //      perform transform to 2d 
     301            0 :         std::vector<vector2> polyChain2D(vrtPolyChain.size());
     302            0 :         TransformPointSetTo2D(&polyChain2D.front(), &polyChain3D.front(),
     303              :                                                   polyChain3D.size());
     304              : /*
     305              : //TODO: perform a more elaborated projection!
     306              :         for(size_t i = 0; i < vrtPolyChain.size(); ++i){
     307              :                 vector3& v = aaPos[vrtPolyChain[i]];
     308              :                 polyChain2D[i] = vector2(v.x(), v.y());
     309              :         }
     310              : */      
     311              : 
     312              : //      perform triangulation
     313              :         vector<int> triIndices;
     314            0 :         if(TriangleFill(triIndices, &polyChain2D.front(), polyChain2D.size(),
     315              :                                         bTriangulateInside))
     316              :         {
     317              :         //      create the triangles
     318            0 :                 for(size_t i = 0; i < triIndices.size(); i+=3){
     319            0 :                         grid.create<Triangle>(TriangleDescriptor(vrtPolyChain[triIndices[i]],
     320            0 :                                                                                                         vrtPolyChain[triIndices[i + 1]],
     321            0 :                                                                                                         vrtPolyChain[triIndices[i + 2]]));
     322              :                 }
     323              :                 
     324              :                 return true;
     325              :         }
     326              : 
     327              : /*
     328              : //tmp. create edges from the edges mid-point along their normals
     329              :         //      calculate the normals
     330              :         vector<vector2> vNormals(polyChain2D.size());
     331              :         CalculatePolychainEdgeNormals(&vNormals.front(), &polyChain2D.front(),
     332              :                                                                         polyChain2D.size(), bTriangulateInside);
     333              :         
     334              :         for(size_t i = 0; i < polyChain2D.size(); ++i){
     335              :                 Vertex* vrt1 = *grid.create<RegularVertex>();
     336              :                 Vertex* vrt2 = *grid.create<RegularVertex>();
     337              :                 Edge* e = *grid.create<RegularEdge>(EdgeDescriptor(vrt1, vrt2));
     338              :                 
     339              :                 VecAdd(aaPos[vrt1], aaPos[vrtPolyChain[i]], aaPos[vrtPolyChain[(i+1)%vrtPolyChain.size()]]);
     340              :                 VecScale(aaPos[vrt1], aaPos[vrt1], 0.5);
     341              :                 
     342              :                 aaPos[vrt2].x() = aaPos[vrt1].x() + vNormals[i].x() * 0.1;
     343              :                 aaPos[vrt2].y() = aaPos[vrt1].y() + vNormals[i].y() * 0.1;
     344              :                 aaPos[vrt2].z() = aaPos[vrt1].z();
     345              :         }
     346              :         return true;
     347              : */
     348              : 
     349              :         return false;
     350            0 : }
     351              : 
     352              : }//     end of namespace
        

Generated by: LCOV version 2.0-1