1 /*
2 
3   Copyright (C) 2002-2011, 2017 Andreas Stahel
4   Copyright (C) 2011-2017 David Sterratt
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; either version 3 of the License, or (at your
9   option) any later version.
10 
11   This program is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program. If not, see
18   <http://www.gnu.org/licenses/>.
19 
20 */
21 
22 /* Originally written for Octave */
23 /* Author: Andreas Stahel <Andreas.Stahel@hta-bi.bfh.ch> */
24 /* 19 August 2011: Ported to R by David Sterratt <david.c.sterratt@ed.ac.uk> */
25 
26 #include <R.h>
27 #include <Rdefines.h>
28 #include <R_ext/Rdynload.h>
29 #include <Rinternals.h>
30 #include "Rgeometry.h"
31 #include "qhull_ra.h"
32 
max(double a,double b,double c)33 static inline double max (double a, double b, double c)
34 {
35   if (a < b)
36     return (b < c ? c : b);
37   else
38     return (a < c ? c : a);
39 }
40 
min(double a,double b,double c)41 static inline double min (double a, double b, double c)
42 {
43   if (a > b)
44     return (b > c ? c : b);
45   else
46     return (a > c ? c : a);
47 }
48 
49 
50 #define REF(x,k,i) x[ielem[k + i*nelem] - 1]
51 
52 /* for large data set the algorithm is very slow one should presort
53  (how?) either the elements of the points of evaluation to cut down
54  the time needed to decide which triangle contains the given point
55 
56  e.g., build up a neighbouring triangle structure and use a simplex-like
57  method to traverse it
58 */
59 
C_tsearch_orig(SEXP x,SEXP y,SEXP elem,SEXP xi,SEXP yi,SEXP bary)60 SEXP C_tsearch_orig(SEXP x,  SEXP y, SEXP elem,
61                     SEXP xi, SEXP yi,
62                     SEXP bary) {
63   int ibary = 0;
64   if (isLogical(bary))
65     if (*LOGICAL(bary) == TRUE)
66       ibary = 1;
67 
68   /* printf("Here 1\n"); */
69   double *rx = REAL(x);
70   double *ry = REAL(y);
71   int nelem = nrows(elem);
72   int *ielem = INTEGER(elem);
73   double *rxi = REAL(xi);
74   double *ryi = REAL(yi);
75   int np = LENGTH(xi);
76   /* printf("%i points\n", np); */
77   SEXP minx, maxx, miny, maxy;
78   PROTECT(minx = allocVector(REALSXP, nelem));
79   PROTECT(maxx = allocVector(REALSXP, nelem));
80   PROTECT(miny = allocVector(REALSXP, nelem));
81   PROTECT(maxy = allocVector(REALSXP, nelem));
82   double *rminx = REAL(minx);
83   double *rmaxx = REAL(maxx);
84   double *rminy = REAL(miny);
85   double *rmaxy = REAL(maxy);
86 
87   /* Find bounding boxes of each triangle */
88   for (int k = 0; k < nelem; k++) {
89     /* printf("X[T[%i, 1]] = %f; T[%i, 1] = %i\n", k+1, REF(rx, k, 0), k+1, ielem[k + 0*nelem]); */
90     rminx[k] = min(REF(rx, k, 0), REF(rx, k, 1), REF(rx, k, 2)) - DOUBLE_EPS;
91     rmaxx[k] = max(REF(rx, k, 0), REF(rx, k, 1), REF(rx, k, 2)) + DOUBLE_EPS;
92     rminy[k] = min(REF(ry, k, 0), REF(ry, k, 1), REF(ry, k, 2)) - DOUBLE_EPS;
93     rmaxy[k] = max(REF(ry, k, 0), REF(ry, k, 1), REF(ry, k, 2)) + DOUBLE_EPS;
94     /* printf("%f %f %f %f\n", rminx[k], rmaxx[k], rminy[k], rmaxy[k]); */
95   }
96 
97   /* Make space for output */
98   SEXP values;
99   PROTECT(values = allocVector(INTSXP, np));
100   int *ivalues = INTEGER(values);
101   SEXP p = NULL;
102   double *rp = NULL;
103   if (ibary) {
104     PROTECT(p = allocMatrix(REALSXP, np, 3));
105     rp = REAL(p);
106     for (int k = 0; k < 3*np; k++)
107       rp[k] = NA_REAL;
108   }
109 
110   double x0 = 0.0, y0 = 0.0;
111   double a11 = 0.0, a12 = 0.0, a21 = 0.0, a22 = 0.0, det = 0.0;
112 
113   double xt, yt;
114   double dx1, dx2, c1, c2;
115   int k = nelem; // k is a counter of elements
116   for (int kp = 0; kp < np; kp++) {
117     xt = rxi[kp];
118     yt = ryi[kp];
119 
120     /* check if last triangle contains the next point */
121     if (k < nelem) {
122       dx1 = xt - x0;
123       dx2 = yt - y0;
124       c1 = ( a22 * dx1 - a21 * dx2) / det;
125       c2 = (-a12 * dx1 + a11 * dx2) / det;
126       if ((c1 >= -DOUBLE_EPS) && (c2 >= -DOUBLE_EPS) && ((c1 + c2) <= (1 + DOUBLE_EPS))) {
127         ivalues[kp] = k+1;
128         if (ibary) {
129           rp[kp] = 1 - c1 - c2;
130           rp[kp+np] = c1;
131           rp[kp+2*np] = c2;
132         }
133         continue;
134       }
135     }
136 
137     // it doesn't, so go through all elements
138     for (k = 0; k < nelem; k++) {
139       /* OCTAVE_QUIT; */
140       if (xt >= rminx[k] && xt <= rmaxx[k] && yt >= rminy[k] && yt <= rmaxy[k]) {
141         /* printf("Point %i (%1.3f, %1.3f) could be in triangle %i (%1.3f, %1.3f) (%1.3f, %1.3f)\n",  */
142         /*        kp+1, xt, yt, k+1, rminx[k], rminy[k], rmaxx[k], rmaxy[k]); */
143         // element inside the minimum rectangle: examine it closely
144         x0  = REF(rx, k, 0);
145         y0  = REF(ry, k, 0);
146         /* printf("Triangle %i: x0=%f, y0=%f\n", k+1, x0, y0); */
147         a11 = REF(rx, k, 1) - x0;
148         a12 = REF(ry, k, 1) - y0;
149         a21 = REF(rx, k, 2) - x0;
150         a22 = REF(ry, k, 2) - y0;
151         det = a11 * a22 - a21 * a12;
152 
153         // solve the system
154         dx1 = xt - x0;
155         dx2 = yt - y0;
156         c1 = ( a22 * dx1 - a21 * dx2) / det;
157         c2 = (-a12 * dx1 + a11 * dx2) / det;
158         if ((c1 >= -DOUBLE_EPS) && (c2 >= -DOUBLE_EPS) && ((c1 + c2) <= (1 + DOUBLE_EPS))) {
159           /* printf("Setting point %i's triangle to %i\n", kp+1, k+1);  */
160           ivalues[kp] = k+1;
161           if (ibary) {
162             rp[kp] = 1 - c1 - c2;
163             rp[kp+np] = c1;
164             rp[kp+2*np] = c2;
165           }
166           break;
167         }
168       } //endif # examine this element closely
169     } //endfor # each element
170     /* printf("%i\n", kp); */
171     if (k == nelem) {
172       ivalues[kp] = NA_INTEGER;
173     }
174   } //endfor # kp
175 
176   SEXP ans;
177   if (ibary) {
178     PROTECT(ans = allocVector(VECSXP, 2));
179     SET_VECTOR_ELT(ans, 0, values);
180     SET_VECTOR_ELT(ans, 1, p);
181     UNPROTECT(7);
182     return(ans);
183   } else {
184     UNPROTECT(5);
185     return(values);
186   }
187 }
188