kriging.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /**
  2. *
  3. * kriging.js
  4. *
  5. * Copyright 2012
  6. */
  7. /* Extend the Array class */
  8. Array.prototype.max = function() {
  9. return Math.max.apply(null, this)
  10. }
  11. Array.prototype.min = function() {
  12. return Math.min.apply(null, this)
  13. }
  14. Array.prototype.mean = function() {
  15. for(var i=0, sum=0; i<this.length;i++) {
  16. sum += this[i];
  17. }
  18. return sum / this.length;
  19. }
  20. /**
  21. * Ported R functions
  22. */
  23. /* Repeat a value */
  24. var R_rep = function(x, times) {
  25. var i = new Array(times);
  26. for(var j=0; j<i.length; j++) {
  27. i[j] = x;
  28. }
  29. return i;
  30. }
  31. /* Matrix transpose */
  32. var R_t = function(x) {
  33. /* Must be a 2-dimensional matrix */
  34. var i, j, n, m;
  35. n = x.length;
  36. m = x[0].length;
  37. var y = new Array(m);
  38. for(i=0;i<m;i++) {
  39. y[i] = new Array(n);
  40. for(j=0;j<n;j++) {
  41. y[i][j] = x[j][i];
  42. }
  43. }
  44. return y;
  45. }
  46. /* Determinant */
  47. var R_det = function(x, n) {
  48. var i, j, k, l;
  49. var det = 0;
  50. var m = new Array(n-1);
  51. for(i=0;i<(n-1);i++) {
  52. m[i] = new Array(n-1);
  53. }
  54. if(n<1) return;
  55. else {
  56. if(n==1) det = x[0][0];
  57. else {
  58. if(n==2) det = x[0][0]*x[1][1] - x[1][0]*x[0][1];
  59. else {
  60. det = 0;
  61. for(i=0;i<n;i++) {
  62. for(j=1;j<n;j++) {
  63. k=0;
  64. for(l=0;l<n;l++) {
  65. if(l==i) continue;
  66. m[j-1][k] = x[j][l];
  67. k++;
  68. }
  69. }
  70. det += Math.pow(-1, i+2) * x[0][i] * R_det(m, n-1);
  71. }
  72. }
  73. }
  74. return det;
  75. }
  76. }
  77. /* Non-R function -- essential for R_solve_ */
  78. var cofactor = function(x, n) {
  79. var i, j, k, l, m, o;
  80. var det;
  81. var c = new Array(n-1);
  82. var y = new Array(n);
  83. for(i=0;i<n;i++) y[i] = new Array(n);
  84. for(i=0;i<(n-1);i++) c[i] = new Array(n-1);
  85. for(i=0;i<n;i++) {
  86. for(j=0;j<n;j++) {
  87. k=0;
  88. for(l=0;l<n;l++) {
  89. if(l==j) continue;
  90. m = 0;
  91. for(o=0;o<n;o++) {
  92. if(o==i) continue;
  93. c[k][m] = x[l][o];
  94. m++;
  95. }
  96. k++;
  97. }
  98. det = R_det(c, n-1);
  99. y[j][i] = Math.pow(-1, j+i+2) * det;
  100. }
  101. }
  102. return y;
  103. }
  104. /* Matrix inversion -- Gauss-jordan elimination */
  105. var R_solve = function(a) {
  106. var n = a.length;
  107. var m = n;
  108. var b = new Array(n);
  109. var indxc = new Array(n);
  110. var indxr = new Array(n);
  111. var ipiv = new Array(n);
  112. var i, icol, irow, j, k, l, ll;
  113. var big, dum, pivinv, temp;
  114. for(i=0;i<n;i++) {
  115. b[i] = new Array(n);
  116. for(j=0;j<n;j++) {
  117. if(i==j) b[i][j] = 1;
  118. else b[i][j] = 0;
  119. }
  120. }
  121. for(j=0;j<n;j++) ipiv[j] = 0;
  122. for(i=0;i<n;i++) {
  123. big = 0;
  124. for(j=0;j<n;j++) {
  125. if(ipiv[j]!=1) {
  126. for(k=0;k<n;k++) {
  127. if(ipiv[k]==0) {
  128. if(Math.abs(a[j][k])>=big) {
  129. big = Math.abs(a[j][k]);
  130. irow = j;
  131. icol = k;
  132. }
  133. }
  134. }
  135. }
  136. }
  137. ++(ipiv[icol]);
  138. if(irow!=icol) {
  139. for(l=0;l<n;l++) {
  140. temp = a[irow][l];
  141. a[irow][l] = a[icol][l];
  142. a[icol][l] = temp;
  143. }
  144. for(l=0;l<m;l++) {
  145. temp = b[irow][l];
  146. b[irow][l] = b[icol][l];
  147. b[icol][l] = temp;
  148. }
  149. }
  150. indxr[i] = irow;
  151. indxc[i] = icol;
  152. if(a[icol][icol]==0) { /* Singular matrix */
  153. return false;
  154. }
  155. pivinv = 1 / a[icol][icol];
  156. a[icol][icol] = 1;
  157. for(l=0;l<n;l++) a[icol][l] *= pivinv;
  158. for(l=0;l<m;l++) b[icol][l] *= pivinv;
  159. for(ll=0;ll<n;ll++) {
  160. if(ll!=icol) {
  161. dum = a[ll][icol];
  162. a[ll][icol] = 0;
  163. for(l=0;l<n;l++) a[ll][l] -= a[icol][l]*dum;
  164. for(l=0;l<m;l++) b[ll][l] -= b[icol][l]*dum;
  165. }
  166. }
  167. }
  168. for(l=(n-1);l>=0;l--) {
  169. if(indxr[l]!=indxc[l]) {
  170. for(k=0;k<n;k++) {
  171. temp = a[k][indxr[l]];
  172. a[k][indxr[l]] = a[k][indxc[l]];
  173. a[k][indxc[l]] = temp;
  174. }
  175. }
  176. }
  177. return a;
  178. }
  179. var R_solve_cramers_rule = function(x) {
  180. /* Solve to determine the adjunct matrix */
  181. var i, j;
  182. var adj = R_t(cofactor(x, x.length));
  183. var inv_det_a = 1 / R_det(x, x.length);
  184. var y = new Array(x.length);
  185. for(i=0;i<x.length;i++) {
  186. y[i] = new Array(x.length);
  187. for(j=0;j<x.length;j++) {
  188. y[i][j] = inv_det_a * adj[i][j];
  189. }
  190. }
  191. return y;
  192. }
  193. /* Fit a linear model */
  194. var R_lm = function(y, x) {
  195. var n = y.length;
  196. /* Add an intercept term to the design matrix */
  197. x = [R_rep(1, n), x];
  198. y = [y];
  199. /* OLS estimate */
  200. return matrixmult(matrixmult(R_solve(matrixmult(R_t(x), x)), R_t(x)), y);
  201. }
  202. /* Cluster analysis */
  203. var R_kmeans = function(x, y, centers) {
  204. }
  205. /**
  206. * Matrix multiplication
  207. */
  208. var matrixmult = function(y, x) {
  209. var i, j, k;
  210. var n = x.length;
  211. var m = x[0].length;
  212. if(m!=y.length) return false;
  213. var p = y[0].length;
  214. var z = new Array(n);
  215. for(i=0;i<n;i++) {
  216. z[i] = new Array(p);
  217. for(j=0;j<p;j++) {
  218. z[i][j] = 0;
  219. for(k=0;k<m;k++) {
  220. z[i][j] += x[i][k] * y[k][j];
  221. }
  222. }
  223. }
  224. return z;
  225. }
  226. /* Point-in-polygon */
  227. var pip = function(X, Y, x, y) {
  228. var i, j;
  229. var c = false;
  230. for(i=0, j=X.length-1; i<X.length; j = i++) {
  231. if( ((Y[i]>y) != (Y[j]>y)) && (x<(X[j]-X[i]) * (y-Y[i]) / (Y[j]-Y[i]) + X[i]) ) {
  232. c = !c;
  233. }
  234. }
  235. return c;
  236. }
  237. /**
  238. * Defines the kriging class
  239. *
  240. */
  241. function kriging(id, pixelsize) {
  242. /* Output testing */
  243. var o = document.getElementById("output");
  244. /* Global vars */
  245. var canvaspad = 50;
  246. var yxratio = 1;
  247. /* Canvas element */
  248. var canvasobj = document.getElementById(id);
  249. this.canvas = document.getElementById(id);
  250. this.canvas.ctx = this.canvas.getContext("2d");
  251. /* New objects */
  252. this.canvas.model = new Object();
  253. /* Kriging method
  254. * Usage: kriging(longitude, latitude, response, polygons)
  255. */
  256. this.krig = function(x, y, response, polygons) {
  257. /* Bring the polygons and frame properties into the DOM */
  258. this.canvas.model.x = x;
  259. this.canvas.model.y = y;
  260. this.canvas.model.response = response;
  261. this.canvas.model.response_min = response.min();
  262. this.canvas.model.response_max = response.max();
  263. this.canvas.model.response_range = response.max() - response.min();
  264. this.canvas.polygons = polygons;
  265. /**
  266. * Calculate the euclidean distance matrix for the coordinates
  267. * and the outcome variable
  268. */
  269. this.canvas.model.n = response.length;
  270. var i, j, k;
  271. var D = new Array(this.canvas.model.n);
  272. var V = new Array(this.canvas.model.n);
  273. for(i=0; i<this.canvas.model.n; i++) {
  274. D[i] = new Array(this.canvas.model.n);
  275. V[i] = new Array(this.canvas.model.n);
  276. for(j=0; j<this.canvas.model.n; j++) {
  277. D[i][j] = Math.sqrt(Math.pow(x[i]-x[j], 2) + Math.pow(y[i]-y[j], 2));
  278. V[i][j] = Math.abs(response[i] - response[j]);
  279. }
  280. }
  281. /* Fit the observations to the variogram */
  282. var lags = 10;
  283. var sum_z, n_h;
  284. this.canvas.model.semivariance = new Array();
  285. this.canvas.model.distance = new Array();
  286. var cutoff = Math.sqrt(Math.pow(x.max() - x.min(), 2) + Math.pow(y.max() - y.min(), 2)) / 3;
  287. for(i=0; i<lags; i++) {
  288. sum_z = 0;
  289. n_h = 0;
  290. for(j=0; j<this.canvas.model.n; j++) {
  291. for(k=j+1; k<this.canvas.model.n; k++) {
  292. if(D[j][k] <= ((i+1)*cutoff/lags)) {
  293. sum_z += Math.pow(V[j][k], 2);
  294. n_h++;
  295. }
  296. }
  297. }
  298. if(!isNaN(sum_z / n_h)) {
  299. this.canvas.model.semivariance.push(sum_z / n_h);
  300. this.canvas.model.distance.push((i+1)*cutoff/lags);
  301. }
  302. }
  303. /* Check for enough points in the lag model */
  304. if(this.canvas.model.semivariance.length<3) {
  305. /* ERROR -- quit app */
  306. }
  307. /* Estimate the model parameters */
  308. var coef = R_lm(this.canvas.model.semivariance, this.canvas.model.distance);
  309. this.canvas.model.nugget = 0; //coef[0][0]; /* Intercept */
  310. this.canvas.model.range = this.canvas.model.distance.max();
  311. this.canvas.model.sill = this.canvas.model.semivariance.max()-this.canvas.model.nugget;//coef[0][1] * this.canvas.model.range;
  312. /**
  313. * Calculate the inverted (n+1) x (n+1) matrix
  314. * Used to calculate weights
  315. */
  316. var X = new Array(this.canvas.model.n+1);
  317. for(i=0;i<=this.canvas.model.n;i++) {
  318. X[i] = new Array(this.canvas.model.n+1);
  319. for(j=0;j<=this.canvas.model.n;j++) {
  320. if(i==this.canvas.model.n && j!=this.canvas.model.n) X[i][j] = 1;
  321. else {
  322. if(i!=this.canvas.model.n && j==this.canvas.model.n) X[i][j] = 1;
  323. else {
  324. if(i==this.canvas.model.n && j==this.canvas.model.n) X[i][j] = 0;
  325. else {
  326. X[i][j] = this.canvas.model.spherical(D[i][j]);
  327. }
  328. }
  329. }
  330. }
  331. }
  332. /* Invert the matrix */
  333. this.canvas.model.X_inv = R_solve(X);
  334. }
  335. /* Variogram models */
  336. this.canvas.model.exponential = function(h) {
  337. if(h==0) return 0;
  338. else {
  339. return this.nugget + (this.sill - this.nugget) * (1 - Math.exp((-3*Math.abs(h)) / this.range));
  340. }
  341. }
  342. this.canvas.model.spherical = function(h) {
  343. if(h>this.range) return this.sill;
  344. if(h<=this.range && h>0) {
  345. return this.nugget + (this.sill - this.nugget) * ((3*h)/(2*this.range) - Math.pow(h, 3) / (2*Math.pow(this.range, 3)));
  346. }
  347. else return 0;
  348. }
  349. /* Model prediction method */
  350. this.canvas.model.pred = function(x, y) {
  351. var i;
  352. var L = R_rep(1, this.n+1);
  353. for(i=0;i<this.n;i++) {
  354. L[i] = this.spherical(Math.sqrt(Math.pow(this.x[i] - x, 2) + Math.pow(this.y[i] - y, 2)))
  355. }
  356. var R = matrixmult(this.X_inv, [L])[0];
  357. R.pop();
  358. return matrixmult(R_t([R]), [this.response])[0][0];
  359. }
  360. /**
  361. * Set up the map properties, event handlers and initialize the map.
  362. */
  363. this.map = function(center, zoom) {
  364. /* Set up the canvas frame */
  365. this.canvas.height = window.innerHeight - this.canvas.offsetTop - 20;
  366. this.canvas.width = window.innerWidth - this.canvas.offsetLeft - 20;
  367. this.canvas.style.border = "";
  368. /**
  369. * Loop through the polygons to determine the limits based on the
  370. * area of each of the polygons.
  371. * AND
  372. * Create an Array containing the center coordinates for each polygon
  373. * to be used during the sorting algorithm.
  374. */
  375. var i, j;
  376. this.canvas.polygoncenters = new Array(this.canvas.polygons.length);
  377. this.canvas.polygonsorted = new Array(this.canvas.polygons.length);
  378. for(i=0;i<this.canvas.polygons.length;i++) {
  379. if(i==0) {
  380. this.canvas.xlim = [this.canvas.polygons[i][0].min(), this.canvas.polygons[i][0].max()];
  381. }
  382. else {
  383. if(this.canvas.polygons[i][0].min()<this.canvas.xlim[0]) this.canvas.xlim[0] = this.canvas.polygons[i][0].min();
  384. if(this.canvas.polygons[i][0].max()>this.canvas.xlim[1]) this.canvas.xlim[1] = this.canvas.polygons[i][0].max();
  385. }
  386. this.canvas.polygoncenters[i] = [this.canvas.polygons[i][0].mean(), this.canvas.polygons[i][1].mean()];
  387. this.canvas.polygonsorted[i] = 0;
  388. }
  389. /**
  390. * Calculate the ratio and pixel size for conversion
  391. * between units.
  392. */
  393. this.canvas.xratio = (this.canvas.xlim[1]-this.canvas.xlim[0]) / this.canvas.width;
  394. this.canvas.yratio = this.canvas.xratio * yxratio;
  395. this.canvas.xlim = [center[0] - 0.5 * this.canvas.width * this.canvas.xratio, center[0] + 0.5 * this.canvas.width * this.canvas.xratio];
  396. this.canvas.ylim = [center[1] - 0.5 * this.canvas.height * this.canvas.yratio, center[1] + 0.5 * this.canvas.height * this.canvas.yratio];
  397. this.canvas.xpixel = pixelsize * this.canvas.xratio;
  398. this.canvas.ypixel = pixelsize * this.canvas.yratio;
  399. /* Start the map */
  400. this.canvas.zoom(zoom, yxratio, pixelsize);
  401. }
  402. /**
  403. * Navigation
  404. */
  405. this.canvas.zoom = function(zoom, yxratio, pixelsize) {
  406. /* Re-size the limits */
  407. var newlen = [zoom * (this.xlim[1]-this.xlim[0])/2,
  408. zoom * (this.ylim[1]-this.ylim[0])/2];
  409. var center = [(this.xlim[1]-this.xlim[0])/2 + this.xlim[0],
  410. (this.ylim[1]-this.ylim[0])/2 + this.ylim[0]];
  411. /* Reset the properties */
  412. this.xlim = [center[0]-newlen[0], center[0]+newlen[0]];
  413. this.ylim = [center[1]-newlen[1], center[1]+newlen[1]];
  414. this.xratio = (this.xlim[1]-this.xlim[0]) / this.width;
  415. this.yratio = this.xratio * yxratio;
  416. this.xpixel = pixelsize * this.xratio;
  417. this.ypixel = pixelsize * this.yratio;
  418. /* Render the map */
  419. this.render();
  420. }
  421. /**
  422. * Methods for drawing onto the canvas
  423. */
  424. /* Color spectrums */
  425. this.canvas.colorspectrum = new Object();
  426. this.canvas.colorspectrum.heatcolors = ["#FF0000", "#FF0700", "#FF0E00", "#FF1500", "#FF1C00", "#FF2200", "#FF2900", "#FF3000", "#FF3700", "#FF3E00", "#FF4500", "#FF4C00", "#FF5300", "#FF5A00", "#FF6000", "#FF6700", "#FF6E00", "#FF7500", "#FF7C00", "#FF8300", "#FF8A00", "#FF9100", "#FF9800", "#FF9F00", "#FFA500", "#FFAC00", "#FFB300", "#FFBA00", "#FFC100", "#FFC800", "#FFCF00", "#FFD600", "#FFDD00", "#FFE300", "#FFEA00", "#FFF100", "#FFF800", "#FFFF00", "#FFFF0B", "#FFFF20", "#FFFF35", "#FFFF4A", "#FFFF60", "#FFFF75", "#FFFF8A", "#FFFF9F", "#FFFFB5", "#FFFFCA", "#FFFFDF", "#FFFFF4"];
  427. this.canvas.colorspectrum.terraincolors = ["#00A600", "#07A800", "#0EAB00", "#16AE00", "#1DB000", "#25B300", "#2DB600", "#36B800", "#3EBB00", "#47BE00", "#50C000", "#59C300", "#63C600", "#6CC800", "#76CB00", "#80CE00", "#8BD000", "#95D300", "#A0D600", "#ABD800", "#B6DB00", "#C2DE00", "#CEE000", "#D9E300", "#E6E600", "#E6DD09", "#E7D612", "#E7CF1C", "#E8C825", "#E8C32E", "#E9BE38", "#E9BA41", "#EAB74B", "#EAB454", "#EBB25E", "#EBB167", "#ECB171", "#ECB17B", "#EDB285", "#EDB48E", "#EEB798", "#EEBAA2", "#EFBFAC", "#EFC4B6", "#F0C9C0", "#F0D0CA", "#F1D7D4", "#F1DFDE", "#F2E8E8", "#F2F2F2"];
  428. this.canvas.colorspectrum.topocolors = ["#4C00FF", "#3B00FF", "#2800FF", "#1600FF", "#0400FF", "#000DFF", "#001FFF", "#0032FF", "#0043FF", "#0055FF", "#0068FF", "#007AFF", "#008BFF", "#009EFF", "#00AFFF", "#00C1FF", "#00D3FF", "#00E5FF", "#00FF4D", "#00FF38", "#00FF24", "#00FF0F", "#05FF00", "#1AFF00", "#2EFF00", "#42FF00", "#57FF00", "#6BFF00", "#80FF00", "#94FF00", "#A8FF00", "#BDFF00", "#D1FF00", "#E6FF00", "#FFFF00", "#FFF90C", "#FFF318", "#FFED24", "#FFE930", "#FFE53B", "#FFE247", "#FFDF53", "#FFDD5F", "#FFDC6B", "#FFDB77", "#FFDB83", "#FFDB8F", "#FFDC9B", "#FFDEA7", "#FFE0B3"];
  429. this.canvas.colorspectrum.cmcolors = ["#80FFFF", "#85FFFF", "#8AFFFF", "#8FFFFF", "#94FFFF", "#99FFFF", "#9EFFFF", "#A3FFFF", "#A8FFFF", "#ADFFFF", "#B3FFFF", "#B8FFFF", "#BDFFFF", "#C2FFFF", "#C7FFFF", "#CCFFFF", "#D1FFFF", "#D6FFFF", "#DBFFFF", "#E0FFFF", "#E6FFFF", "#EBFFFF", "#F0FFFF", "#F5FFFF", "#FAFFFF", "#FFFAFF", "#FFF5FF", "#FFF0FF", "#FFEBFF", "#FFE6FF", "#FFE0FF", "#FFDBFF", "#FFD6FF", "#FFD1FF", "#FFCCFF", "#FFC7FF", "#FFC2FF", "#FFBDFF", "#FFB8FF", "#FFB3FF", "#FFADFF", "#FFA8FF", "#FFA3FF", "#FF9EFF", "#FF99FF", "#FF94FF", "#FF8FFF", "#FF8AFF", "#FF85FF", "#FF80FF"];
  430. this.canvas.render = function() {
  431. this.clear();
  432. this.background();
  433. this.points();
  434. }
  435. this.canvas.pixel = function(x, y, col) {
  436. this.ctx.fillStyle = col;
  437. /* Spaced-out pixels */
  438. //this.ctx.fillRect((x-this.xlim[0])/this.xratio - pixelsize/2 + 1, this.height - (y-this.ylim[0])/this.yratio - pixelsize/2 + 1, pixelsize - 2, pixelsize - 2);
  439. /* Solid map */
  440. this.ctx.fillRect((x-this.xlim[0])/this.xratio - pixelsize/2, this.height - (y-this.ylim[0])/this.yratio - pixelsize/2, pixelsize, pixelsize);
  441. }
  442. this.canvas.focus = function(x, y, v, col) {
  443. this.ctx.beginPath();
  444. this.ctx.arc((x-this.xlim[0])/this.xratio, this.height - (y-this.ylim[0])/this.yratio, 2, 0, 2 * Math.PI, false);
  445. this.ctx.fillStyle = col;
  446. this.ctx.fill();
  447. this.ctx.fillText( Math.round(v*100)/100, (x - this.xlim[0]) / this.xratio - (2 * pixelsize) / 2 +5, 3+ this.height - (y - this.ylim[0]) / this.yratio - (2 * pixelsize) / 2 )
  448. }
  449. this.canvas.clear = function() {
  450. this.ctx.clearRect(0, 0, this.width, this.height);
  451. }
  452. /* Plot observed points */
  453. this.canvas.points = function() {
  454. var i;
  455. for(i=0;i<this.model.n;i++) {
  456. this.focus(this.model.x[i], this.model.y[i], this.model.response[i], "black");
  457. }
  458. }
  459. /* Fills the background with the polygons */
  460. this.canvas.background = function() {
  461. /**
  462. * 1) Nearest-neighbor
  463. * 2) Loop through sorted polygons
  464. * 3) Point-in-polygon for eligible points
  465. * 4) Break if no points in polygon
  466. */
  467. var i, j, k;
  468. for(i=0; i<this.polygoncenters.length; i++) {
  469. this.polygonsorted[i] = Math.sqrt(Math.pow(this.polygoncenters[i][0] - this.xlim.mean(), 2) + Math.pow(this.polygoncenters[i][1] - this.ylim.mean(), 2));
  470. }
  471. var maxVal = this.polygonsorted.max();
  472. var nearest = this.polygonsorted.indexOf(this.polygonsorted.min());
  473. var xbox = [0,0];
  474. var ybox = [0,0];
  475. var color;
  476. for(i=0;i<this.polygons.length;i++) {
  477. /* Calculate the intersecting box */
  478. if(this.xlim[0]>this.polygons[nearest][0].min()) xbox[0] = this.xpixel * Math.floor(this.xlim[0]/this.xpixel);
  479. else xbox[0] = this.xpixel * Math.floor(this.polygons[nearest][0].min()/this.xpixel);
  480. if(this.xlim[1]<this.polygons[nearest][0].max()) xbox[1] = this.xpixel * Math.ceil(this.xlim[1]/this.xpixel);
  481. else xbox[1] = this.xpixel * Math.ceil(this.polygons[nearest][0].max()/this.xpixel);
  482. if(this.ylim[0]>this.polygons[nearest][1].min()) ybox[0] = this.ypixel * Math.floor(this.ylim[0]/this.ypixel);
  483. else ybox[0] = this.ypixel * Math.floor(this.polygons[nearest][1].min()/this.ypixel);
  484. if(this.ylim[0]<this.polygons[nearest][1].max()) ybox[1] = this.ypixel * Math.ceil(this.ylim[1]/this.ypixel);
  485. else ybox[1] = this.ypixel * Math.ceil(this.polygons[nearest][1].max()/this.ypixel);
  486. for(j = xbox[0]; j <= xbox[1]; j += this.xpixel) {
  487. for(k = ybox[0]; k <= ybox[1]; k += this.ypixel) {
  488. if(pip(this.polygons[nearest][0], this.polygons[nearest][1], j, k)) {
  489. color = Math.round(49 * (this.model.pred(j, k) - this.model.response_min) / (this.model.response_range));
  490. if(color<0) color = 0;
  491. else if(color>49) color = 49;
  492. this.pixel(j, k, this.colorspectrum.terraincolors[color])
  493. }
  494. }
  495. }
  496. this.polygonsorted[nearest] = maxVal;
  497. nearest = this.polygonsorted.indexOf(this.polygonsorted.min());
  498. }
  499. }
  500. return true;
  501. }