LCOV - code coverage report
Current view: top level - alg - delaunay.c (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 204 219 93.2 %
Date: 2024-05-04 12:52:34 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL algorithms
       4             :  * Purpose:  Delaunay triangulation
       5             :  * Author:   Even Rouault, even.rouault at spatialys.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * Permission is hereby granted, free of charge, to any person obtaining a
      11             :  * copy of this software and associated documentation files (the "Software"),
      12             :  * to deal in the Software without restriction, including without limitation
      13             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14             :  * and/or sell copies of the Software, and to permit persons to whom the
      15             :  * Software is furnished to do so, subject to the following conditions:
      16             :  *
      17             :  * The above copyright notice and this permission notice shall be included
      18             :  * in all copies or substantial portions of the Software.
      19             :  *
      20             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26             :  * DEALINGS IN THE SOFTWARE.
      27             :  ****************************************************************************/
      28             : 
      29             : #if defined(__MINGW32__) || defined(__MINGW64__)
      30             : /*  This avoids i586-mingw32msvc/include/direct.h from including libqhull/io.h
      31             :  * ... */
      32             : #define _DIRECT_H_
      33             : /* For __MINGW64__ */
      34             : #define _INC_DIRECT
      35             : #define _INC_STAT
      36             : #endif
      37             : 
      38             : #if defined(INTERNAL_QHULL) && !defined(DONT_DEPRECATE_SPRINTF)
      39             : #define DONT_DEPRECATE_SPRINTF
      40             : #endif
      41             : 
      42             : #include "cpl_error.h"
      43             : #include "cpl_conv.h"
      44             : #include "cpl_string.h"
      45             : #include "gdal_alg.h"
      46             : 
      47             : #include <stdio.h>
      48             : #include <stdlib.h>
      49             : #include <string.h>
      50             : #include <ctype.h>
      51             : #include <math.h>
      52             : 
      53             : #if defined(INTERNAL_QHULL) || defined(EXTERNAL_QHULL)
      54             : #define HAVE_INTERNAL_OR_EXTERNAL_QHULL 1
      55             : #endif
      56             : 
      57             : #if HAVE_INTERNAL_OR_EXTERNAL_QHULL
      58             : #ifdef INTERNAL_QHULL
      59             : 
      60             : #include "internal_qhull_headers.h"
      61             : 
      62             : #else /* INTERNAL_QHULL */
      63             : 
      64             : #ifdef _MSC_VER
      65             : #pragma warning(push)
      66             : #pragma warning(                                                               \
      67             :     disable : 4324)  // 'qhT': structure was padded due to alignment specifier
      68             : #endif
      69             : 
      70             : #if defined(__clang__)
      71             : #pragma clang diagnostic push
      72             : #pragma clang diagnostic ignored "-Wdocumentation"
      73             : #endif
      74             : 
      75             : #include "libqhull_r/libqhull_r.h"
      76             : #include "libqhull_r/qset_r.h"
      77             : 
      78             : #if defined(__clang__)
      79             : #pragma clang diagnostic pop
      80             : #endif
      81             : 
      82             : #ifdef _MSC_VER
      83             : #pragma warning(pop)
      84             : #endif
      85             : 
      86             : #endif /* INTERNAL_QHULL */
      87             : 
      88             : #endif /* HAVE_INTERNAL_OR_EXTERNAL_QHULL*/
      89             : 
      90             : /************************************************************************/
      91             : /*                       GDALHasTriangulation()                         */
      92             : /************************************************************************/
      93             : 
      94             : /** Returns if GDAL is built with Delaunay triangulation support.
      95             :  *
      96             :  * @return TRUE if GDAL is built with Delaunay triangulation support.
      97             :  *
      98             :  * @since GDAL 2.1
      99             :  */
     100           4 : int GDALHasTriangulation()
     101             : {
     102             : #if HAVE_INTERNAL_OR_EXTERNAL_QHULL
     103           4 :     return TRUE;
     104             : #else
     105             :     return FALSE;
     106             : #endif
     107             : }
     108             : 
     109             : /************************************************************************/
     110             : /*                   GDALTriangulationCreateDelaunay()                  */
     111             : /************************************************************************/
     112             : 
     113             : /** Computes a Delaunay triangulation of the passed points
     114             :  *
     115             :  * @param nPoints number of points
     116             :  * @param padfX x coordinates of the points.
     117             :  * @param padfY y coordinates of the points.
     118             :  * @return triangulation that must be freed with GDALTriangulationFree(), or
     119             :  *         NULL in case of error.
     120             :  *
     121             :  * @since GDAL 2.1
     122             :  */
     123           5 : GDALTriangulation *GDALTriangulationCreateDelaunay(int nPoints,
     124             :                                                    const double *padfX,
     125             :                                                    const double *padfY)
     126             : {
     127             : #if HAVE_INTERNAL_OR_EXTERNAL_QHULL
     128             :     coordT *points;
     129             :     int i, j;
     130           5 :     GDALTriangulation *psDT = NULL;
     131             :     facetT *facet;
     132             :     GDALTriFacet *pasFacets;
     133             :     int *panMapQHFacetIdToFacetIdx; /* map from QHull facet ID to the index of
     134             :                                        our GDALTriFacet* array */
     135             :     int curlong, totlong;           /* memory remaining after qh_memfreeshort */
     136           5 :     char *pszTempFilename = NULL;
     137           5 :     FILE *fpTemp = NULL;
     138             : 
     139             :     qhT qh_qh;
     140           5 :     qhT *qh = &qh_qh;
     141             : 
     142           5 :     QHULL_LIB_CHECK /* Check for compatible library */
     143             : 
     144           5 :         points = (coordT *)VSI_MALLOC2_VERBOSE(sizeof(double) * 2, nPoints);
     145           5 :     if (points == NULL)
     146             :     {
     147           0 :         return NULL;
     148             :     }
     149       14681 :     for (i = 0; i < nPoints; i++)
     150             :     {
     151       14676 :         points[2 * i] = padfX[i];
     152       14676 :         points[2 * i + 1] = padfY[i];
     153             :     }
     154             : 
     155           5 :     qh_meminit(qh, NULL);
     156             : 
     157           5 :     if (CPLTestBoolean(CPLGetConfigOption("QHULL_LOG_TO_TEMP_FILE", "NO")))
     158             :     {
     159           2 :         pszTempFilename = CPLStrdup(CPLGenerateTempFilename(NULL));
     160           2 :         fpTemp = fopen(pszTempFilename, "wb");
     161             :     }
     162           5 :     if (fpTemp == NULL)
     163           3 :         fpTemp = stderr;
     164             : 
     165             :     /* d: Delaunay */
     166             :     /* Qbb: scale last coordinate to [0,m] for Delaunay */
     167             :     /* Qc: keep coplanar points with nearest facet */
     168             :     /* Qz: add a point-at-infinity for Delaunay triangulation */
     169             :     /* Qt: triangulated output */
     170           5 :     int ret = qh_new_qhull(qh, 2, nPoints, points, FALSE /* ismalloc */,
     171             :                            "qhull d Qbb Qc Qz Qt", NULL, fpTemp);
     172           5 :     if (fpTemp != stderr)
     173             :     {
     174           2 :         fclose(fpTemp);
     175             :     }
     176           5 :     if (pszTempFilename != NULL)
     177             :     {
     178           2 :         VSIUnlink(pszTempFilename);
     179           2 :         VSIFree(pszTempFilename);
     180             :     }
     181             : 
     182           5 :     VSIFree(points);
     183           5 :     points = NULL;
     184             : 
     185           5 :     if (ret != 0)
     186             :     {
     187           2 :         CPLError(CE_Failure, CPLE_AppDefined, "Delaunay triangulation failed");
     188           2 :         goto end;
     189             :     }
     190             : 
     191             :     /* Establish a map from QHull facet id to the index in our array of
     192             :      * sequential facets */
     193             :     panMapQHFacetIdToFacetIdx =
     194           3 :         (int *)VSI_MALLOC2_VERBOSE(sizeof(int), qh->facet_id);
     195           3 :     if (panMapQHFacetIdToFacetIdx == NULL)
     196             :     {
     197           0 :         goto end;
     198             :     }
     199           3 :     memset(panMapQHFacetIdToFacetIdx, 0xFF, sizeof(int) * qh->facet_id);
     200             : 
     201       29335 :     for (j = 0, facet = qh->facet_list; facet != NULL && facet->next != NULL;
     202       29332 :          facet = facet->next)
     203             :     {
     204       29332 :         if (facet->upperdelaunay != qh->UPPERdelaunay)
     205         500 :             continue;
     206             : 
     207       57664 :         if (qh_setsize(qh, facet->vertices) != 3 ||
     208       28832 :             qh_setsize(qh, facet->neighbors) != 3)
     209             :         {
     210           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     211             :                      "Triangulation resulted in non triangular facet %d: "
     212             :                      "vertices=%d",
     213             :                      facet->id, qh_setsize(qh, facet->vertices));
     214           0 :             VSIFree(panMapQHFacetIdToFacetIdx);
     215           0 :             goto end;
     216             :         }
     217             : 
     218       28832 :         CPLAssert(facet->id < qh->facet_id);
     219       28832 :         panMapQHFacetIdToFacetIdx[facet->id] = j++;
     220             :     }
     221             : 
     222           3 :     pasFacets = (GDALTriFacet *)VSI_MALLOC2_VERBOSE(j, sizeof(GDALTriFacet));
     223           3 :     if (pasFacets == NULL)
     224             :     {
     225           0 :         VSIFree(panMapQHFacetIdToFacetIdx);
     226           0 :         goto end;
     227             :     }
     228             : 
     229           3 :     psDT = (GDALTriangulation *)CPLCalloc(1, sizeof(GDALTriangulation));
     230           3 :     psDT->nFacets = j;
     231           3 :     psDT->pasFacets = pasFacets;
     232             : 
     233             :     // Store vertex and neighbor information for each triangle.
     234       29335 :     for (facet = qh->facet_list; facet != NULL && facet->next != NULL;
     235       29332 :          facet = facet->next)
     236             :     {
     237             :         int k;
     238       29332 :         if (facet->upperdelaunay != qh->UPPERdelaunay)
     239         500 :             continue;
     240       28832 :         k = panMapQHFacetIdToFacetIdx[facet->id];
     241       57664 :         pasFacets[k].anVertexIdx[0] =
     242       28832 :             qh_pointid(qh, ((vertexT *)facet->vertices->e[0].p)->point);
     243       57664 :         pasFacets[k].anVertexIdx[1] =
     244       28832 :             qh_pointid(qh, ((vertexT *)facet->vertices->e[1].p)->point);
     245       57664 :         pasFacets[k].anVertexIdx[2] =
     246       28832 :             qh_pointid(qh, ((vertexT *)facet->vertices->e[2].p)->point);
     247       28832 :         pasFacets[k].anNeighborIdx[0] =
     248       28832 :             panMapQHFacetIdToFacetIdx[((facetT *)facet->neighbors->e[0].p)->id];
     249       28832 :         pasFacets[k].anNeighborIdx[1] =
     250       28832 :             panMapQHFacetIdToFacetIdx[((facetT *)facet->neighbors->e[1].p)->id];
     251       28832 :         pasFacets[k].anNeighborIdx[2] =
     252       28832 :             panMapQHFacetIdToFacetIdx[((facetT *)facet->neighbors->e[2].p)->id];
     253             :     }
     254             : 
     255           3 :     VSIFree(panMapQHFacetIdToFacetIdx);
     256             : 
     257           5 : end:
     258           5 :     qh_freeqhull(qh, !qh_ALL);
     259           5 :     qh_memfreeshort(qh, &curlong, &totlong);
     260             : 
     261           5 :     return psDT;
     262             : #else  /* HAVE_INTERNAL_OR_EXTERNAL_QHULL */
     263             : 
     264             :     /* Suppress unused argument warnings. */
     265             :     (void)nPoints;
     266             :     (void)padfX;
     267             :     (void)padfY;
     268             : 
     269             :     CPLError(CE_Failure, CPLE_NotSupported,
     270             :              "GDALTriangulationCreateDelaunay() unavailable since GDAL built "
     271             :              "without QHull support");
     272             :     return NULL;
     273             : #endif /* HAVE_INTERNAL_OR_EXTERNAL_QHULL */
     274             : }
     275             : 
     276             : /************************************************************************/
     277             : /*                       GDALTriangulationFree()                        */
     278             : /************************************************************************/
     279             : 
     280             : /** Free a triangulation.
     281             :  *
     282             :  * @param psDT triangulation.
     283             :  * @since GDAL 2.1
     284             :  */
     285           5 : void GDALTriangulationFree(GDALTriangulation *psDT)
     286             : {
     287           5 :     if (psDT)
     288             :     {
     289           3 :         VSIFree(psDT->pasFacets);
     290           3 :         VSIFree(psDT->pasFacetCoefficients);
     291           3 :         VSIFree(psDT);
     292             :     }
     293           5 : }
     294             : 
     295             : /************************************************************************/
     296             : /*               GDALTriangulationComputeBarycentricCoefficients()      */
     297             : /************************************************************************/
     298             : 
     299             : /** Computes barycentric coefficients for each triangles of the triangulation.
     300             :  *
     301             :  * @param psDT triangulation.
     302             :  * @param padfX x coordinates of the points. Must be identical to the one passed
     303             :  *              to GDALTriangulationCreateDelaunay().
     304             :  * @param padfY y coordinates of the points. Must be identical to the one passed
     305             :  *              to GDALTriangulationCreateDelaunay().
     306             :  *
     307             :  * @return TRUE in case of success.
     308             :  *
     309             :  * @since GDAL 2.1
     310             :  */
     311           4 : int GDALTriangulationComputeBarycentricCoefficients(GDALTriangulation *psDT,
     312             :                                                     const double *padfX,
     313             :                                                     const double *padfY)
     314             : {
     315             :     int i;
     316             : 
     317           4 :     if (psDT->pasFacetCoefficients != NULL)
     318             :     {
     319           1 :         return TRUE;
     320             :     }
     321           3 :     psDT->pasFacetCoefficients =
     322           3 :         (GDALTriBarycentricCoefficients *)VSI_MALLOC2_VERBOSE(
     323             :             sizeof(GDALTriBarycentricCoefficients), psDT->nFacets);
     324           3 :     if (psDT->pasFacetCoefficients == NULL)
     325             :     {
     326           0 :         return FALSE;
     327             :     }
     328             : 
     329       28835 :     for (i = 0; i < psDT->nFacets; i++)
     330             :     {
     331       28832 :         GDALTriFacet *psFacet = &(psDT->pasFacets[i]);
     332       28832 :         GDALTriBarycentricCoefficients *psCoeffs =
     333       28832 :             &(psDT->pasFacetCoefficients[i]);
     334       28832 :         double dfX1 = padfX[psFacet->anVertexIdx[0]];
     335       28832 :         double dfY1 = padfY[psFacet->anVertexIdx[0]];
     336       28832 :         double dfX2 = padfX[psFacet->anVertexIdx[1]];
     337       28832 :         double dfY2 = padfY[psFacet->anVertexIdx[1]];
     338       28832 :         double dfX3 = padfX[psFacet->anVertexIdx[2]];
     339       28832 :         double dfY3 = padfY[psFacet->anVertexIdx[2]];
     340             :         /* See https://en.wikipedia.org/wiki/Barycentric_coordinate_system */
     341       28832 :         double dfDenom =
     342       28832 :             (dfY2 - dfY3) * (dfX1 - dfX3) + (dfX3 - dfX2) * (dfY1 - dfY3);
     343       28832 :         if (fabs(dfDenom) < 1e-5)
     344             :         {
     345             :             // Degenerate triangle
     346          28 :             psCoeffs->dfMul1X = 0.0;
     347          28 :             psCoeffs->dfMul1Y = 0.0;
     348          28 :             psCoeffs->dfMul2X = 0.0;
     349          28 :             psCoeffs->dfMul2Y = 0.0;
     350          28 :             psCoeffs->dfCstX = 0.0;
     351          28 :             psCoeffs->dfCstY = 0.0;
     352             :         }
     353             :         else
     354             :         {
     355       28804 :             psCoeffs->dfMul1X = (dfY2 - dfY3) / dfDenom;
     356       28804 :             psCoeffs->dfMul1Y = (dfX3 - dfX2) / dfDenom;
     357       28804 :             psCoeffs->dfMul2X = (dfY3 - dfY1) / dfDenom;
     358       28804 :             psCoeffs->dfMul2Y = (dfX1 - dfX3) / dfDenom;
     359       28804 :             psCoeffs->dfCstX = dfX3;
     360       28804 :             psCoeffs->dfCstY = dfY3;
     361             :         }
     362             :     }
     363           3 :     return TRUE;
     364             : }
     365             : 
     366             : /************************************************************************/
     367             : /*               GDALTriangulationComputeBarycentricCoordinates()       */
     368             : /************************************************************************/
     369             : 
     370             : #define BARYC_COORD_L1(psCoeffs, dfX, dfY)                                     \
     371             :     (psCoeffs->dfMul1X * ((dfX)-psCoeffs->dfCstX) +                            \
     372             :      psCoeffs->dfMul1Y * ((dfY)-psCoeffs->dfCstY))
     373             : #define BARYC_COORD_L2(psCoeffs, dfX, dfY)                                     \
     374             :     (psCoeffs->dfMul2X * ((dfX)-psCoeffs->dfCstX) +                            \
     375             :      psCoeffs->dfMul2Y * ((dfY)-psCoeffs->dfCstY))
     376             : #define BARYC_COORD_L3(l1, l2) (1 - (l1) - (l2))
     377             : 
     378             : /** Computes the barycentric coordinates of a point.
     379             :  *
     380             :  * @param psDT triangulation.
     381             :  * @param nFacetIdx index of the triangle in the triangulation
     382             :  * @param dfX x coordinate of the point.
     383             :  * @param dfY y coordinate of the point.
     384             :  * @param pdfL1 (output) pointer to the 1st barycentric coordinate.
     385             :  * @param pdfL2 (output) pointer to the 2nd barycentric coordinate.
     386             :  * @param pdfL3 (output) pointer to the 2nd barycentric coordinate.
     387             :  *
     388             :  * @return TRUE in case of success.
     389             :  *
     390             :  * @since GDAL 2.1
     391             :  */
     392             : 
     393       14170 : int GDALTriangulationComputeBarycentricCoordinates(
     394             :     const GDALTriangulation *psDT, int nFacetIdx, double dfX, double dfY,
     395             :     double *pdfL1, double *pdfL2, double *pdfL3)
     396             : {
     397             :     const GDALTriBarycentricCoefficients *psCoeffs;
     398       14170 :     if (psDT->pasFacetCoefficients == NULL)
     399             :     {
     400           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     401             :                  "GDALTriangulationComputeBarycentricCoefficients() should be "
     402             :                  "called before");
     403           1 :         return FALSE;
     404             :     }
     405       14169 :     CPLAssert(nFacetIdx >= 0 && nFacetIdx < psDT->nFacets);
     406       14169 :     psCoeffs = &(psDT->pasFacetCoefficients[nFacetIdx]);
     407       14169 :     *pdfL1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
     408       14169 :     *pdfL2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
     409       14169 :     *pdfL3 = BARYC_COORD_L3(*pdfL1, *pdfL2);
     410             : 
     411       14169 :     return TRUE;
     412             : }
     413             : 
     414             : /************************************************************************/
     415             : /*               GDALTriangulationFindFacetBruteForce()                 */
     416             : /************************************************************************/
     417             : 
     418             : #define EPS 1e-10
     419             : 
     420             : /** Returns the index of the triangle that contains the point by iterating
     421             :  * over all triangles.
     422             :  *
     423             :  * If the function returns FALSE and *panOutputFacetIdx >= 0, then it means
     424             :  * the point is outside the hull of the triangulation, and *panOutputFacetIdx
     425             :  * is the closest triangle to the point.
     426             :  *
     427             :  * @param psDT triangulation.
     428             :  * @param dfX x coordinate of the point.
     429             :  * @param dfY y coordinate of the point.
     430             :  * @param panOutputFacetIdx (output) pointer to the index of the triangle,
     431             :  *                          or -1 in case of failure.
     432             :  *
     433             :  * @return index >= 0 of the triangle in case of success, -1 otherwise.
     434             :  *
     435             :  * @since GDAL 2.1
     436             :  */
     437             : 
     438       10706 : int GDALTriangulationFindFacetBruteForce(const GDALTriangulation *psDT,
     439             :                                          double dfX, double dfY,
     440             :                                          int *panOutputFacetIdx)
     441             : {
     442             :     int nFacetIdx;
     443       10706 :     *panOutputFacetIdx = -1;
     444       10706 :     if (psDT->pasFacetCoefficients == NULL)
     445             :     {
     446           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     447             :                  "GDALTriangulationComputeBarycentricCoefficients() should be "
     448             :                  "called before");
     449           1 :         return FALSE;
     450             :     }
     451      309577 :     for (nFacetIdx = 0; nFacetIdx < psDT->nFacets; nFacetIdx++)
     452             :     {
     453             :         double l1, l2, l3;
     454      298880 :         const GDALTriBarycentricCoefficients *psCoeffs =
     455      298880 :             &(psDT->pasFacetCoefficients[nFacetIdx]);
     456      298880 :         if (psCoeffs->dfMul1X == 0.0 && psCoeffs->dfMul2X == 0.0 &&
     457      298760 :             psCoeffs->dfMul1Y == 0.0 && psCoeffs->dfMul2Y == 0.0)
     458             :         {
     459             :             // Degenerate triangle
     460      298860 :             continue;
     461             :         }
     462          20 :         l1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
     463          20 :         if (l1 < -EPS)
     464             :         {
     465           2 :             int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[0];
     466           2 :             if (neighbor < 0)
     467             :             {
     468           2 :                 *panOutputFacetIdx = nFacetIdx;
     469           2 :                 return FALSE;
     470             :             }
     471           0 :             continue;
     472             :         }
     473          18 :         if (l1 > 1 + EPS)
     474           7 :             continue;
     475          11 :         l2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
     476          11 :         if (l2 < -EPS)
     477             :         {
     478           3 :             int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[1];
     479           3 :             if (neighbor < 0)
     480             :             {
     481           2 :                 *panOutputFacetIdx = nFacetIdx;
     482           2 :                 return FALSE;
     483             :             }
     484           1 :             continue;
     485             :         }
     486           8 :         if (l2 > 1 + EPS)
     487           0 :             continue;
     488           8 :         l3 = BARYC_COORD_L3(l1, l2);
     489           8 :         if (l3 < -EPS)
     490             :         {
     491           4 :             int neighbor = psDT->pasFacets[nFacetIdx].anNeighborIdx[2];
     492           4 :             if (neighbor < 0)
     493             :             {
     494           0 :                 *panOutputFacetIdx = nFacetIdx;
     495           0 :                 return FALSE;
     496             :             }
     497           4 :             continue;
     498             :         }
     499           4 :         if (l3 > 1 + EPS)
     500           0 :             continue;
     501           4 :         *panOutputFacetIdx = nFacetIdx;
     502           4 :         return TRUE;
     503             :     }
     504       10697 :     return FALSE;
     505             : }
     506             : 
     507             : /************************************************************************/
     508             : /*               GDALTriangulationFindFacetDirected()                   */
     509             : /************************************************************************/
     510             : 
     511             : #define EPS 1e-10
     512             : 
     513             : /** Returns the index of the triangle that contains the point by walking in
     514             :  * the triangulation.
     515             :  *
     516             :  * If the function returns FALSE and *panOutputFacetIdx >= 0, then it means
     517             :  * the point is outside the hull of the triangulation, and *panOutputFacetIdx
     518             :  * is the closest triangle to the point.
     519             :  *
     520             :  * @param psDT triangulation.
     521             :  * @param nFacetIdx index of first triangle to start with.
     522             :  *                  Must be >= 0 && < psDT->nFacets
     523             :  * @param dfX x coordinate of the point.
     524             :  * @param dfY y coordinate of the point.
     525             :  * @param panOutputFacetIdx (output) pointer to the index of the triangle,
     526             :  *                          or -1 in case of failure.
     527             :  *
     528             :  * @return TRUE in case of success, FALSE otherwise.
     529             :  *
     530             :  * @since GDAL 2.1
     531             :  */
     532             : 
     533       25373 : int GDALTriangulationFindFacetDirected(const GDALTriangulation *psDT,
     534             :                                        int nFacetIdx, double dfX, double dfY,
     535             :                                        int *panOutputFacetIdx)
     536             : {
     537             : #ifdef DEBUG_VERBOSE
     538             :     const int nFacetIdxInitial = nFacetIdx;
     539             : #endif
     540             :     int k, nIterMax;
     541       25373 :     *panOutputFacetIdx = -1;
     542       25373 :     if (psDT->pasFacetCoefficients == NULL)
     543             :     {
     544           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     545             :                  "GDALTriangulationComputeBarycentricCoefficients() should be "
     546             :                  "called before");
     547           1 :         return FALSE;
     548             :     }
     549       25372 :     CPLAssert(nFacetIdx >= 0 && nFacetIdx < psDT->nFacets);
     550             : 
     551       25372 :     nIterMax = 2 + psDT->nFacets / 4;
     552       83687 :     for (k = 0; k < nIterMax; k++)
     553             :     {
     554             :         double l1, l2, l3;
     555       83686 :         int bMatch = TRUE;
     556       83686 :         const GDALTriFacet *psFacet = &(psDT->pasFacets[nFacetIdx]);
     557       83686 :         const GDALTriBarycentricCoefficients *psCoeffs =
     558       83686 :             &(psDT->pasFacetCoefficients[nFacetIdx]);
     559       83686 :         if (psCoeffs->dfMul1X == 0.0 && psCoeffs->dfMul2X == 0.0 &&
     560       10697 :             psCoeffs->dfMul1Y == 0.0 && psCoeffs->dfMul2Y == 0.0)
     561             :         {
     562             :             // Degenerate triangle
     563       10696 :             break;
     564             :         }
     565       72990 :         l1 = BARYC_COORD_L1(psCoeffs, dfX, dfY);
     566       72990 :         if (l1 < -EPS)
     567             :         {
     568       15500 :             int neighbor = psFacet->anNeighborIdx[0];
     569       15500 :             if (neighbor < 0)
     570             :             {
     571             : #ifdef DEBUG_VERBOSE
     572             :                 CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
     573             :                          nFacetIdx, k, nFacetIdxInitial);
     574             : #endif
     575         433 :                 *panOutputFacetIdx = nFacetIdx;
     576         433 :                 return FALSE;
     577             :             }
     578       15067 :             nFacetIdx = neighbor;
     579       15067 :             continue;
     580             :         }
     581       57490 :         else if (l1 > 1 + EPS)
     582       12974 :             bMatch = FALSE;  // outside or degenerate
     583             : 
     584       57490 :         l2 = BARYC_COORD_L2(psCoeffs, dfX, dfY);
     585       57490 :         if (l2 < -EPS)
     586             :         {
     587       21250 :             int neighbor = psFacet->anNeighborIdx[1];
     588       21250 :             if (neighbor < 0)
     589             :             {
     590             : #ifdef DEBUG_VERBOSE
     591             :                 CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
     592             :                          nFacetIdx, k, nFacetIdxInitial);
     593             : #endif
     594          27 :                 *panOutputFacetIdx = nFacetIdx;
     595          27 :                 return FALSE;
     596             :             }
     597       21223 :             nFacetIdx = neighbor;
     598       21223 :             continue;
     599             :         }
     600       36240 :         else if (l2 > 1 + EPS)
     601       11415 :             bMatch = FALSE;  // outside or degenerate
     602             : 
     603       36240 :         l3 = BARYC_COORD_L3(l1, l2);
     604       36240 :         if (l3 < -EPS)
     605             :         {
     606       22063 :             int neighbor = psFacet->anNeighborIdx[2];
     607       22063 :             if (neighbor < 0)
     608             :             {
     609             : #ifdef DEBUG_VERBOSE
     610             :                 CPLDebug("GDAL", "Outside %d in %d iters (initial = %d)",
     611             :                          nFacetIdx, k, nFacetIdxInitial);
     612             : #endif
     613          38 :                 *panOutputFacetIdx = nFacetIdx;
     614          38 :                 return FALSE;
     615             :             }
     616       22025 :             nFacetIdx = neighbor;
     617       22025 :             continue;
     618             :         }
     619       14177 :         else if (l3 > 1 + EPS)
     620           0 :             bMatch = FALSE;  // outside or degenerate
     621             : 
     622       14177 :         if (bMatch)
     623             :         {
     624             : #ifdef DEBUG_VERBOSE
     625             :             CPLDebug("GDAL", "Inside %d in %d iters (initial = %d)", nFacetIdx,
     626             :                      k, nFacetIdxInitial);
     627             : #endif
     628       14177 :             *panOutputFacetIdx = nFacetIdx;
     629       14177 :             return TRUE;
     630             :         }
     631             :         else
     632             :         {
     633           0 :             break;
     634             :         }
     635             :     }
     636             : 
     637             :     static int nDebugMsgCount = 0;
     638       10697 :     if (nDebugMsgCount <= 20)
     639             :     {
     640          21 :         CPLDebug("GDAL", "Using brute force lookup%s",
     641          21 :                  (nDebugMsgCount == 20)
     642             :                      ? " (this debug message will no longer be emitted)"
     643             :                      : "");
     644          21 :         nDebugMsgCount++;
     645             :     }
     646             : 
     647       10697 :     return GDALTriangulationFindFacetBruteForce(psDT, dfX, dfY,
     648             :                                                 panOutputFacetIdx);
     649             : }

Generated by: LCOV version 1.14