field.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. # Flexlay - A Generic 2D Game Editor
  2. # Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. from typing import List
  17. import numpy.typing as npt
  18. import numpy as np
  19. class Field:
  20. @staticmethod
  21. def from_size(width: int, height: int) -> 'Field':
  22. return Field(np.zeros((height, width), dtype=np.uint32))
  23. @staticmethod
  24. def from_list(width: int, height: int, data: List[int]) -> 'Field':
  25. return Field(np.array(data, dtype=np.uint32).reshape(height, width))
  26. def __init__(self, data: npt.NDArray[np.uint32]) -> None:
  27. self._data = data
  28. def copy_region(self, x: int, y: int, w: int, h: int) -> 'Field':
  29. start_x = max(0, -x)
  30. start_y = max(0, -y)
  31. end_x = min(self.width, w - x)
  32. end_y = min(self.height, h - y)
  33. field = Field.from_size(w, h)
  34. for iy in range(start_y, end_y):
  35. for ix in range(start_x, end_x):
  36. field.put(x + ix, y + iy, self.at(ix, iy))
  37. return field
  38. def copy(self) -> 'Field':
  39. return Field(np.copy(self._data))
  40. def put(self, x: int, y: int, value: int) -> None:
  41. assert 0 <= value < np.iinfo(np.uint32).max, "{}: not in range".format(value)
  42. self._data[y][x] = value
  43. def at(self, x: int, y: int) -> int:
  44. assert (x >= 0 or x < self.width or y >= 0 or y < self.height)
  45. return int(self._data[y][x])
  46. def resize(self, w: int, h: int, x: int = 0, y: int = 0) -> None:
  47. field = self.copy_region(x, y, w, h)
  48. self._data = field._data
  49. @property
  50. def width(self) -> int:
  51. return int(self._data.shape[1])
  52. @property
  53. def height(self) -> int:
  54. return int(self._data.shape[0])
  55. def size(self) -> int:
  56. return int(self._data.size)
  57. def __contains__(self, key: int) -> bool:
  58. return bool(key in self._data)
  59. def __str__(self) -> str:
  60. result = "\n"
  61. for y in range(self.height):
  62. for x in range(self.width):
  63. result += "%04s " % self.at(x, y)
  64. result += "\n"
  65. return result
  66. # EOF #