PageRenderTime 149ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/alaspatial/src/main/java/org/ala/spatial/util/SimpleRegion.java

http://alageospatialportal.googlecode.com/
Java | 1665 lines | 1352 code | 58 blank | 255 comment | 171 complexity | 4ebb7388708c9748ec323c8d96270f30 MD5 | raw file
  1. package org.ala.spatial.util;
  2. import java.awt.image.BufferedImage;
  3. import java.io.File;
  4. import java.io.Serializable;
  5. import java.util.ArrayList;
  6. import java.util.HashMap;
  7. import javax.imageio.ImageIO;
  8. import org.ala.spatial.analysis.cluster.SpatialCluster3;
  9. /**
  10. * SimpleRegion enables point to shape intersections, where the shape
  11. * is stored within SimpleRegion as a circle, bounding box or polygon.
  12. *
  13. * Other utilities include shape presence on a defined grid;
  14. * fully present, partially present, absent.
  15. *
  16. * @author Adam Collins
  17. */
  18. public class SimpleRegion extends Object implements Serializable {
  19. static final long serialVersionUID = -5509351896749940566L;
  20. /**
  21. * shape type not declared
  22. */
  23. public static final int UNDEFINED = 0;
  24. /**
  25. * shape type bounding box; upper, lower, left, right
  26. */
  27. public static final int BOUNDING_BOX = 1;
  28. /**
  29. * shape type circle; point and radius
  30. */
  31. public static final int CIRCLE = 2;
  32. /**
  33. * shape type polygon; list of points as longitude, latitude pairs
  34. * last point == first point
  35. */
  36. public static final int POLYGON = 3;
  37. /**
  38. * UNDEFINED state for grid intersection output
  39. *
  40. * can be considered ABSENCE
  41. */
  42. public static final int GI_UNDEFINED = 0;
  43. /**
  44. * PARTiALLy PRESENT state for grid intersection output
  45. */
  46. public static final int GI_PARTIALLY_PRESENT = 1;
  47. /**
  48. * FULLY PRESENT state for grid intersection output
  49. */
  50. public static final int GI_FULLY_PRESENT = 2;
  51. /**
  52. * ABSENCE state for grid intersection output
  53. */
  54. public static final int GI_ABSENCE = 0;
  55. /**
  56. * assigned shape type
  57. */
  58. int type;
  59. /**
  60. * points store
  61. * BOUNDING_BOX = double [2][2]
  62. * CIRCLE = double [1][2]
  63. * POLYGON, n points (start = end) = double[n][2]
  64. */
  65. float[][] points;
  66. /**
  67. * for point/grid to polygon intersection method
  68. *
  69. * polygon edges as lines of the form <code>y = a*x + b</code>
  70. * lines = double [n][2]
  71. * where
  72. * n is number of edges
  73. * value at [0] is <code>a</code>
  74. * value at [1] is <code>b</code>
  75. */
  76. float[][] lines2;
  77. /**
  78. * bounding box for types BOUNDING_BOX and POLYGON
  79. *
  80. * bounding_box = double [2][2]
  81. * where
  82. * [0][0] = minimum longitude
  83. * [0][1] = minimum latitude
  84. * [1][0] = maximum longitude
  85. * [1][1] = maximum latitude
  86. */
  87. double[][] bounding_box; //for polygons
  88. /**
  89. * radius for type CIRCLE in m
  90. *
  91. */
  92. double radius;
  93. /**
  94. * misc attributes
  95. */
  96. HashMap<String, Object> attributes;
  97. /**
  98. * Constructor for a SimpleRegion with no shape
  99. */
  100. public SimpleRegion() {
  101. type = UNDEFINED;
  102. }
  103. /**
  104. * gets number of points for type POLYGON
  105. *
  106. * note: first point = last point
  107. *
  108. * @return number of points as int
  109. */
  110. public int getNumberOfPoints() {
  111. return points.length;
  112. }
  113. /**
  114. * gets the bounding box for types POLYGON and BOUNDING_BOX
  115. *
  116. * @return bounding box as double[2][2]
  117. * with [][0] longitude and [][1] latitude
  118. * minimum values at [0][], maximum values at [1][0]
  119. */
  120. public double[][] getBoundingBox() {
  121. return bounding_box;
  122. }
  123. /**
  124. * defines the SimpleRegion as type BOUNDING_BOX
  125. *
  126. * @param longitude1
  127. * @param latitude1
  128. * @param longitude2
  129. * @param latitude2
  130. */
  131. public void setBox(double longitude1, double latitude1, double longitude2, double latitude2) {
  132. type = BOUNDING_BOX;
  133. points = new float[2][2];
  134. points[0][0] = (float) Math.min(longitude1, longitude2);
  135. points[0][1] = (float) Math.min(latitude1, latitude2);
  136. points[1][0] = (float) Math.max(longitude1, longitude2);
  137. points[1][1] = (float) Math.max(latitude1, latitude2);
  138. for (int i = 0; i < points.length; i++) {
  139. //fix at -180 and 180
  140. if (points[i][0] < -180) {
  141. points[i][0] = -180;
  142. }
  143. if (points[i][0] > 180) {
  144. points[i][0] = 180;
  145. }
  146. while (points[i][1] < -180) {
  147. points[i][1] = -180;
  148. }
  149. while (points[i][1] > 180) {
  150. points[i][1] = 180;
  151. }
  152. }
  153. bounding_box = new double[2][2];
  154. bounding_box[0][0] = points[0][0];
  155. bounding_box[0][1] = points[0][1];
  156. bounding_box[1][0] = points[1][0];
  157. bounding_box[1][1] = points[1][1];
  158. }
  159. /**
  160. * defines the SimpleRegion as type UNDEFINED
  161. */
  162. public void setNone() {
  163. type = UNDEFINED;
  164. }
  165. /**
  166. * defines the SimpleRegion as type CIRCLE
  167. *
  168. * @param longitude
  169. * @param latitude
  170. * @param radius_ radius of the circle in m
  171. */
  172. public void setCircle(double longitude, double latitude, double radius_) {
  173. type = CIRCLE;
  174. points = new float[1][2];
  175. points[0][0] = (float) longitude;
  176. points[0][1] = (float) latitude;
  177. radius = radius_;
  178. }
  179. /**
  180. * defines the SimpleRegion as type POLYGON
  181. *
  182. * @param points_ array of points as longitude and latiude
  183. * in double [n][2] where n is the number of points
  184. */
  185. public void setPolygon(double[][] points_) {
  186. if (points_ != null && points_.length > 1) {
  187. type = POLYGON;
  188. int i;
  189. for (i = 0; i < points_.length; i++) {
  190. //fix at -180 and 180
  191. if (points_[i][0] < -180) {
  192. points_[i][0] = -180;
  193. }
  194. if (points_[i][0] > 180) {
  195. points_[i][0] = 180;
  196. }
  197. while (points_[i][1] < -180) {
  198. points_[i][1] = -180;
  199. }
  200. while (points_[i][1] > 180) {
  201. points_[i][1] = 180;
  202. }
  203. }
  204. /* copy and ensure last point == first point */
  205. int len = points_.length - 1;
  206. if (points_[0][0] != points_[len][0] || points_[0][1] != points_[len][1]) {
  207. points = new float[points_.length + 1][2];
  208. for (i = 0; i < points_.length; i++) {
  209. points[i][0] = (float) points_[i][0];
  210. points[i][1] = (float) points_[i][1];
  211. }
  212. points[points_.length][0] = (float) points_[0][0];
  213. points[points_.length][1] = (float) points_[0][1];
  214. } else {
  215. points = new float[points_.length][2];
  216. for (i = 0; i < points_.length; i++) {
  217. points[i][0] = (float) points_[i][0];
  218. points[i][1] = (float) points_[i][1];
  219. }
  220. }
  221. /* bounding box setup */
  222. bounding_box = new double[2][2];
  223. bounding_box[0][0] = points[0][0];
  224. bounding_box[0][1] = points[0][1];
  225. bounding_box[1][0] = points[0][0];
  226. bounding_box[1][1] = points[0][1];
  227. for (i = 1; i < points.length; i++) {
  228. if (bounding_box[0][0] > points[i][0]) {
  229. bounding_box[0][0] = points[i][0];
  230. }
  231. if (bounding_box[1][0] < points[i][0]) {
  232. bounding_box[1][0] = points[i][0];
  233. }
  234. if (bounding_box[0][1] > points[i][1]) {
  235. bounding_box[0][1] = points[i][1];
  236. }
  237. if (bounding_box[1][1] < points[i][1]) {
  238. bounding_box[1][1] = points[i][1];
  239. }
  240. }
  241. // intersection method precalculated data
  242. lines2 = new float[points.length][2]; //lines[0][] is not used
  243. for (i = 0; i < points.length - 1; i++) {
  244. lines2[i + 1][0] = (points[i][1] - points[i + 1][1])
  245. / (points[i][0] - points[i + 1][0]); //slope
  246. lines2[i + 1][1] = points[i][1] - lines2[i + 1][0] * points[i][0]; //intercept
  247. }
  248. }
  249. }
  250. /**
  251. * defines the SimpleRegion as type POLYGON
  252. *
  253. * @param points_ array of points as longitude and latiude
  254. * in double [n][2] where n is the number of points
  255. */
  256. public void setPolygon(float[][] points_) {
  257. if (points_ != null && points_.length > 1) {
  258. type = POLYGON;
  259. int i;
  260. for (i = 0; i < points_.length; i++) {
  261. //fix at -180 and 180
  262. if (points_[i][0] < -180) {
  263. points_[i][0] = -180;
  264. }
  265. if (points_[i][0] > 180) {
  266. points_[i][0] = 180;
  267. }
  268. while (points_[i][1] < -180) {
  269. points_[i][1] = -180;
  270. }
  271. while (points_[i][1] > 180) {
  272. points_[i][1] = 180;
  273. }
  274. }
  275. /* copy and ensure last point == first point */
  276. int len = points_.length - 1;
  277. if (points_[0][0] != points_[len][0] || points_[0][1] != points_[len][1]) {
  278. points = new float[points_.length + 1][2];
  279. for (i = 0; i < points_.length; i++) {
  280. points[i][0] = (float) points_[i][0];
  281. points[i][1] = (float) points_[i][1];
  282. }
  283. points[points_.length][0] = (float) points_[0][0];
  284. points[points_.length][1] = (float) points_[0][1];
  285. } else {
  286. points = new float[points_.length][2];
  287. for (i = 0; i < points_.length; i++) {
  288. points[i][0] = (float) points_[i][0];
  289. points[i][1] = (float) points_[i][1];
  290. }
  291. }
  292. /* bounding box setup */
  293. bounding_box = new double[2][2];
  294. bounding_box[0][0] = points[0][0];
  295. bounding_box[0][1] = points[0][1];
  296. bounding_box[1][0] = points[0][0];
  297. bounding_box[1][1] = points[0][1];
  298. for (i = 1; i < points.length; i++) {
  299. if (bounding_box[0][0] > points[i][0]) {
  300. bounding_box[0][0] = points[i][0];
  301. }
  302. if (bounding_box[1][0] < points[i][0]) {
  303. bounding_box[1][0] = points[i][0];
  304. }
  305. if (bounding_box[0][1] > points[i][1]) {
  306. bounding_box[0][1] = points[i][1];
  307. }
  308. if (bounding_box[1][1] < points[i][1]) {
  309. bounding_box[1][1] = points[i][1];
  310. }
  311. }
  312. // intersection method precalculated data
  313. lines2 = new float[points.length][2]; //lines[0][] is not used
  314. for (i = 0; i < points.length - 1; i++) {
  315. lines2[i + 1][0] = (points[i][1] - points[i + 1][1])
  316. / (points[i][0] - points[i + 1][0]); //slope
  317. lines2[i + 1][1] = points[i][1] - lines2[i + 1][0] * points[i][0]; //intercept
  318. }
  319. }
  320. }
  321. /**
  322. * gets points of a polygon only
  323. *
  324. * @return points of this object if it is a polygon as double[][]
  325. * otherwise returns null.
  326. */
  327. public float[][] getPoints() {
  328. return points;
  329. }
  330. /**
  331. * returns true when the point provided is within the SimpleRegion
  332. *
  333. * note: type UNDEFINED implies no boundary, always returns true.
  334. *
  335. * @param longitude
  336. * @param latitude
  337. * @return true iff point is within or on the edge of this SimpleRegion
  338. */
  339. public boolean isWithin(double longitude, double latitude) {
  340. switch (type) {
  341. case 0:
  342. /* no region defined, must be within this absence of a boundary */
  343. return true;
  344. case 1:
  345. /* return for bounding box */
  346. return (longitude <= points[1][0] && longitude >= points[0][0]
  347. && latitude <= points[1][1] && latitude >= points[0][1]);
  348. case 2:
  349. /* TODO: fix to use radius units m not degrees */
  350. double x = longitude - points[0][0];
  351. double y = latitude - points[0][1];
  352. return Math.sqrt(x * x + y * y) <= radius;
  353. case 3:
  354. /* determine for Polygon */
  355. return isWithinPolygon(longitude, latitude);
  356. }
  357. return false;
  358. }
  359. public boolean isWithin_EPSG900913(double longitude, double latitude) {
  360. switch (type) {
  361. case 0:
  362. /* no region defined, must be within this absence of a boundary */
  363. return true;
  364. case 1:
  365. /* return for bounding box */
  366. return (longitude <= points[1][0] && longitude >= points[0][0]
  367. && latitude <= points[1][1] && latitude >= points[0][1]);
  368. case 2:
  369. /* TODO: fix to use radius units m not degrees */
  370. double x = longitude - points[0][0];
  371. double y = latitude - points[0][1];
  372. return Math.sqrt(x * x + y * y) <= radius;
  373. case 3:
  374. /* determine for Polygon */
  375. return isWithinPolygon_EPSG900913(longitude, latitude);
  376. }
  377. return false;
  378. }
  379. /**
  380. * returns true when point is within the polygon
  381. *
  382. * method:
  383. * treat as segments with target long in the middle:
  384. *
  385. *
  386. * __-1__|___1_
  387. * |
  388. *
  389. *
  390. * iterate through points and count number of latitude axis crossing where
  391. * crossing is > latitude.
  392. *
  393. * point is inside of area when number of crossings is odd;
  394. *
  395. * point is on a polygon edge return true
  396. *
  397. * @param longitude
  398. * @param latitude
  399. * @return true iff longitude and latitude point is on edge or within polygon
  400. */
  401. private boolean isWithinPolygon(double longitude, double latitude) {
  402. // bounding box test
  403. if (longitude <= bounding_box[1][0] && longitude >= bounding_box[0][0]
  404. && latitude <= bounding_box[1][1] && latitude >= bounding_box[0][1]) {
  405. //initial segment
  406. boolean segment = points[0][0] > longitude;
  407. double y;
  408. int i;
  409. int len = points.length;
  410. int score = 0;
  411. for (i = 1; i < len; i++) {
  412. // is it in a new segment?
  413. if ((points[i][0] > longitude) != segment) {
  414. //lat value at line crossing > target point
  415. y = lines2[i][0] * longitude + lines2[i][1];
  416. if (y > latitude) {
  417. score++;
  418. } else if (y == latitude) {
  419. //line crossing
  420. return true;
  421. }
  422. segment = !segment;
  423. } else if (points[i][0] == longitude && points[i][1] == latitude) {
  424. //point on point
  425. return true;
  426. }
  427. }
  428. return (score % 2 != 0);
  429. }
  430. return false; //not within bounding box
  431. }
  432. private boolean isWithinPolygon_EPSG900913(double longitude, double latitude) {
  433. SpatialCluster3 sc = new SpatialCluster3();
  434. // bounding box test
  435. if (longitude <= bounding_box[1][0] && longitude >= bounding_box[0][0]
  436. && latitude <= bounding_box[1][1] && latitude >= bounding_box[0][1]) {
  437. //initial segment
  438. int longitudePx = sc.convertLngToPixel(longitude);
  439. boolean segment = sc.convertLngToPixel(points[0][0]) > longitudePx;
  440. int y;
  441. int i;
  442. int len = points.length;
  443. int score = 0;
  444. for (i = 1; i < len; i++) {
  445. // is it in a new segment?
  446. if ((sc.convertLngToPixel(points[i][0]) > longitudePx) != segment) {
  447. //lat value at line crossing > target point
  448. y = (int)((longitudePx - sc.convertLngToPixel(points[i][0]))
  449. * ((sc.convertLatToPixel(points[i][1]) - sc.convertLatToPixel(points[i - 1][1]))
  450. / (double) (sc.convertLngToPixel(points[i][0]) - sc.convertLngToPixel(points[i - 1][0])))
  451. + sc.convertLatToPixel(points[i][1]));
  452. if (y > sc.convertLatToPixel(latitude)) {
  453. score++;
  454. } else if (y == sc.convertLatToPixel(latitude)) {
  455. //line crossing
  456. return true;
  457. }
  458. segment = !segment;
  459. } else if (points[i][0] == longitude && points[i][1] == latitude) {
  460. //point on point
  461. return true;
  462. }
  463. }
  464. return (score % 2 != 0);
  465. }
  466. return false; //not within bounding box
  467. }
  468. /**
  469. * determines overlap with a grid
  470. *
  471. * for type POLYGON
  472. * when <code>three_state_map</code> is not null populate it with one of:
  473. * GI_UNDEFINED
  474. * GI_PARTIALLY_PRESENT
  475. * GI_FULLY_PRESENT
  476. * GI_ABSENCE
  477. *
  478. * @param longitude1
  479. * @param latitude1
  480. * @param longitude2
  481. * @param latitude2
  482. * @param xres number of longitude segements as int
  483. * @param yres number of latitude segments as int
  484. * @return (x,y) as double [][2] for each grid cell at least partially falling
  485. * within the specified region of the specified resolution beginning at 0,0
  486. * for minimum longitude and latitude through to xres,yres for maximums
  487. */
  488. public int[][] getOverlapGridCells(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map, boolean noCellsReturned) {
  489. int[][] cells = null;
  490. switch (type) {
  491. case 0:
  492. break;
  493. case 1:
  494. cells = getOverlapGridCells_Box(longitude1, latitude1, longitude2, latitude2, width, height, bounding_box, three_state_map, noCellsReturned);
  495. break;
  496. case 2:
  497. break; /* TODO: circle grid */
  498. case 3:
  499. cells = getOverlapGridCells_Polygon(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map, noCellsReturned);
  500. }
  501. return cells;
  502. }
  503. /**
  504. * stacks PARTIALLY_PRESENT shape outline onto three_state_map
  505. *
  506. * @param longitude1
  507. * @param latitude1
  508. * @param longitude2
  509. * @param latitude2
  510. * @param width
  511. * @param height
  512. * @param three_state_map
  513. * @param noCellsReturned
  514. */
  515. public void getOverlapGridCells_Acc(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map) {
  516. switch (type) {
  517. case 0:
  518. break;
  519. case 1:
  520. getOverlapGridCells_Box_Acc(longitude1, latitude1, longitude2, latitude2, width, height, bounding_box, three_state_map);
  521. break;
  522. case 2:
  523. break; /* TODO: circle grid */
  524. case 3:
  525. getOverlapGridCells_Polygon_Acc(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map);
  526. }
  527. }
  528. public int[][] getOverlapGridCells(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map) {
  529. return getOverlapGridCells(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map, false);
  530. }
  531. /**
  532. * determines overlap with a grid for a BOUNDING_BOX
  533. *
  534. * @param longitude1
  535. * @param latitude1
  536. * @param longitude2
  537. * @param latitude2
  538. * @param xres number of longitude segements as int
  539. * @param yres number of latitude segments as int
  540. * @param bb bounding box as double[2][2] with [][0] as longitude, [][1] as latitude,
  541. * [0][] as minimum values, [1][] as maximum values
  542. * @return (x,y) as double [][2] for each grid cell at least partially falling
  543. * within the specified region of the specified resolution beginning at 0,0
  544. * for minimum longitude and latitude through to xres,yres for maximums
  545. */
  546. public int[][] getOverlapGridCells_Box(double longitude1, double latitude1,
  547. double longitude2, double latitude2, int width, int height, double[][] bb, byte[][] three_state_map, boolean noCellsReturned) {
  548. double xstep = Math.abs(longitude2 - longitude1) / (double) width;
  549. double ystep = Math.abs(latitude2 - latitude1) / (double) height;
  550. //double maxlong = Math.max(longitude1, longitude2);
  551. double minlong = Math.min(longitude1, longitude2);
  552. //double maxlat = Math.max(latitude1, latitude2);
  553. double minlat = Math.min(latitude1, latitude2);
  554. //setup minimums from bounding box (TODO: should this have -1 on steps?)
  555. int xstart = (int) Math.floor((bb[0][0] - minlong) / xstep);
  556. int ystart = (int) Math.floor((bb[0][1] - minlat) / ystep);
  557. int xend = (int) Math.ceil((bb[1][0] - minlong) / xstep);
  558. int yend = (int) Math.ceil((bb[1][1] - minlat) / ystep);
  559. if (xstart < 0) {
  560. xstart = 0;
  561. }
  562. if (ystart < 0) {
  563. ystart = 0;
  564. }
  565. if (xend > width) {
  566. xend = width;
  567. }
  568. if (yend > height) {
  569. yend = height;
  570. }
  571. // fill data with cell coordinates
  572. int out_width = xend - xstart;
  573. int out_height = yend - ystart;
  574. int j, i, p = 0;
  575. int[][] data = null;
  576. if (!noCellsReturned) {
  577. data = new int[out_width * out_height][2];
  578. if (three_state_map == null) {
  579. for (j = ystart; j < yend; j++) {
  580. for (i = xstart; i < xend; i++) {
  581. data[p][0] = i;
  582. data[p][1] = j;
  583. p++;
  584. }
  585. }
  586. } else {
  587. for (j = ystart; j < yend; j++) {
  588. for (i = xstart; i < xend; i++) {
  589. data[p][0] = i;
  590. data[p][1] = j;
  591. three_state_map[j][i] = SimpleRegion.GI_FULLY_PRESENT;
  592. p++;
  593. }
  594. }
  595. //set three state map edges to partially present
  596. if (xstart < xend && xend > 0) {
  597. for (j = ystart; j < yend; j++) {
  598. three_state_map[j][xstart] = SimpleRegion.GI_PARTIALLY_PRESENT;
  599. three_state_map[j][xend - 1] = SimpleRegion.GI_PARTIALLY_PRESENT;
  600. }
  601. }
  602. if (ystart < yend && yend > 0) {
  603. for (i = xstart; i < xend; i++) {
  604. three_state_map[ystart][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  605. three_state_map[yend - 1][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  606. }
  607. }
  608. //no need to set SimpleRegion.GI_ABSENCE
  609. }
  610. } else {
  611. if (three_state_map == null) {
  612. for (j = ystart; j < yend; j++) {
  613. for (i = xstart; i < xend; i++) {
  614. data[p][0] = i;
  615. data[p][1] = j;
  616. p++;
  617. }
  618. }
  619. } else {
  620. for (j = ystart; j < yend; j++) {
  621. for (i = xstart; i < xend; i++) {
  622. three_state_map[j][i] = SimpleRegion.GI_FULLY_PRESENT;
  623. }
  624. }
  625. //set three state map edges to partially present
  626. if (xstart < xend && xend > 0) {
  627. for (j = ystart; j < yend; j++) {
  628. three_state_map[j][xstart] = SimpleRegion.GI_PARTIALLY_PRESENT;
  629. three_state_map[j][xend - 1] = SimpleRegion.GI_PARTIALLY_PRESENT;
  630. }
  631. }
  632. if (ystart < yend && yend > 0) {
  633. for (i = xstart; i < xend; i++) {
  634. three_state_map[ystart][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  635. three_state_map[yend - 1][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  636. }
  637. }
  638. }
  639. }
  640. return data;
  641. }
  642. /**
  643. * defines a region by a points string, POLYGON only
  644. *
  645. * TODO: define better format for parsing, including BOUNDING_BOX and CIRCLE
  646. *
  647. * @param pointsString points separated by ',' with longitude and latitude separated by ':'
  648. * @return SimpleRegion object
  649. */
  650. public static SimpleRegion parseSimpleRegion(String pointsString) {
  651. if (pointsString.equalsIgnoreCase("none")) {
  652. return null;
  653. }
  654. SimpleRegion simpleregion = new SimpleRegion();
  655. ArrayList<Double> points = new ArrayList<Double>();
  656. int pos;
  657. int lastpos = 0;
  658. while((pos = Math.min(pointsString.indexOf(',', lastpos), pointsString.indexOf(' ', lastpos))) > 0) {
  659. try {
  660. points.add(Double.parseDouble(pointsString.substring(lastpos, pos)));
  661. } catch (Exception e) {
  662. points.add(0.0);
  663. }
  664. lastpos = pos + 1;
  665. }
  666. //one coordinate pair left
  667. pos = pointsString.indexOf(' ', lastpos);
  668. try {
  669. points.add(Double.parseDouble(pointsString.substring(lastpos, pos)));
  670. lastpos = pos + 1;
  671. } catch (Exception e) {
  672. points.add(0.0);
  673. }
  674. try {
  675. points.add(Double.parseDouble(pointsString.substring(lastpos, pointsString.length())));
  676. } catch (Exception e) {
  677. points.add(0.0);
  678. }
  679. //test for box
  680. // get min/max long/lat
  681. // each point has only one identical lat or long to previous point
  682. // 4 or 5 points (start and end points may be identical)
  683. if (((points.size() == 8 && (points.get(0) != points.get(6) || points.get(1) != points.get(7)))
  684. || (points.size() == 5 && points.get(0) == points.get(8)
  685. && points.get(1) == points.get(9)))) {
  686. //get min/max long/lat
  687. double minlong = 0, minlat = 0, maxlong = 0, maxlat = 0;
  688. for (int i = 0; i < points.size(); i+=2) {
  689. if (i == 0 || minlong > points.get(i)) {
  690. minlong = points.get(i);
  691. }
  692. if (i == 0 || maxlong < points.get(i)) {
  693. maxlong = points.get(i);
  694. }
  695. if (i == 0 || minlat > points.get(i+1)) {
  696. minlat = points.get(i+1);
  697. }
  698. if (i == 0 || maxlat < points.get(i+1)) {
  699. maxlat = points.get(i+1);
  700. }
  701. }
  702. // each point has only one identical lat or long to previous point
  703. int prev_idx = 6;
  704. int i = 0;
  705. for (i = 0; i < 8; i+=2) {
  706. if ((points.get(i) == points.get(prev_idx))
  707. == (points.get(i+1) == points.get(prev_idx+1))) {
  708. break;
  709. }
  710. prev_idx = i;
  711. }
  712. //it is a box if no 'break' occurred
  713. if (i == 8) {
  714. simpleregion.setBox(minlong, minlat, maxlong, maxlat);
  715. return simpleregion;
  716. }
  717. }
  718. double [][] pointsArray = new double[points.size()/2][2];
  719. for(int i=0;i<points.size();i+=2) {
  720. pointsArray[i/2][0] = points.get(i);
  721. pointsArray[i/2][1] = points.get(i+1);
  722. }
  723. simpleregion.setPolygon(pointsArray);
  724. return simpleregion;
  725. }
  726. public double getWidth() {
  727. return bounding_box[1][0] - bounding_box[0][0];
  728. }
  729. public double getHeight() {
  730. return bounding_box[1][1] - bounding_box[0][1];
  731. }
  732. public int getType() {
  733. return type;
  734. }
  735. public void setAttribute(String name, Object value) {
  736. if (attributes == null) {
  737. attributes = new HashMap<String, Object>();
  738. }
  739. attributes.put(name, value);
  740. }
  741. public Object getAttribute(String name) {
  742. if (attributes != null) {
  743. return attributes.get(name);
  744. }
  745. return null;
  746. }
  747. public void saveGridAsImage(byte[][] three_state_map) {
  748. try {
  749. long t1 = System.currentTimeMillis();
  750. BufferedImage bi = new BufferedImage(three_state_map[0].length, three_state_map.length, BufferedImage.TYPE_INT_RGB);
  751. for (int i = 0; i < three_state_map.length; i++) {
  752. for (int j = 0; j < three_state_map[i].length; j++) {
  753. if (three_state_map[i][j] == 0) {
  754. bi.setRGB(j, (three_state_map.length - 1 - i), 0xFFFFFF);
  755. } else if (three_state_map[i][j] == 1) {
  756. bi.setRGB(j, (three_state_map.length - 1 - i), 0x99FF99);
  757. } else if (three_state_map[i][j] == 2) {
  758. bi.setRGB(j, (three_state_map.length - 1 - i), 0x9999FF);
  759. }
  760. }
  761. }
  762. ImageIO.write(bi, "png", File.createTempFile("grd", ".png", new File("d:\\")));
  763. System.out.println("save grid in " + (System.currentTimeMillis() - t1) + "ms");
  764. } catch (Exception e) {
  765. e.printStackTrace();
  766. }
  767. }
  768. /**
  769. * determines overlap with a grid for POLYGON
  770. *
  771. * when <code>three_state_map</code> is not null populate it with one of:
  772. * GI_UNDEFINED
  773. * GI_PARTIALLY_PRESENT
  774. * GI_FULLY_PRESENT
  775. * GI_ABSENCE
  776. *
  777. * 1. Get 3state mask and fill edge passes as 'partial'.
  778. * then
  779. * 3. Test 0,0 then progress across vert raster until finding cells[][] entry
  780. * 4. Repeat from (3).
  781. *
  782. * @param longitude1
  783. * @param latitude1
  784. * @param longitude2
  785. * @param latitude2
  786. * @param xres number of longitude segements as int
  787. * @param yres number of latitude segments as int
  788. * @return (x,y) as double [][2] for each grid cell at least partially falling
  789. * within the specified region of the specified resolution beginning at 0,0
  790. * for minimum longitude and latitude through to xres,yres for maximums
  791. */
  792. public int[][] getOverlapGridCells_Polygon(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map, boolean noCellsReturned) {
  793. int i, j;
  794. if (three_state_map == null) {
  795. three_state_map = new byte[height][width];
  796. }
  797. double divx = (longitude2 - longitude1) / width;
  798. double divy = (latitude2 - latitude1) / height;
  799. //to cells
  800. int x, y, xend, yend, xDirection, icross;
  801. double xcross, endlat, dx1, dx2, dy1, dy2, slope, intercept;
  802. for (j = 1; j < points.length; j++) {
  803. if (points[j][1] < points[j - 1][1]) {
  804. dx1 = points[j][0];
  805. dy1 = points[j][1];
  806. dx2 = points[j - 1][0];
  807. dy2 = points[j - 1][1];
  808. } else {
  809. dx2 = points[j][0];
  810. dy2 = points[j][1];
  811. dx1 = points[j - 1][0];
  812. dy1 = points[j - 1][1];
  813. }
  814. x = (int) ((dx1 - longitude1) / divx);
  815. y = (int) ((dy1 - latitude1) / divy);
  816. xend = (int) ((dx2 - longitude1) / divx);
  817. yend = (int) ((dy2 - latitude1) / divy);
  818. if (y >= 0 && y < height && x >= 0 && x < width) {
  819. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  820. }
  821. if (x == xend && y == yend) {
  822. continue;
  823. }
  824. xDirection = (x < xend) ? 1 : -1;
  825. slope = (dy1 - dy2) / (dx1 - dx2);
  826. intercept = dy1 - slope * dx1;
  827. if (x == xend) {
  828. //vertical line
  829. while (y != yend) {
  830. y++;
  831. if (y >= 0 && y < height && x >= 0 && x < width) {
  832. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  833. }
  834. }
  835. } else if (y == yend) {
  836. //horizontal line
  837. while (x != xend) {
  838. x += xDirection;
  839. if (y >= 0 && y < height && x >= 0 && x < width) {
  840. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  841. }
  842. }
  843. } else { //sloped line
  844. endlat = dy2;
  845. for (double k = (y + 1) * divy + latitude1; k < endlat; k += divy) {
  846. //move in yDirection to get x
  847. xcross = (k - intercept) / slope;
  848. icross = (int) ((xcross - longitude1) / divx);
  849. while (x != icross && x != xend) {
  850. x += xDirection;
  851. if (y >= 0 && y < height && x >= 0 && x < width) {
  852. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  853. }
  854. }
  855. if (y != yend) {
  856. y++;
  857. if (y >= 0 && y < height && x >= 0 && x < width) {
  858. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  859. }
  860. }
  861. }
  862. //finish horizontal line
  863. while (x != xend) {
  864. x += xDirection;
  865. if (y >= 0 && y < height && x >= 0 && x < width) {
  866. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  867. }
  868. }
  869. }
  870. }
  871. //do raster check
  872. int[][] data = new int[width * height][2];
  873. boolean cellsReturned = !noCellsReturned;
  874. int p = 0;
  875. for (j = 0; j < three_state_map[0].length; j++) {
  876. for (i = 0; i < three_state_map.length; i++) {
  877. if (three_state_map[i][j] == GI_PARTIALLY_PRESENT) {
  878. //if it is partially present, do nothing
  879. } else if ((j == 0 || three_state_map[i][j - 1] == GI_PARTIALLY_PRESENT)) {
  880. if (i > 0
  881. && (three_state_map[i - 1][j] == GI_FULLY_PRESENT
  882. || three_state_map[i - 1][j] == GI_ABSENCE)) {
  883. //use same as LHS
  884. three_state_map[i][j] = three_state_map[i - 1][j];
  885. } else if (isWithin(j * divx + divx / 2 + longitude1, i * divy + divy / 2 + latitude1)) {
  886. //if the previous was partially present, test
  887. three_state_map[i][j] = GI_FULLY_PRESENT;
  888. } //else absent
  889. } else {
  890. //if the previous was fully present, repeat
  891. //if the previous was absent, repeat
  892. three_state_map[i][j] = three_state_map[i][j - 1];
  893. }
  894. //apply to cells;
  895. if (cellsReturned && three_state_map[i][j] != GI_UNDEFINED) { //undefined == absence
  896. data[p][0] = j;
  897. data[p][1] = i;
  898. p++;
  899. }
  900. }
  901. }
  902. return java.util.Arrays.copyOfRange(data, 0, p);
  903. }
  904. public void getOverlapGridCells_Polygon_Acc(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map) {
  905. int i, j;
  906. double divx = (longitude2 - longitude1) / width;
  907. double divy = (latitude2 - latitude1) / height;
  908. //to cells
  909. int x, y, xend, yend, xDirection, icross;
  910. double xcross, endlat, dx1, dx2, dy1, dy2, slope, intercept;
  911. for (j = 1; j < points.length; j++) {
  912. if (points[j][1] < points[j - 1][1]) {
  913. dx1 = points[j][0];
  914. dy1 = points[j][1];
  915. dx2 = points[j - 1][0];
  916. dy2 = points[j - 1][1];
  917. } else {
  918. dx2 = points[j][0];
  919. dy2 = points[j][1];
  920. dx1 = points[j - 1][0];
  921. dy1 = points[j - 1][1];
  922. }
  923. x = (int) ((dx1 - longitude1) / divx);
  924. y = (int) ((dy1 - latitude1) / divy);
  925. xend = (int) ((dx2 - longitude1) / divx);
  926. yend = (int) ((dy2 - latitude1) / divy);
  927. if (x == xend && y == yend) {
  928. continue;
  929. }
  930. xDirection = (x < xend) ? 1 : -1;
  931. slope = (dy1 - dy2) / (dx1 - dx2);
  932. intercept = dy1 - slope * dx1;
  933. if (y >= 0 && y < height && x >= 0 && x < width) {
  934. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  935. }
  936. if (x == xend) {
  937. //vertical line
  938. while (y != yend) {
  939. y++;
  940. if (y >= 0 && y < height && x >= 0 && x < width) {
  941. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  942. }
  943. }
  944. } else if (y == yend) {
  945. //horizontal line
  946. while (x != xend) {
  947. x += xDirection;
  948. if (y >= 0 && y < height && x >= 0 && x < width) {
  949. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  950. }
  951. }
  952. } else { //sloped line
  953. endlat = dy2;
  954. for (double k = (y + 1) * divy + latitude1; k < endlat; k += divy) {
  955. //move in yDirection to get x
  956. xcross = (k - intercept) / slope;
  957. icross = (int) ((xcross - longitude1) / divx);
  958. while (x != icross && x != xend) {
  959. x += xDirection;
  960. if (y >= 0 && y < height && x >= 0 && x < width) {
  961. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  962. }
  963. }
  964. if (y != yend) {
  965. y++;
  966. if (y >= 0 && y < height && x >= 0 && x < width) {
  967. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  968. }
  969. }
  970. }
  971. //finish horizontal line
  972. while (x != xend) {
  973. x += xDirection;
  974. if (y >= 0 && y < height && x >= 0 && x < width) {
  975. three_state_map[y][x] = GI_PARTIALLY_PRESENT;
  976. }
  977. }
  978. }
  979. }
  980. }
  981. public int[][] fillAccMask(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map, boolean noCellsReturned) {
  982. double divx = (longitude2 - longitude1) / width;
  983. double divy = (latitude2 - latitude1) / height;
  984. int i, j;
  985. //do raster check
  986. int[][] data = null;
  987. boolean cellsReturned = !noCellsReturned;
  988. if (cellsReturned) {
  989. data = new int[width * height][2];
  990. }
  991. int p = 0;
  992. for (j = 0; j < three_state_map[0].length; j++) {
  993. for (i = 0; i < three_state_map.length; i++) {
  994. if (three_state_map[i][j] == GI_PARTIALLY_PRESENT) {
  995. //if it is partially present, do nothing
  996. } else if ((j == 0 || three_state_map[i][j - 1] == GI_PARTIALLY_PRESENT)) {
  997. if (i > 0
  998. && (three_state_map[i - 1][j] == GI_FULLY_PRESENT
  999. || three_state_map[i - 1][j] == GI_ABSENCE)) {
  1000. //use same as LHS
  1001. three_state_map[i][j] = three_state_map[i - 1][j];
  1002. } else if (isWithin(j * divx + divx / 2 + longitude1, i * divy + divy / 2 + latitude1)) {
  1003. //if the previous was partially present, test
  1004. three_state_map[i][j] = GI_FULLY_PRESENT;
  1005. } //else absent
  1006. } else {
  1007. //if the previous was fully present, repeat
  1008. //if the previous was absent, repeat
  1009. three_state_map[i][j] = three_state_map[i][j - 1];
  1010. }
  1011. //apply to cells;
  1012. if (cellsReturned && three_state_map[i][j] != GI_UNDEFINED) { //undefined == absence
  1013. data[p][0] = j;
  1014. data[p][1] = i;
  1015. p++;
  1016. }
  1017. }
  1018. }
  1019. if (data != null) {
  1020. data = java.util.Arrays.copyOf(data, p);
  1021. }
  1022. return data;
  1023. }
  1024. private void getOverlapGridCells_Box_Acc(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, double[][] bb, byte[][] three_state_map) {
  1025. double xstep = Math.abs(longitude2 - longitude1) / (double) width;
  1026. double ystep = Math.abs(latitude2 - latitude1) / (double) height;
  1027. //double maxlong = Math.max(longitude1, longitude2);
  1028. double minlong = Math.min(longitude1, longitude2);
  1029. //double maxlat = Math.max(latitude1, latitude2);
  1030. double minlat = Math.min(latitude1, latitude2);
  1031. //setup minimums from bounding box (TODO: should this have -1 on steps?)
  1032. int xstart = (int) Math.floor((bb[0][0] - minlong) / xstep);
  1033. int ystart = (int) Math.floor((bb[0][1] - minlat) / ystep);
  1034. int xend = (int) Math.ceil((bb[1][0] - minlong) / xstep);
  1035. int yend = (int) Math.ceil((bb[1][1] - minlat) / ystep);
  1036. if (xstart < 0) {
  1037. xstart = 0;
  1038. }
  1039. if (ystart < 0) {
  1040. ystart = 0;
  1041. }
  1042. if (xend > width) {
  1043. xend = width;
  1044. }
  1045. if (yend > height) {
  1046. yend = height;
  1047. }
  1048. // fill data with cell coordinates
  1049. //int out_width = xend - xstart;
  1050. //int out_height = yend - ystart;
  1051. int j, i, p = 0;
  1052. //int[][] data = null;
  1053. //set three state map edges to partially present
  1054. if (xstart < xend && xend > 0) {
  1055. for (j = ystart; j < yend; j++) {
  1056. three_state_map[j][xstart] = SimpleRegion.GI_PARTIALLY_PRESENT;
  1057. three_state_map[j][xend - 1] = SimpleRegion.GI_PARTIALLY_PRESENT;
  1058. }
  1059. }
  1060. if (ystart < yend && yend > 0) {
  1061. for (i = xstart; i < xend; i++) {
  1062. three_state_map[ystart][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  1063. three_state_map[yend - 1][i] = SimpleRegion.GI_PARTIALLY_PRESENT;
  1064. }
  1065. }
  1066. }
  1067. public int[][] getOverlapGridCells_EPSG900913(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map, boolean noCellsReturned) {
  1068. int[][] cells = null;
  1069. switch (type) {
  1070. case 0:
  1071. break;
  1072. case 1:
  1073. cells = getOverlapGridCells_Box(longitude1, latitude1, longitude2, latitude2, width, height, bounding_box, three_state_map, noCellsReturned);
  1074. break;
  1075. case 2:
  1076. break; /* TODO: circle grid */
  1077. case 3:
  1078. cells = getOverlapGridCells_Polygon_EPSG900913(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map, noCellsReturned);
  1079. }
  1080. return cells;
  1081. }
  1082. /**
  1083. * stacks PARTIALLY_PRESENT shape outline onto three_state_map
  1084. *
  1085. * @param longitude1
  1086. * @param latitude1
  1087. * @param longitude2
  1088. * @param latitude2
  1089. * @param width
  1090. * @param height
  1091. * @param three_state_map
  1092. * @param noCellsReturned
  1093. */
  1094. public void getOverlapGridCells_Acc_EPSG900913(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map) {
  1095. switch (type) {
  1096. case 0:
  1097. break;
  1098. case 1:
  1099. getOverlapGridCells_Box_Acc(longitude1, latitude1, longitude2, latitude2, width, height, bounding_box, three_state_map);
  1100. break;
  1101. case 2:
  1102. break; /* TODO: circle grid */
  1103. case 3:
  1104. getOverlapGridCells_Polygon_Acc_EPSG900913(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map);
  1105. }
  1106. }
  1107. public int[][] getOverlapGridCells_EPSG900913(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map) {
  1108. return getOverlapGridCells_EPSG900913(longitude1, latitude1, longitude2, latitude2, width, height, three_state_map, false);
  1109. }
  1110. public int[][] getOverlapGridCells_Polygon_EPSG900913(double olongitude1, double olatitude1, double olongitude2, double olatitude2, int owidth, int oheight, byte[][] three_state_map, boolean noCellsReturned) {
  1111. int i, j;
  1112. if (three_state_map == null) {
  1113. three_state_map = new byte[oheight][owidth];
  1114. }
  1115. SpatialCluster3 sc = new SpatialCluster3();
  1116. int longitude1 = sc.convertLngToPixel(olongitude1);
  1117. int longitude2 = sc.convertLngToPixel(olongitude2);
  1118. int latitude1 = sc.convertLatToPixel(olatitude2);
  1119. int latitude2 = sc.convertLatToPixel(olatitude1);
  1120. int scale = 100; //if it is too small the 'fill' operation is messed up
  1121. int width = owidth * scale;
  1122. int height = oheight * scale;
  1123. double divx = (longitude2 - longitude1) / width;
  1124. double divy = (latitude2 - latitude1) / height;
  1125. double odivx = (olongitude2 - olongitude1) / owidth;
  1126. double odivy = (olatitude2 - olatitude1) / oheight;
  1127. int oy, ox;
  1128. //to cells
  1129. int x, y, xend, yend, xDirection, icross;
  1130. double slope, intercept;
  1131. int xcross, endlat, dx1, dx2, dy1, dy2;
  1132. for (j = 1; j < points.length; j++) {
  1133. if (points[j][1] > points[j - 1][1]) {
  1134. dx1 = sc.convertLngToPixel(points[j][0]);
  1135. dy1 = sc.convertLatToPixel(points[j][1]);
  1136. dx2 = sc.convertLngToPixel(points[j - 1][0]);
  1137. dy2 = sc.convertLatToPixel(points[j - 1][1]);
  1138. } else {
  1139. dx2 = sc.convertLngToPixel(points[j][0]);
  1140. dy2 = sc.convertLatToPixel(points[j][1]);
  1141. dx1 = sc.convertLngToPixel(points[j - 1][0]);
  1142. dy1 = sc.convertLatToPixel(points[j - 1][1]);
  1143. }
  1144. x = (int) ((dx1 - longitude1) / divx);
  1145. y = (int) ((dy1 - latitude1) / divy);
  1146. xend = (int) ((dx2 - longitude1) / divx);
  1147. yend = (int) ((dy2 - latitude1) / divy);
  1148. if (y >= 0 && y < height && x >= 0 && x < width) {
  1149. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1150. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1151. if (oy >= oheight) {
  1152. oy = oheight - 1;
  1153. }
  1154. if (ox >= owidth) {
  1155. ox = owidth - 1;
  1156. }
  1157. if (oy < 0) {
  1158. oy = 0;
  1159. }
  1160. if (ox < 0) {
  1161. ox = 0;
  1162. }
  1163. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1164. }
  1165. if (x == xend && y == yend) {
  1166. continue;
  1167. }
  1168. xDirection = (x < xend) ? 1 : -1;
  1169. slope = (dy1 - dy2) / (double) (dx1 - dx2);
  1170. intercept = (double) (dy1 - slope * dx1);
  1171. if (x == xend) {
  1172. //vertical line
  1173. while (y != yend) {
  1174. y++;
  1175. if (y >= 0 && y < height && x >= 0 && x < width) {
  1176. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1177. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1178. if (oy >= oheight) {
  1179. oy = oheight - 1;
  1180. }
  1181. if (ox >= owidth) {
  1182. ox = owidth - 1;
  1183. }
  1184. if (oy < 0) {
  1185. oy = 0;
  1186. }
  1187. if (ox < 0) {
  1188. ox = 0;
  1189. }
  1190. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1191. }
  1192. }
  1193. } else if (y == yend) {
  1194. //horizontal line
  1195. while (x != xend) {
  1196. x += xDirection;
  1197. if (y >= 0 && y < height && x >= 0 && x < width) {
  1198. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1199. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1200. if (oy >= oheight) {
  1201. oy = oheight - 1;
  1202. }
  1203. if (ox >= owidth) {
  1204. ox = owidth - 1;
  1205. }
  1206. if (oy < 0) {
  1207. oy = 0;
  1208. }
  1209. if (ox < 0) {
  1210. ox = 0;
  1211. }
  1212. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1213. }
  1214. }
  1215. } else { //sloped line
  1216. endlat = dy2;
  1217. for (int k = (int) ((y + 1) * divy + latitude1); k < endlat; k += divy) {
  1218. //move in yDirection to get x
  1219. xcross = (int) ((k - intercept) / slope);
  1220. icross = (int) ((xcross - longitude1) / divx);
  1221. while (x != icross && x != xend) {
  1222. x += xDirection;
  1223. if (y >= 0 && y < height && x >= 0 && x < width) {
  1224. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1225. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1226. if (oy >= oheight) {
  1227. oy = oheight - 1;
  1228. }
  1229. if (ox >= owidth) {
  1230. ox = owidth - 1;
  1231. }
  1232. if (oy < 0) {
  1233. oy = 0;
  1234. }
  1235. if (ox < 0) {
  1236. ox = 0;
  1237. }
  1238. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1239. }
  1240. }
  1241. if (y != yend) {
  1242. y++;
  1243. if (y >= 0 && y < height && x >= 0 && x < width) {
  1244. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1245. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1246. if (oy >= oheight) {
  1247. oy = oheight - 1;
  1248. }
  1249. if (ox >= owidth) {
  1250. ox = owidth - 1;
  1251. }
  1252. if (oy < 0) {
  1253. oy = 0;
  1254. }
  1255. if (ox < 0) {
  1256. ox = 0;
  1257. }
  1258. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1259. }
  1260. }
  1261. }
  1262. //finish horizontal line
  1263. while (x != xend) {
  1264. x += xDirection;
  1265. if (y >= 0 && y < height && x >= 0 && x < width) {
  1266. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1267. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1268. if (oy >= oheight) {
  1269. oy = oheight - 1;
  1270. }
  1271. if (ox >= owidth) {
  1272. ox = owidth - 1;
  1273. }
  1274. if (oy < 0) {
  1275. oy = 0;
  1276. }
  1277. if (ox < 0) {
  1278. ox = 0;
  1279. }
  1280. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1281. }
  1282. }
  1283. }
  1284. }
  1285. //do raster check
  1286. int[][] data = new int[owidth * oheight][2];
  1287. boolean cellsReturned = !noCellsReturned;
  1288. int p = 0;
  1289. for (j = 0; j < three_state_map[0].length; j++) {
  1290. for (i = 0; i < three_state_map.length; i++) {
  1291. if (three_state_map[i][j] == GI_PARTIALLY_PRESENT) {
  1292. //if it is partially present, do nothing
  1293. } else if ((j == 0 || three_state_map[i][j - 1] == GI_PARTIALLY_PRESENT)) {
  1294. if (i > 0
  1295. && (three_state_map[i - 1][j] == GI_FULLY_PRESENT
  1296. || three_state_map[i - 1][j] == GI_ABSENCE)) {
  1297. //use same as LHS
  1298. three_state_map[i][j] = three_state_map[i - 1][j];
  1299. } else if (isWithin_EPSG900913(j * odivx + odivx / 2 + olongitude1, i * odivy + odivy / 2 + olatitude1)) {
  1300. //if the previous was partially present, test
  1301. three_state_map[i][j] = GI_FULLY_PRESENT;
  1302. } //else absent
  1303. } else {
  1304. //if the previous was fully present, repeat
  1305. //if the previous was absent, repeat
  1306. three_state_map[i][j] = three_state_map[i][j - 1];
  1307. }
  1308. //apply to cells;
  1309. if (cellsReturned && three_state_map[i][j] != GI_UNDEFINED) { //undefined == absence
  1310. data[p][0] = j;
  1311. data[p][1] = i;
  1312. p++;
  1313. }
  1314. }
  1315. }
  1316. return java.util.Arrays.copyOfRange(data, 0, p);
  1317. }
  1318. public void getOverlapGridCells_Polygon_Acc_EPSG900913(double olongitude1, double olatitude1, double olongitude2, double olatitude2, int owidth, int oheight, byte[][] three_state_map) {
  1319. int i, j;
  1320. if (three_state_map == null) {
  1321. three_state_map = new byte[oheight][owidth];
  1322. }
  1323. SpatialCluster3 sc = new SpatialCluster3();
  1324. int longitude1 = sc.convertLngToPixel(olongitude1);
  1325. int longitude2 = sc.convertLngToPixel(olongitude2);
  1326. int latitude1 = sc.convertLatToPixel(olatitude2);
  1327. int latitude2 = sc.convertLatToPixel(olatitude1);
  1328. int scale = 16; //if it is too small the 'fill' operation is messed up
  1329. int width = owidth * scale;
  1330. int height = oheight * scale;
  1331. double divx = (longitude2 - longitude1) / width;
  1332. double divy = (latitude2 - latitude1) / height;
  1333. double odivx = (olongitude2 - olongitude1) / owidth;
  1334. double odivy = (olatitude2 - olatitude1) / oheight;
  1335. int oy, ox;
  1336. //to cells
  1337. int x, y, xend, yend, xDirection, icross;
  1338. double slope, intercept;
  1339. int xcross, endlat, dx1, dx2, dy1, dy2;
  1340. for (j = 1; j < points.length; j++) {
  1341. if (points[j][1] > points[j - 1][1]) {
  1342. dx1 = sc.convertLngToPixel(points[j][0]);
  1343. dy1 = sc.convertLatToPixel(points[j][1]);
  1344. dx2 = sc.convertLngToPixel(points[j - 1][0]);
  1345. dy2 = sc.convertLatToPixel(points[j - 1][1]);
  1346. } else {
  1347. dx2 = sc.convertLngToPixel(points[j][0]);
  1348. dy2 = sc.convertLatToPixel(points[j][1]);
  1349. dx1 = sc.convertLngToPixel(points[j - 1][0]);
  1350. dy1 = sc.convertLatToPixel(points[j - 1][1]);
  1351. }
  1352. x = (int) ((dx1 - longitude1) / divx);
  1353. y = (int) ((dy1 - latitude1) / divy);
  1354. xend = (int) ((dx2 - longitude1) / divx);
  1355. yend = (int) ((dy2 - latitude1) / divy);
  1356. if (y >= 0 && y < height && x >= 0 && x < width) {
  1357. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1358. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1359. if (oy >= oheight) {
  1360. oy = oheight - 1;
  1361. }
  1362. if (ox >= owidth) {
  1363. ox = owidth - 1;
  1364. }
  1365. if (oy < 0) {
  1366. oy = 0;
  1367. }
  1368. if (ox < 0) {
  1369. ox = 0;
  1370. }
  1371. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1372. }
  1373. if (x == xend && y == yend) {
  1374. continue;
  1375. }
  1376. xDirection = (x < xend) ? 1 : -1;
  1377. slope = (dy1 - dy2) / (double) (dx1 - dx2);
  1378. intercept = (double) (dy1 - slope * dx1);
  1379. if (x == xend) {
  1380. //vertical line
  1381. while (y != yend) {
  1382. y++;
  1383. if (y >= 0 && y < height && x >= 0 && x < width) {
  1384. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1385. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1386. if (oy >= oheight) {
  1387. oy = oheight - 1;
  1388. }
  1389. if (ox >= owidth) {
  1390. ox = owidth - 1;
  1391. }
  1392. if (oy < 0) {
  1393. oy = 0;
  1394. }
  1395. if (ox < 0) {
  1396. ox = 0;
  1397. }
  1398. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1399. }
  1400. }
  1401. } else if (y == yend) {
  1402. //horizontal line
  1403. while (x != xend) {
  1404. x += xDirection;
  1405. if (y >= 0 && y < height && x >= 0 && x < width) {
  1406. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1407. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1408. if (oy >= oheight) {
  1409. oy = oheight - 1;
  1410. }
  1411. if (ox >= owidth) {
  1412. ox = owidth - 1;
  1413. }
  1414. if (oy < 0) {
  1415. oy = 0;
  1416. }
  1417. if (ox < 0) {
  1418. ox = 0;
  1419. }
  1420. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1421. }
  1422. }
  1423. } else { //sloped line
  1424. endlat = dy2;
  1425. for (int k = (int) ((y + 1) * divy + latitude1); k < endlat; k += divy) {
  1426. //move in yDirection to get x
  1427. xcross = (int) ((k - intercept) / slope);
  1428. icross = (int) ((xcross - longitude1) / divx);
  1429. while (x != icross && x != xend) {
  1430. x += xDirection;
  1431. if (y >= 0 && y < height && x >= 0 && x < width) {
  1432. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1433. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1434. if (oy >= oheight) {
  1435. oy = oheight - 1;
  1436. }
  1437. if (ox >= owidth) {
  1438. ox = owidth - 1;
  1439. }
  1440. if (oy < 0) {
  1441. oy = 0;
  1442. }
  1443. if (ox < 0) {
  1444. ox = 0;
  1445. }
  1446. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1447. }
  1448. }
  1449. if (y != yend) {
  1450. y++;
  1451. if (y >= 0 && y < height && x >= 0 && x < width) {
  1452. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1453. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1454. if (oy >= oheight) {
  1455. oy = oheight - 1;
  1456. }
  1457. if (ox >= owidth) {
  1458. ox = owidth - 1;
  1459. }
  1460. if (oy < 0) {
  1461. oy = 0;
  1462. }
  1463. if (ox < 0) {
  1464. ox = 0;
  1465. }
  1466. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1467. }
  1468. }
  1469. }
  1470. //finish horizontal line
  1471. while (x != xend) {
  1472. x += xDirection;
  1473. if (y >= 0 && y < height && x >= 0 && x < width) {
  1474. oy = (int) ((sc.convertPixelToLat((int) (y * divy + latitude1)) - olatitude1) / odivy);
  1475. ox = (int) ((sc.convertPixelToLng((int) (x * divx + longitude1)) - olongitude1) / odivx);
  1476. if (oy >= oheight) {
  1477. oy = oheight - 1;
  1478. }
  1479. if (ox >= owidth) {
  1480. ox = owidth - 1;
  1481. }
  1482. if (oy < 0) {
  1483. oy = 0;
  1484. }
  1485. if (ox < 0) {
  1486. ox = 0;
  1487. }
  1488. three_state_map[oy][ox] = GI_PARTIALLY_PRESENT;
  1489. }
  1490. }
  1491. }
  1492. }
  1493. }
  1494. public int[][] fillAccMask_EPSG900913(double longitude1, double latitude1, double longitude2, double latitude2, int width, int height, byte[][] three_state_map, boolean noCellsReturned) {
  1495. double divx = (longitude2 - longitude1) / width;
  1496. double divy = (latitude2 - latitude1) / height;
  1497. int i, j;
  1498. //do raster check
  1499. int[][] data = null;
  1500. boolean cellsReturned = !noCellsReturned;
  1501. if (cellsReturned) {
  1502. data = new int[width * height][2];
  1503. }
  1504. int p = 0;
  1505. for (j = 0; j < three_state_map[0].length; j++) {
  1506. for (i = 0; i < three_state_map.length; i++) {
  1507. if (three_state_map[i][j] == GI_PARTIALLY_PRESENT) {
  1508. //if it is partially present, do nothing
  1509. } else if ((j == 0 || three_state_map[i][j - 1] == GI_PARTIALLY_PRESENT)) {
  1510. if (i > 0
  1511. && (three_state_map[i - 1][j] == GI_FULLY_PRESENT
  1512. || three_state_map[i - 1][j] == GI_ABSENCE)) {
  1513. //use same as LHS
  1514. three_state_map[i][j] = three_state_map[i - 1][j];
  1515. } else if (isWithin_EPSG900913(j * divx + divx / 2 + longitude1, i * divy + divy / 2 + latitude1)) {
  1516. //if the previous was partially present, test
  1517. three_state_map[i][j] = GI_FULLY_PRESENT;
  1518. } //else absent
  1519. } else {
  1520. //if the previous was fully present, repeat
  1521. //if the previous was absent, repeat
  1522. three_state_map[i][j] = three_state_map[i][j - 1];
  1523. }
  1524. //apply to cells;
  1525. if (cellsReturned && three_state_map[i][j] != GI_UNDEFINED) { //undefined == absence
  1526. data[p][0] = j;
  1527. data[p][1] = i;
  1528. p++;
  1529. }
  1530. }
  1531. }
  1532. if (data != null) {
  1533. data = java.util.Arrays.copyOf(data, p);
  1534. }
  1535. return data;
  1536. }
  1537. }