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