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

Generated by: LCOV version 1.14