💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
4.7 KiB

  1. /*
  2. * Copyright (C) 2017 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper Source Code.
  5. *
  6. * Antkeeper Source Code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper Source Code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper Source Code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "pheromone-matrix.hpp"
  20. #include "../configuration.hpp"
  21. #include <algorithm>
  22. #include <cmath>
  23. PheromoneMatrix::PheromoneMatrix(int columns, int rows, const Vector2& boundsMin, const Vector2& boundsMax)
  24. {
  25. this->columns = columns;
  26. this->rows = rows;
  27. size = columns * rows;
  28. bufferA = new float[size];
  29. bufferB = new float[size];
  30. activeBuffer = bufferA;
  31. this->boundsMin = boundsMin;
  32. this->boundsMax = boundsMax;
  33. matrixWidth = boundsMax.x - boundsMin.x;
  34. matrixHeight = boundsMax.y - boundsMin.y;
  35. matrixHalfWidth = matrixWidth * 0.5f;
  36. matrixHalfHeight = matrixHeight * 0.5f;
  37. cellWidth = matrixWidth / static_cast<float>(columns);
  38. cellHeight = matrixHeight / static_cast<float>(rows);
  39. diffusionKernelSize = 3;
  40. diffusionKernelRadius = 1;
  41. diffusionKernel = new float*[diffusionKernelSize];
  42. for (int i = 0; i < diffusionKernelSize; ++i)
  43. {
  44. diffusionKernel[i] = new float[diffusionKernelSize];
  45. }
  46. diffusionKernel[0][0] = 0.0083333f; diffusionKernel[0][1] = 0.0166667f; diffusionKernel[0][2] = 0.0083333f;
  47. diffusionKernel[1][0] = 0.0166667f; diffusionKernel[1][1] = 0.9f; diffusionKernel[1][2] = 0.0166667f;
  48. diffusionKernel[2][0] = 0.0083333f; diffusionKernel[2][1] = 0.0166667f; diffusionKernel[2][2] = 0.0083333f;
  49. clear();
  50. }
  51. PheromoneMatrix::~PheromoneMatrix()
  52. {
  53. delete[] bufferA;
  54. delete[] bufferB;
  55. for (int i = 0; i < diffusionKernelSize; ++i)
  56. {
  57. delete[] diffusionKernel[i];
  58. }
  59. delete[] diffusionKernel;
  60. }
  61. void PheromoneMatrix::clear()
  62. {
  63. for (int i = 0; i < size; ++i)
  64. {
  65. activeBuffer[i] = 0.0f;
  66. }
  67. }
  68. void PheromoneMatrix::evaporate()
  69. {
  70. for (int i = 0; i < size; ++i)
  71. {
  72. activeBuffer[i] *= EVAPORATION_FACTOR;
  73. }
  74. }
  75. void PheromoneMatrix::diffuse()
  76. {
  77. float* diffusionBuffer = (activeBuffer == bufferA) ? bufferB : bufferA;
  78. int index = 0;
  79. for (int i = 0; i < rows; ++i)
  80. {
  81. for (int j = 0; j < columns; ++j)
  82. {
  83. float concentration = 0.0f;
  84. for (int k = -diffusionKernelRadius; k <= diffusionKernelRadius; ++k)
  85. {
  86. int row = std::max<int>(0, std::min<int>(rows - 1, i + k));
  87. for (int l = -diffusionKernelRadius; l <= diffusionKernelRadius; ++l)
  88. {
  89. int column = std::max<int>(0, std::min<int>(columns - 1, j + l));
  90. concentration += activeBuffer[row * columns + column] * diffusionKernel[k + diffusionKernelRadius][l + diffusionKernelRadius];
  91. }
  92. }
  93. diffusionBuffer[index++] = concentration;
  94. }
  95. }
  96. activeBuffer = diffusionBuffer;
  97. }
  98. float PheromoneMatrix::query(const Vector2& position) const
  99. {
  100. int column = static_cast<int>((matrixHalfWidth + position.x) / cellWidth);
  101. int row = static_cast<int>((matrixHalfHeight + position.y) / cellHeight);
  102. if (columns < 0 || column >= columns || row < 0 || row >= rows)
  103. {
  104. return 0.0f;
  105. }
  106. int index = row * columns + column;
  107. return activeBuffer[index];
  108. }
  109. float PheromoneMatrix::query(const Vector2& position, float radius) const
  110. {
  111. float radiusSquared = radius * radius;
  112. float concentration = 0.0f;
  113. for (float y = position.y - radius; y <= position.y + radius; y += cellHeight)
  114. {
  115. int row = static_cast<int>((matrixHalfHeight + y) / cellHeight);
  116. if (row < 0)
  117. continue;
  118. else if (row >= rows)
  119. break;
  120. float dy = y - position.y;
  121. for (float x = position.x - radius; x <= position.x + radius; x += cellWidth)
  122. {
  123. int column = floor((matrixHalfWidth + x) / cellWidth);
  124. if (column < 0)
  125. continue;
  126. else if (column >= columns)
  127. break;
  128. float dx = x - position.x;
  129. float distanceSquared = dx * dx + dy * dy;
  130. if (distanceSquared <= radiusSquared)
  131. {
  132. concentration += activeBuffer[row * columns + column];
  133. }
  134. }
  135. }
  136. return concentration;
  137. }
  138. void PheromoneMatrix::deposit(const Vector2& position, float concentration)
  139. {
  140. int column = static_cast<int>((matrixHalfWidth + position.x) / cellWidth);
  141. int row = static_cast<int>((matrixHalfHeight + position.y) / cellHeight);
  142. if (columns < 0 || column >= columns || row < 0 || row >= rows)
  143. {
  144. return;
  145. }
  146. int index = row * columns + column;
  147. activeBuffer[index] += concentration;
  148. }