PageRenderTime 29ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/ResInsight-2018.01.1/Fwk/VizFwk/LibRegGrid2D/cvfRegGrid2D.cpp

https://bitbucket.org/terraai/resinsight
C++ | 557 lines | 299 code | 118 blank | 140 comment | 59 complexity | faab31ebe2662cfd0bd3f163daa57056 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. //##################################################################################################
  2. //
  3. // Custom Visualization Core library
  4. // Copyright (C) 2011-2013 Ceetron AS
  5. //
  6. // This library may be used under the terms of either the GNU General Public License or
  7. // the GNU Lesser General Public License as follows:
  8. //
  9. // GNU General Public License Usage
  10. // This library is free software: you can redistribute it and/or modify
  11. // it under the terms of the GNU General Public License as published by
  12. // the Free Software Foundation, either version 3 of the License, or
  13. // (at your option) any later version.
  14. //
  15. // This library is distributed in the hope that it will be useful, but WITHOUT ANY
  16. // WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17. // FITNESS FOR A PARTICULAR PURPOSE.
  18. //
  19. // See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
  20. // for more details.
  21. //
  22. // GNU Lesser General Public License Usage
  23. // This library is free software; you can redistribute it and/or modify
  24. // it under the terms of the GNU Lesser General Public License as published by
  25. // the Free Software Foundation; either version 2.1 of the License, or
  26. // (at your option) any later version.
  27. //
  28. // This library is distributed in the hope that it will be useful, but WITHOUT ANY
  29. // WARRANTY; without even the implied warranty of MERCHANTABILITY or
  30. // FITNESS FOR A PARTICULAR PURPOSE.
  31. //
  32. // See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
  33. // for more details.
  34. //
  35. //##################################################################################################
  36. #include "cvfBase.h"
  37. #include "cvfRegGrid2D.h"
  38. namespace cvf {
  39. //==================================================================================================
  40. ///
  41. /// \class cvf::RegGrid2D
  42. /// \ingroup RegGrid2D
  43. ///
  44. ///
  45. ///
  46. //==================================================================================================
  47. //--------------------------------------------------------------------------------------------------
  48. ///
  49. //--------------------------------------------------------------------------------------------------
  50. RegGrid2D::RegGrid2D()
  51. {
  52. m_gridPointCountI = 0;
  53. m_gridPointCountJ = 0;
  54. m_spacing.set(0, 0);
  55. m_offset.set(0, 0);
  56. }
  57. //--------------------------------------------------------------------------------------------------
  58. ///
  59. //--------------------------------------------------------------------------------------------------
  60. void RegGrid2D::allocateGrid(int gridPointCountI, int gridPointCountJ)
  61. {
  62. CVF_ASSERT(gridPointCountI >= 0);
  63. CVF_ASSERT(gridPointCountJ >= 0);
  64. m_gridPointCountI = gridPointCountI;
  65. m_gridPointCountJ = gridPointCountJ;
  66. m_elevations.resize(static_cast<size_t>(gridPointCount()));
  67. }
  68. //--------------------------------------------------------------------------------------------------
  69. ///
  70. //--------------------------------------------------------------------------------------------------
  71. int RegGrid2D::gridPointCountI() const
  72. {
  73. return m_gridPointCountI;
  74. }
  75. //--------------------------------------------------------------------------------------------------
  76. ///
  77. //--------------------------------------------------------------------------------------------------
  78. int RegGrid2D::gridPointCountJ() const
  79. {
  80. return m_gridPointCountJ;
  81. }
  82. //--------------------------------------------------------------------------------------------------
  83. ///
  84. //--------------------------------------------------------------------------------------------------
  85. int RegGrid2D::gridPointCount() const
  86. {
  87. return m_gridPointCountI * m_gridPointCountJ;
  88. }
  89. //--------------------------------------------------------------------------------------------------
  90. ///
  91. //--------------------------------------------------------------------------------------------------
  92. Vec2d RegGrid2D::spacing() const
  93. {
  94. return m_spacing;
  95. }
  96. //--------------------------------------------------------------------------------------------------
  97. ///
  98. //--------------------------------------------------------------------------------------------------
  99. void RegGrid2D::setSpacing(const Vec2d& spacing)
  100. {
  101. CVF_ASSERT(spacing.x() >= 0);
  102. CVF_ASSERT(spacing.y() >= 0);
  103. m_spacing = spacing;
  104. }
  105. //--------------------------------------------------------------------------------------------------
  106. ///
  107. //--------------------------------------------------------------------------------------------------
  108. Vec2d RegGrid2D::offset() const
  109. {
  110. return m_offset;
  111. }
  112. //--------------------------------------------------------------------------------------------------
  113. ///
  114. //--------------------------------------------------------------------------------------------------
  115. void RegGrid2D::setOffset(const Vec2d& offset)
  116. {
  117. m_offset = offset;
  118. }
  119. //--------------------------------------------------------------------------------------------------
  120. ///
  121. //--------------------------------------------------------------------------------------------------
  122. Rectd RegGrid2D::boundingRectangle() const
  123. {
  124. Vec2d min = gridPointCoordinate(0, 0);
  125. Vec2d max = gridPointCoordinate(m_gridPointCountI - 1, m_gridPointCountJ - 1);
  126. return Rectd::fromMinMax(min, max);
  127. }
  128. //--------------------------------------------------------------------------------------------------
  129. ///
  130. //--------------------------------------------------------------------------------------------------
  131. void RegGrid2D::setElevation(int i, int j, double elevation)
  132. {
  133. int index = toArrayIndex(i, j);
  134. setElevation(index, elevation);
  135. }
  136. //--------------------------------------------------------------------------------------------------
  137. ///
  138. //--------------------------------------------------------------------------------------------------
  139. void RegGrid2D::setElevation(int arrayIndex, double elevation)
  140. {
  141. CVF_ASSERT(arrayIndex >= 0 && arrayIndex < gridPointCount());
  142. m_elevations.set(static_cast<size_t>(arrayIndex), elevation);
  143. }
  144. //--------------------------------------------------------------------------------------------------
  145. ///
  146. //--------------------------------------------------------------------------------------------------
  147. double RegGrid2D::elevation(int i, int j) const
  148. {
  149. int index = toArrayIndex(i, j);
  150. CVF_ASSERT(index >=0 && index < gridPointCount());
  151. return m_elevations[static_cast<size_t>(index)];
  152. }
  153. //--------------------------------------------------------------------------------------------------
  154. ///
  155. //--------------------------------------------------------------------------------------------------
  156. void RegGrid2D::setAllElevations(double elevation)
  157. {
  158. m_elevations.setAll(elevation);
  159. }
  160. //--------------------------------------------------------------------------------------------------
  161. ///
  162. //--------------------------------------------------------------------------------------------------
  163. void RegGrid2D::setElevations(const DoubleArray& elevations)
  164. {
  165. setElevations(elevations.ptr(), static_cast<int>(elevations.size()));
  166. }
  167. //--------------------------------------------------------------------------------------------------
  168. ///
  169. //--------------------------------------------------------------------------------------------------
  170. void RegGrid2D::setElevations(const double* elevations, int numElevationValues)
  171. {
  172. CVF_ASSERT(elevations);
  173. CVF_ASSERT(numElevationValues > 0);
  174. CVF_ASSERT(numElevationValues == gridPointCount());
  175. m_elevations.assign(elevations, static_cast<size_t>(numElevationValues));
  176. }
  177. //--------------------------------------------------------------------------------------------------
  178. /// Use bilinear interpolation to find value at specified coordinate
  179. ///
  180. /// Undefined is returned along the edge of the grid (between grid points)
  181. //--------------------------------------------------------------------------------------------------
  182. double RegGrid2D::pointElevation(const Vec2d& coord) const
  183. {
  184. Rectd region = boundingRectangle();
  185. if (!region.contains(coord)) return UNDEFINED_DOUBLE;
  186. int x1, y1;
  187. cellFromPoint(coord, &x1, &y1);
  188. Vec2d test = gridPointCoordinate(x1, y1);
  189. if (test == coord)
  190. {
  191. // Early exit if we hit exactly at a grid point
  192. return elevation(x1, y1);
  193. }
  194. // If we hit the outer edge of the reg grid, we are not able to compute the value using bilinear interpolation
  195. if (x1 >= m_gridPointCountI - 1) return UNDEFINED_DOUBLE;
  196. if (y1 >= m_gridPointCountJ - 1) return UNDEFINED_DOUBLE;
  197. CVF_ASSERT(x1 >= 0);
  198. CVF_ASSERT(y1 >= 0);
  199. CVF_ASSERT(x1 < m_gridPointCountI - 1);
  200. CVF_ASSERT(y1 < m_gridPointCountJ - 1);
  201. // Variable names taken from http://en.wikipedia.org/wiki/Bilinear_interpolation
  202. const Vec2i q11(x1, y1);
  203. const Vec2i q21(x1 + 1, y1);
  204. const Vec2i q22(x1 + 1, y1 + 1);
  205. const Vec2i q12(x1, y1 + 1);
  206. Vec2d q11Coord = gridPointCoordinate(q11.x(), q11.y());
  207. Vec2d q22Coord = gridPointCoordinate(q22.x(), q22.y());
  208. Vec2d localCoord = coord;// - m_offset;
  209. // Interpolate in x-direction
  210. double elevationR1 = ((q22Coord.x() - localCoord.x()) / m_spacing.x()) * elevation(q11.x(), q11.y()) +
  211. ((localCoord.x() - q11Coord.x()) / m_spacing.x()) * elevation(q21.x(), q21.y());
  212. double elevationR2 = ((q22Coord.x() - localCoord.x()) / m_spacing.x()) * elevation(q12.x(), q12.y()) +
  213. ((localCoord.x() - q11Coord.x()) / m_spacing.x()) * elevation(q22.x(), q22.y());
  214. // Interpolate intermediate results in y-direction
  215. double elevationValue = ((q22Coord.y() - localCoord.y()) / m_spacing.y()) * elevationR1 +
  216. ((localCoord.y() - q11Coord.y()) / m_spacing.y()) * elevationR2;
  217. return static_cast<double>(elevationValue);
  218. }
  219. //--------------------------------------------------------------------------------------------------
  220. ///
  221. //--------------------------------------------------------------------------------------------------
  222. void RegGrid2D::pointElevations(const Array<Vec2d>& coords, DoubleArray* elevations) const
  223. {
  224. CVF_ASSERT(elevations);
  225. size_t i;
  226. for (i = 0; i < coords.size(); i++)
  227. {
  228. elevations->add(pointElevation(coords[i]));
  229. }
  230. }
  231. //--------------------------------------------------------------------------------------------------
  232. ///
  233. //--------------------------------------------------------------------------------------------------
  234. void RegGrid2D::mapPolylineOnGrid(const Array<Vec2d>& lineCoords, Vec3dArray* elevations) const
  235. {
  236. CVF_ASSERT(lineCoords.size() >= 2);
  237. CVF_ASSERT(elevations);
  238. size_t i;
  239. for (i = 1; i < lineCoords.size(); i++)
  240. {
  241. mapLineSegmentOnGrid(lineCoords[i - 1], lineCoords[i], elevations);
  242. }
  243. }
  244. //--------------------------------------------------------------------------------------------------
  245. /// Map a line segment onto the grid
  246. ///
  247. /// Space is allocated for the incoming vector array, there are situations where number of allocated vectors
  248. /// is larger than number of vectors used.
  249. /// \internal See http://mathworld.wolfram.com/Line.html
  250. //--------------------------------------------------------------------------------------------------
  251. void RegGrid2D::mapLineSegmentOnGrid(const Vec2d& point1, const Vec2d& point2, Vec3dArray* intersections) const
  252. {
  253. CVF_ASSERT(intersections);
  254. double delta = 0.00001;
  255. Rectd gridRegion = boundingRectangle();
  256. Vec2d intersect1, intersect2;
  257. if (!gridRegion.segmentIntersect(point1, point2, &intersect1, &intersect2)) return;
  258. Vec2d ab = intersect2 - intersect1;
  259. // Find out if ij is increasing or decreasing
  260. int changeI = ab.x() > 0.0 ? 1 : -1;
  261. int changeJ = ab.y() > 0.0 ? 1 : -1;
  262. int gridI, gridJ;
  263. cellFromPoint(intersect1, &gridI, &gridJ);
  264. if (changeI == 1) gridI++;
  265. if (changeJ == 1) gridJ++;
  266. int maxGridI, maxGridJ;
  267. cellFromPoint(intersect2, &maxGridI, &maxGridJ);
  268. if (changeI == 1) maxGridI++;
  269. if (changeJ == 1) maxGridJ++;
  270. // Reserve space in array once
  271. // Will reserve number of grid points in each direction, plus endpoints
  272. size_t numItemsToAllocate = intersections->size() + Math::abs(maxGridI - gridI) + Math::abs(maxGridJ - gridJ) + 2;
  273. intersections->reserve(numItemsToAllocate);
  274. // Add line segment start if it not a grid point
  275. if ((intersect1 - gridPointCoordinate(gridI, gridJ)).lengthSquared() > delta)
  276. {
  277. intersections->add(Vec3d(intersect1, pointElevation(intersect1)));
  278. }
  279. Vec2d currentIntersection;
  280. bool horizontalLine = Math::abs(ab.y()) < delta;
  281. if (horizontalLine)
  282. {
  283. while (gridI != maxGridI)
  284. {
  285. Vec2d nextGridPointCoord = gridPointCoordinate(gridI, gridJ);
  286. currentIntersection.set(nextGridPointCoord.x(), intersect1.y());
  287. intersections->add(Vec3d(currentIntersection, pointElevation(currentIntersection)));
  288. gridI += changeI;
  289. }
  290. }
  291. bool verticalLine = Math::abs(ab.x()) < delta;
  292. if (verticalLine)
  293. {
  294. while (gridJ != maxGridJ)
  295. {
  296. Vec2d nextGridPointCoord = gridPointCoordinate(gridI, gridJ);
  297. currentIntersection.set(intersect1.x(), nextGridPointCoord.y());
  298. intersections->add(Vec3d(currentIntersection, pointElevation(currentIntersection)));
  299. gridJ += changeJ;
  300. }
  301. }
  302. if (!(horizontalLine || verticalLine))
  303. {
  304. // y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
  305. // y = m * (x - x1) + y1
  306. // y = mx + b
  307. double m = (intersect2.y() - intersect1.y()) / (intersect2.x() - intersect1.x());
  308. // b = y1 - (m * x1)
  309. double b = intersect1.y() - (m * intersect1.x());
  310. currentIntersection = intersect1;
  311. while ((gridI != maxGridI || gridJ != maxGridJ))
  312. {
  313. Vec2d nextGridPointCoord = gridPointCoordinate(gridI, gridJ);
  314. double nextYValue = m * nextGridPointCoord.x() + b;
  315. double nextXValue = (nextGridPointCoord.y() - b) / m;
  316. Vec2d horizontalIntersection(nextXValue, nextGridPointCoord.y());
  317. Vec2d verticalIntersection(nextGridPointCoord.x(), nextYValue);
  318. if ((horizontalIntersection - verticalIntersection).lengthSquared() < delta)
  319. {
  320. // Intersection at grid point, increase both i and j
  321. currentIntersection = horizontalIntersection;
  322. gridI += changeI;
  323. gridJ += changeJ;
  324. }
  325. else
  326. {
  327. // Find closest candidate
  328. if ((currentIntersection - horizontalIntersection).lengthSquared() < (currentIntersection - verticalIntersection).lengthSquared())
  329. {
  330. currentIntersection = horizontalIntersection;
  331. gridJ += changeJ;
  332. }
  333. else
  334. {
  335. currentIntersection = verticalIntersection;
  336. gridI += changeI;
  337. }
  338. }
  339. intersections->add(Vec3d(currentIntersection, pointElevation(currentIntersection)));
  340. }
  341. }
  342. // Add line segment end if this is not a grid point
  343. if ((currentIntersection - intersect2).lengthSquared() > delta)
  344. {
  345. intersections->add(Vec3d(intersect2, pointElevation(intersect2)));
  346. }
  347. }
  348. //--------------------------------------------------------------------------------------------------
  349. ///
  350. //--------------------------------------------------------------------------------------------------
  351. bool RegGrid2D::minMaxElevation(double* minElevation, double* maxElevation) const
  352. {
  353. if (gridPointCount() == 0) return false;
  354. double minValue = std::numeric_limits<double>::max();
  355. double maxValue = -std::numeric_limits<double>::max();
  356. size_t i;
  357. for (i = 0; i < m_elevations.size(); i++)
  358. {
  359. double elevationValue = m_elevations[i];
  360. if (elevationValue < minValue) minValue = elevationValue;
  361. if (elevationValue > maxValue) maxValue = elevationValue;
  362. }
  363. if (minElevation)
  364. {
  365. *minElevation = minValue;
  366. }
  367. if (maxElevation)
  368. {
  369. *maxElevation = maxValue;
  370. }
  371. return true;
  372. }
  373. //--------------------------------------------------------------------------------------------------
  374. ///
  375. //--------------------------------------------------------------------------------------------------
  376. bool RegGrid2D::minMaxElevationInRegion(int minI, int minJ, int maxI, int maxJ, double* minElevation, double* maxElevation) const
  377. {
  378. CVF_ASSERT(minI >= 0 && minI <= maxI);
  379. CVF_ASSERT(minJ >= 0 && minJ <= maxJ);
  380. if (gridPointCount() == 0) return false;
  381. double minValue = std::numeric_limits<double>::max();
  382. double maxValue = -std::numeric_limits<double>::max();
  383. int ix, iy;
  384. for (ix = minI; ix <= maxI; ix++)
  385. {
  386. for (iy = minJ; iy <= maxJ; iy++)
  387. {
  388. double elevationValue = elevation(ix, iy);
  389. if (elevationValue < minValue) minValue = elevationValue;
  390. if (elevationValue > maxValue) maxValue = elevationValue;
  391. }
  392. }
  393. if (minElevation)
  394. {
  395. *minElevation = minValue;
  396. }
  397. if (maxElevation)
  398. {
  399. *maxElevation = maxValue;
  400. }
  401. return true;
  402. }
  403. //--------------------------------------------------------------------------------------------------
  404. ///
  405. //--------------------------------------------------------------------------------------------------
  406. Vec2d RegGrid2D::gridPointCoordinate(int i, int j) const
  407. {
  408. CVF_ASSERT(i >= 0 && i < m_gridPointCountI);
  409. CVF_ASSERT(j >= 0 && j < m_gridPointCountJ);
  410. Vec2d coord(m_offset);
  411. coord.x() += m_spacing.x() * i;
  412. coord.y() += m_spacing.y() * j;
  413. return coord;
  414. }
  415. //--------------------------------------------------------------------------------------------------
  416. ///
  417. //--------------------------------------------------------------------------------------------------
  418. int RegGrid2D::toArrayIndex(int i, int j) const
  419. {
  420. CVF_ASSERT(i >= 0 && i < m_gridPointCountI);
  421. CVF_ASSERT(j >= 0 && j < m_gridPointCountJ);
  422. int elevationIndex = m_gridPointCountI * j + i;
  423. CVF_ASSERT(elevationIndex < gridPointCount());
  424. return elevationIndex;
  425. }
  426. //--------------------------------------------------------------------------------------------------
  427. ///
  428. //--------------------------------------------------------------------------------------------------
  429. void RegGrid2D::cellFromPoint(const Vec2d& coord, int* i, int* j) const
  430. {
  431. CVF_ASSERT(i && j);
  432. int gridI = static_cast<int>(Math::floor((coord.x() - offset().x()) / spacing().x()));
  433. int gridJ = static_cast<int>(Math::floor((coord.y() - offset().y()) / spacing().y()));
  434. CVF_ASSERT(gridI >= 0 && gridI < m_gridPointCountI);
  435. CVF_ASSERT(gridJ >= 0 && gridJ < m_gridPointCountJ);
  436. *i = gridI;
  437. *j = gridJ;
  438. }
  439. } // namespace cvf