├── __init__.py ├── core ├── __init__.py ├── point.py ├── vector.py └── block.py ├── README.rst ├── LICENSE ├── tests └── test_point.py └── .gitignore /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | sympy-image 2 | ############## 3 | Some Sympy Objects Adapted to Image Manipulation 4 | 5 | This project is born from the following insight: 6 | 7 | Images are more or less rectangles with energy. 8 | 9 | This is not really a complete framework nor has any ambitious goals. 10 | 11 | Just two three subclasses to some objects of :code:`sympy.geometry` module 12 | that I found useful when dealing with images. 13 | 14 | Requirements 15 | ------------- 16 | - numpy 17 | - sympy 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 DKE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/test_point.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import numpy as np 4 | import sympy.geometry 5 | 6 | currentdir = os.getcwd() 7 | projectdir = os.path.join(os.pardir, currentdir) 8 | coredir = os.path.join(projectdir, 'core') 9 | os.chdir(coredir) 10 | 11 | from core import point 12 | 13 | os.chdir(currentdir) 14 | 15 | class PointTest(unittest.TestCase): 16 | "Tests for point class" 17 | 18 | def test_PointND_checkPointDirectionStatic(self): 19 | "Test checkPointDirection method of N dimensional point object" 20 | a = point.PointND((1, 2)) 21 | b = point.PointND((3, 6)) 22 | compval = True 23 | result = point.PointND._checkPointDirection(a, b) 24 | self.assertEqual(compval, result) 25 | 26 | def test_PointND_checkPointDirectionInstance(self): 27 | "Test checkPointDirection method of N dimensional point object" 28 | a = point.PointND((1, 2)) 29 | b = point.PointND((3, 6)) 30 | compval = True 31 | result = a.checkPointDirection(b) 32 | self.assertEqual(compval, result) 33 | 34 | def test_Point2D_carte2polar(self): 35 | "Test carte2polar method of 2 dimensional point object" 36 | compang = 0.6435 37 | compdist = 5.0 38 | a = point.Point2D(3,4) 39 | dist, ang = a.carte2polar() 40 | ang = round(ang, 4) 41 | self.assertEqual((compang, compdist), (ang, dist)) 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /core/point.py: -------------------------------------------------------------------------------- 1 | # Regrouping objects with respect to points 2 | # Author: Kaan Eraslan 3 | # Licensing: see, License 4 | 5 | # Packages 6 | 7 | import numpy as np 8 | from sympy.geometry import point 9 | 10 | from utils import jit_points as jpoints 11 | 12 | 13 | class PointND(point.Point): 14 | "N dimensional point object" 15 | 16 | def __init__(self, coords: ()): 17 | self.coords = coords 18 | self.ndim = len(coords) 19 | super().__init__(coords) 20 | 21 | def __str__(self): 22 | return "Point at {}".format(str(self.coords)) 23 | 24 | def __repr__(self): 25 | return "{0}-d point at {1}.".format(self.ndim, str(self.coords)) 26 | 27 | def __hash__(self): 28 | "Hash object" 29 | point_coordinates = self.coords 30 | return hash(point_coordinates) 31 | 32 | @staticmethod 33 | def _checkPointDirection(point1, point2): 34 | "Check whether two points are in same direction" 35 | assert point1.ndim == point2.ndim 36 | return point1.unit == point2.unit 37 | 38 | def checkPointDirection(self, point): 39 | "Wrapper for class instance" 40 | return self._checkPointDirection(point1=self, point2=point) 41 | 42 | 43 | class Point2D(point.Point2D): 44 | "Regroups methods with respect to point in 2d" 45 | 46 | def __init__(self, x=0, y=0, 47 | coordlist=None, 48 | degree=0): 49 | if coordlist is not None: 50 | assert len(coordlist) == 2 51 | super().__init__(coords=coordlist) 52 | x = coordlist[0] 53 | y = coordlist[1] 54 | else: 55 | super().__init__(coords=(x, y)) 56 | # 57 | self.angle_degree = degree 58 | self.radian = self.angle_degree * np.pi / 180 59 | self.old_x = 0 60 | self.old_y = 0 61 | self.new_y = 0 62 | self.new_x = 0 63 | self.x = x 64 | self.y = y 65 | 66 | def __call__(self): 67 | "Implements direct calls" 68 | return self.__str__() 69 | 70 | def carte2polar(self): 71 | "Transform cartesian coordinates to polar coordinates" 72 | x = self.x 73 | y = self.y 74 | distance = np.sqrt(x**2 + y**2) 75 | # formally sqrt((x - 0)^2 + (y-0)^2) 76 | angle = np.arctan2(y, x) 77 | 78 | return distance, angle 79 | 80 | 81 | class ImagePoint2D(Point2D): 82 | "Extends euclidean space points to images" 83 | 84 | def __init__(self, 85 | image: np.ndarray[[np.uint8]], 86 | x, y, 87 | costfn=lambda x: x, 88 | emap=None #: np.ndarray[[np.uint8]], 89 | spacePoint=None) -> None: 90 | self.x = x 91 | self.y = y 92 | if spacePoint is not None: 93 | self.x = spacePoint.x 94 | self.y = spacePoint.y 95 | super().__init__(x=self.x, y=self.y) 96 | self.costfn = costfn 97 | self.emap = emap 98 | self.image = image 99 | self.pixel_value = None 100 | self.pixel_energy = None 101 | # self.parent = ImagePoint2D() 102 | # self.child = ImagePoint2D() 103 | # 104 | 105 | def copy(self): 106 | "Duplicate the current instance of the class" 107 | point = ImagePoint2D(image=self.image) 108 | point.pixel_value = self.pixel_value 109 | point.pixel_energy = self.pixel_energy 110 | point.x = self.x 111 | point.y = self.y 112 | # 113 | return point 114 | 115 | def getPoint2D(self): 116 | "Get the euclidean space point representation of current point" 117 | point = Point2D(x=self.x, y=self.y) 118 | return point 119 | 120 | def getPointRowVal(self): 121 | "Get the row of the point from matrix" 122 | row = np.uint32(self.y) 123 | return self.image[row, :] 124 | 125 | def getPointColVal(self): 126 | "Get the col of the point from matrix" 127 | col = np.uint32(self.x) 128 | return self.image[:, col] 129 | 130 | def getPointVal(self): 131 | "Get value of the point from matrix" 132 | row, col = np.uint32(self.y), np.uint32(self.x) 133 | return self.image[row, col] 134 | 135 | def setPixelValueEnergy(self): 136 | "Set pixel value of the point" 137 | row = np.uint32(self.y) 138 | col = np.uint32(self.x) 139 | if self.image.ndim == 2: 140 | self.pixel_value = self.image[row, col] 141 | if self.emap is not None: 142 | self.pixel_energy = self.emap[row, col] 143 | else: 144 | self.pixel_energy = self.pixel_value 145 | elif self.image.ndim == 3: 146 | self.pixel_value = self.image[row, col, :] 147 | if self.emap is not None: 148 | self.pixel_energy = self.emap[row, col] 149 | else: 150 | self.pixel_energy = self.image[row, col, :].sum() 151 | # 152 | return self.pixel_value, self.pixel_energy 153 | 154 | def setPointProperties(self): 155 | "Wrapper for setting values to point properties" 156 | self.setPixelValueEnergy() 157 | -------------------------------------------------------------------------------- /core/vector.py: -------------------------------------------------------------------------------- 1 | # Regroups objects with respect to lines 2 | # Author: Kaan Eraslan 3 | # Licensing: see, LICENSE 4 | 5 | # Packages 6 | 7 | import numpy as np 8 | from sympy.geometry import line 9 | 10 | from point import ImagePoint2D, Point, Point2D 11 | 12 | 13 | class LocatedVector(line.Segment): 14 | "Located vector n dimensional" 15 | 16 | def __init__(self, spoint: Point, epoint: Point) -> None: 17 | super().__init__(spoint, epoint) 18 | self.spoint = spoint # start point 19 | self.epoint = epoint # end point 20 | self.ndim = len(spoint.coords) 21 | 22 | @staticmethod 23 | def isVectorEqual2Vector(vec1, vec2) -> bool: 24 | "Check whether 2 vectors are equal" 25 | # formula: for 2 vecs AB, and DC 26 | # they are equal if B-A = D-C 27 | # S.Lang 1986, p.10 28 | spoint1 = vec1.spoint 29 | epoint1 = vec1.epoint 30 | spoint2 = vec2.spoint 31 | epoint2 = vec2.epoint 32 | 33 | diff1 = spoint1 - epoint1 34 | diff2 = spoint2 - epoint2 35 | 36 | checkval = False 37 | 38 | if diff1 == diff2: 39 | checkval = True 40 | 41 | return checkval 42 | 43 | def __eq__(self, vec): 44 | "Implement == operator for instances" 45 | return self.isVectorEqual2Vector(vec1=self, vec2=vec) 46 | 47 | @staticmethod 48 | def hasVectorSameDirection2Vector(vec1, vec2) -> bool: 49 | "Check whether 2 vectors have same direction" 50 | return vec1.direction == vec2.direction 51 | 52 | def hasSameDirection2Vector(self, vec): 53 | "Wrapper method for class instances" 54 | return self.hasVectorSameDirection2Vector(vec1=self, vec2=vec) 55 | 56 | def getNorm(self): 57 | "Wrapper for class instance" 58 | return self.length 59 | 60 | 61 | class LocatedVector2D(LocatedVector): 62 | "Located Vector in Euclidean Space" 63 | 64 | def __init__( 65 | self, 66 | initial_point=None, # :Point2D: 67 | final_point=None, # :Point2D: 68 | segment=None): 69 | if segment is None and initial_point is None and final_point is None: 70 | raise ValueError( 71 | 'please provide either initial and final points or' 72 | ' a segment to initiate the vector') 73 | elif (segment is None and initial_point is None 74 | and final_point is not None): 75 | raise ValueError( 76 | 'please provide an initial point if a final point is provided' 77 | ' or provide a segment to initiate the vector') 78 | elif (segment is None and initial_point is not None 79 | and final_point is None): 80 | raise ValueError( 81 | 'please provide an final point if an initial point is provided' 82 | ' or provide a segment to initiate the vector') 83 | elif (segment is not None and initial_point is not None 84 | and final_point is not None): 85 | raise ValueError( 86 | 'please provide either initial and final points or' 87 | ' a segment to initiate the vector not both') 88 | elif (segment is not None and initial_point is None 89 | and final_point is None): 90 | spoint = segment.points[0] 91 | epoint = segment.points[1] 92 | super().__init__(spoint=spoint, epoint=epoint) 93 | elif (segment is None and initial_point is not None 94 | and final_point is not None): 95 | super().__init__(spoint=initial_point, epoint=final_point) 96 | 97 | self.pointList = [] 98 | 99 | @staticmethod 100 | def _getPoint2VecDistancePoint(aVec, point, isMin: bool): 101 | "Get closest/farthest point on vec with distance to the given point" 102 | points = aVec.pointList 103 | npoint = Point2D([0, 0]) # point at origin 104 | if isMin is True: 105 | retval = float('inf') 106 | else: 107 | retval = float('-inf') 108 | 109 | for p in points: 110 | # assert p.ndim == point.ndim 111 | vec = LocatedVector(p, point) 112 | vecnorm = vec.getNorm() 113 | checkval = bool 114 | 115 | if isMin is True: 116 | checkval = vecnorm < retval 117 | else: 118 | checkval = vecnorm > retval 119 | 120 | if checkval: 121 | retval = vecnorm 122 | npoint = p 123 | return npoint, retval 124 | 125 | @classmethod 126 | def _getNearestPointAndDistance(cls, vec, point): 127 | "Get the closest point on the line with distance or not to given point" 128 | return cls._getPoint2VecDistancePoint(vec, point, True) 129 | 130 | @classmethod 131 | def _getMinDistance2Point( 132 | cls, 133 | vec, #: LocatedVector2D, 134 | point: Point2D) -> float: 135 | "Get distance to line" 136 | distancePoint = cls.getNearestPointAndDistance(vec, point) 137 | 138 | return distancePoint[1] 139 | 140 | @classmethod 141 | def _getNearestPointOnVec(cls, vec, point) -> Point2D: 142 | "Get closest point on vec to the given point" 143 | distancePoint = cls.getNearestPointAndDistance(vec, point) 144 | return distancePoint[0] 145 | 146 | @classmethod 147 | def _getFarthestPointAndDistance(cls, vec, point): 148 | "Get farthest point and distance on the vector with given point" 149 | return cls._getPoint2VecDistancePoint(vec, point, False) 150 | 151 | @classmethod 152 | def _getMaxDistance2Point(cls, vec, point) -> float: 153 | "Get farthest point and distance on the vec with given point" 154 | distancePoint = cls.getFarthestPointAndDistance(vec, point) 155 | return distancePoint[1] 156 | 157 | @classmethod 158 | def _getFarthestPointOnVec(cls, vec, point) -> Point2D: 159 | "Get farthest point and distance on the vec with given point" 160 | distancePoint = cls.getFarthestPointAndDistance(vec, point) 161 | return distancePoint[0] 162 | 163 | @classmethod 164 | def _getManhattanDistance(cls, point1_: Point2D, point2_: Point2D) -> int: 165 | "Get manhattan distance between two points" 166 | return point1_.taxicab_distance(point2_) 167 | 168 | @staticmethod 169 | def _getStraightLine(point1: Point2D, point2: Point2D) -> list: 170 | """ 171 | Get line from points including the points included in the line 172 | Bresenham's line algorithm adapted from pseudocode in wikipedia: 173 | https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm 174 | 175 | image should be grayscale 176 | 177 | """ 178 | # define local variables for readability 179 | P1X = point1.x 180 | P1Y = point1.y 181 | P2X = point2.x 182 | P2Y = point2.y 183 | 184 | # difference and absolute difference between points 185 | # used to calculate slope and relative location between points 186 | diffX = P2X - P1X 187 | diffXa = np.absolute(diffX, dtype="int32") 188 | diffY = P2Y - P1Y 189 | diffYa = np.absolute(diffY, dtype="int32") 190 | # 191 | steepx = 1 192 | if P1X < P2X: 193 | steepx = 1 194 | else: 195 | steepx = -1 196 | # 197 | if P1Y < P2Y: 198 | steepy = 1 199 | else: 200 | steepy = -1 201 | # 202 | div_term = diffXa 203 | # 204 | if diffXa > diffYa: 205 | div_term = diffXa 206 | else: 207 | div_term = -diffYa 208 | # 209 | error = div_term / 2 210 | # 211 | error2 = 0 212 | # 213 | arrival_condition = bool((P1X, P1Y) == (P2X, P2Y)) 214 | # 215 | line_points = [] 216 | initial_p = Point2D([P1X, P1Y]) 217 | line_points.append(initial_p) 218 | # 219 | while arrival_condition is False: 220 | error2 = error 221 | if error2 > -diffXa: 222 | error = error - diffYa 223 | P1X = P1X + steepx 224 | # 225 | if error2 < diffYa: 226 | error = error + diffXa 227 | P1Y = P1Y + steepy 228 | # 229 | # Check 230 | point = Point2D([P1X, P1Y]) 231 | line_points.append(point) 232 | arrival_condition = bool((P1X, P1Y) == (P2X, P2Y)) 233 | # 234 | return line_points 235 | 236 | @staticmethod 237 | def _getStraightDistance(p1: Point2D, p2: Point2D) -> np.float: 238 | "Get straight distance between two points" 239 | vec = LocatedVector(p1, p2) 240 | vecnorm = vec.getNorm() 241 | # 242 | return vecnorm 243 | 244 | @staticmethod 245 | def _getVec2VecDistancePointVec(vec1, vec2, isMin): 246 | "Get least/farthest distance" 247 | spoints = vec1.pointList # starting points 248 | nspoint = Point2D([0, 0]) 249 | nepoint = Point2D([0, 1]) 250 | svec = None 251 | 252 | if isMin is True: 253 | distance = float('inf') 254 | else: 255 | distance = float('-inf') 256 | 257 | for sp in spoints: 258 | # 259 | distancePoint = vec2.getPoint2VecDistancePoint( 260 | point=sp, isMin=isMin) 261 | epoint = distancePoint[0] 262 | dist = distancePoint[1] 263 | 264 | if isMin is True: 265 | checkval = dist <= distance 266 | else: 267 | checkval = dist > distance 268 | 269 | if checkval: 270 | distance = dist 271 | nspoint = sp 272 | nepoint = epoint 273 | svec = LocatedVector2D(nspoint, nepoint) 274 | # 275 | svec.setVecProperties() 276 | return nspoint, nepoint, svec, distance 277 | 278 | @classmethod 279 | def getVec2VecDistancePointVec(cls, vec1, vec2, isMin): 280 | "Wrapper for staticmethod" 281 | return cls._getVec2VecDistancePointVec(vec1, vec2, isMin) 282 | 283 | @classmethod 284 | def getVec2VecMinDistance(cls, vec1, vec2): 285 | "Get min distance between two located vectors" 286 | distancePointsVec = cls.getVec2VecDistancePointVec( 287 | vec1, vec2, isMin=True) 288 | return distancePointsVec[3] 289 | 290 | @classmethod 291 | def getVec2VecMaxDistance(cls, vec1, vec2): 292 | "Get max distance between two located vectors" 293 | distancePointsVec = cls.getVec2VecDistancePointVec( 294 | vec1, vec2, isMin=False) 295 | return distancePointsVec[3] 296 | 297 | @classmethod 298 | def getVec2VecMinVec(cls, vec1, vec2): 299 | "Get min distance between two located vectors" 300 | distancePointsVec = cls.getVec2VecDistancePointVec( 301 | vec1, vec2, isMin=True) 302 | return distancePointsVec[2] 303 | 304 | @classmethod 305 | def getVec2VecMaxVec(cls, vec1, vec2): 306 | "Get max distance between two located vectors" 307 | distancePointsVec = cls.getVec2VecDistancePointVec( 308 | vec1, vec2, isMin=False) 309 | return distancePointsVec[2] 310 | 311 | @classmethod 312 | def getVec2VecMinSpoint(cls, vec1, vec2): 313 | "Get min distance between two located vectors" 314 | distancePointsVec = cls.getVec2VecDistancePointVec( 315 | vec1, vec2, isMin=True) 316 | return distancePointsVec[0] 317 | 318 | @classmethod 319 | def getVec2VecMaxSpoint(cls, vec1, vec2): 320 | "Get max distance between two located vectors" 321 | distancePointsVec = cls.getVec2VecDistancePointVec( 322 | vec1, vec2, isMin=False) 323 | return distancePointsVec[0] 324 | 325 | @classmethod 326 | def getVec2VecMinEpoint(cls, vec1, vec2): 327 | "Get min distance between two located vectors" 328 | distancePointsVec = cls.getVec2VecDistancePointVec( 329 | vec1, vec2, isMin=True) 330 | return distancePointsVec[1] 331 | 332 | @classmethod 333 | def getVec2VecMaxEpoint(cls, vec1, vec2): 334 | "Get max distance between two located vectors" 335 | distancePointsVec = cls.getVec2VecDistancePointVec( 336 | vec1, vec2, isMin=False) 337 | return distancePointsVec[1] 338 | 339 | def setLine(self): 340 | "Set line from starting point to end point" 341 | self.pointList = self._getStraightLine( 342 | point1=self.p_init, point2=self.p_final) 343 | return None 344 | 345 | def setVecProperties(self): 346 | "Wrapper for setters" 347 | self.setLine() 348 | 349 | return None 350 | 351 | def getMinDistance2Point(self, point) -> float: 352 | "Get min distance of the given point to line" 353 | assert point.ndim == self.ndim 354 | return self._getMinDistance2Point(vec=self, point=point) 355 | 356 | def getNearestPoint2Point(self, point) -> Point2D: 357 | "Get nearest point on the vector to the given point" 358 | assert point.ndim == self.ndim 359 | return self._getNearestPointOnVec(vec=self, point=point) 360 | 361 | def getMaxDistancePoint(self, point): 362 | "Get max distance of the given point to line" 363 | assert point.ndim == self.ndim 364 | return self._getMaxDistance2Point(vec=self, point=point) 365 | 366 | def getFarthestPoint2Point(self, point) -> Point2D: 367 | "Get farthest point on the vector to the given point" 368 | assert point.ndim == self.ndim 369 | return self._getFarthestPointOnVec(vec=self, point=point) 370 | 371 | def getMinMaxDistance2Vec(self, isMin, vec): 372 | "Get minimum or maximum distance to given vector from self" 373 | assert self.ndim == vec.ndim 374 | distance = None 375 | if isMin is True: 376 | distance = self.getVec2VecMinDistance(vec1=self, vec2=vec) 377 | else: 378 | distance = self.getVec2VecMaxDistance(vec1=self, vec2=vec) 379 | return distance 380 | 381 | def getMinMaxVec2Vec(self, isMin, vec): 382 | "Get minimum or maximum distance vector to given vector from self" 383 | assert self.ndim == vec.ndim 384 | if isMin is True: 385 | nvec = self.getVec2VecMinVec(vec1=self, vec2=vec) 386 | else: 387 | nvec = self.getVec2VecMaxVec(vec1=self, vec2=vec) 388 | return nvec 389 | 390 | def getMinDistance2Vec(self, vec): 391 | "Get min distance to given vec" 392 | assert self.ndim == vec.ndim 393 | return self.getVec2VecMinDistance(vec1=self, vec2=vec) 394 | 395 | def getMaxDistance2Vec(self, vec): 396 | "Get max distance to given vec" 397 | assert self.ndim == vec.ndim 398 | return self.getVec2VecMaxDistance(vec1=self, vec2=vec) 399 | 400 | def getMinDistanceVec2Vec(self, vec) -> LocatedVector: 401 | "Get vec that has the length min distance to given vec" 402 | assert self.ndim == vec.ndim 403 | return self.getMinMaxVec2Vec(isMin=True, vec=vec) 404 | 405 | def getMaxDistanceVec2Vec(self, vec) -> LocatedVector: 406 | "Get vec that has the length max distance to given vec" 407 | assert self.ndim == vec.ndim 408 | return self.getMinMaxVec2Vec(isMin=False, vec=vec) 409 | 410 | 411 | class ImageLocatedVector2D(LocatedVector2D): 412 | "Extends the line in euclidean space to images" 413 | 414 | def __init__( 415 | self, 416 | image: np.ndarray[[np.uint8]], 417 | vec=None, 418 | initial_point=None, # :Point2D: 419 | final_point=None, # :Point2D: 420 | segment=None) -> None: 421 | "" 422 | if vec is None: 423 | super().__init__(initial_point, final_point, segment) 424 | else: 425 | spoint = vec.spoint 426 | epoint = vec.epoint 427 | super().__init__(spoint, epoint) 428 | self.image = image 429 | self.charge = 0 430 | 431 | @staticmethod 432 | def getConditionDistanceCharge(minDist, minCharge, distanceParentScope, 433 | distanceLocalScope, chargeParentScope, 434 | chargeLocalScope): 435 | "Set evaluation condition with respect to given booleans" 436 | if minDist is True and minCharge is None: 437 | condition = distanceLocalScope <= distanceParentScope 438 | elif minDist is False and minCharge is None: 439 | condition = distanceLocalScope > distanceParentScope 440 | elif minCharge is True and minDist is None: 441 | condition = chargeLocalScope <= chargeParentScope 442 | elif minCharge is False and minDist is None: 443 | condition = chargeLocalScope > chargeParentScope 444 | elif minDist is True and minCharge is True: 445 | condition = bool(distanceLocalScope <= distanceParentScope 446 | and chargeLocalScope <= chargeParentScope) 447 | elif minDist is True and minCharge is False: 448 | condition = bool(distanceLocalScope <= distanceParentScope 449 | and chargeLocalScope > chargeParentScope) 450 | elif minDist is False and minCharge is True: 451 | condition = bool(distanceLocalScope > distanceParentScope 452 | and chargeLocalScope <= chargeParentScope) 453 | elif minDist is False and minCharge is False: 454 | condition = bool(distanceLocalScope > distanceParentScope 455 | and chargeLocalScope > chargeParentScope) 456 | return condition 457 | 458 | @staticmethod 459 | def getDistanceChargeVariables(minDist: bool, minCharge: bool): 460 | "Get distance charge variables based on given conditions" 461 | if minDist is True and minCharge is None: 462 | distance = float('inf') 463 | charge = None 464 | elif minDist is False and minCharge is None: 465 | distance = float('-inf') 466 | charge = None 467 | elif minCharge is True and minDist is None: 468 | distance = None 469 | charge = float('inf') 470 | elif minCharge is False and minDist is None: 471 | distance = None 472 | charge = float('-inf') 473 | elif minDist is True and minCharge is True: 474 | distance = float('inf') 475 | charge = float('inf') 476 | elif minDist is True and minCharge is False: 477 | distance = float('inf') 478 | charge = float('-inf') 479 | elif minDist is False and minCharge is True: 480 | distance = float('-inf') 481 | charge = float('inf') 482 | elif minDist is False and minCharge is False: 483 | distance = float('-inf') 484 | charge = float('-inf') 485 | return distance, charge 486 | 487 | @classmethod 488 | def _getVec2VecDistancePointChargeVec( 489 | cls, 490 | vec1, 491 | vec2, 492 | isMinDistance, # boolean or none 493 | isMinCharge): 494 | "Reinterpretates the base class static method to include charge" 495 | # 496 | spoints = vec1.pointList # starting points 497 | nspoint = None 498 | nepoint = None 499 | svec = None 500 | distance, charge = cls.getDistanceChargeVariables( 501 | minDist=isMinDistance, minCharge=isMinCharge) 502 | 503 | for sp in spoints: 504 | # 505 | distancePoint = vec2.getPoint2VecDistancePoint( 506 | point=sp, isMin=isMinDistance) 507 | epoint = distancePoint[0] 508 | dist = distancePoint[1] 509 | tempvec = ImageLocatedVector2D(sp, epoint) 510 | tempvec.setVecProperties() 511 | tempcharge = tempvec.charge 512 | 513 | checkval = cls.getConditionDstanceCharge( 514 | minDist=isMinDistance, 515 | minCharge=isMinCharge, 516 | distanceParentScope=distance, 517 | distanceLocalScope=dist, 518 | chargeParentScope=charge, 519 | chargeLocalScope=tempcharge) 520 | if checkval: 521 | distance = dist 522 | nspoint = sp 523 | nepoint = epoint 524 | svec = tempvec 525 | charge = tempcharge 526 | # 527 | return nspoint, nepoint, svec, distance, charge 528 | 529 | @classmethod 530 | def getVec2VecDistancePointVec(cls, vec1, vec2, isMin: bool): 531 | "Overrides the base class method" 532 | return cls._getVec2VecDistancePointChargeVec( 533 | vec1, vec2, isMinDistance=isMin, isMinCharge=None)[:4] 534 | 535 | @classmethod 536 | def getVec2VecMinCharge(cls, vec1, vec2): 537 | "Get min charge between two located vectors" 538 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 539 | vec1, vec2, isMinDistance=None, isMinCharge=True) 540 | return distancePointsVec[4] 541 | 542 | @classmethod 543 | def getVec2VecMaxCharge(cls, vec1, vec2): 544 | "Get min distance between two located vectors" 545 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 546 | vec1, vec2, isMinDistance=None, isMinCharge=False) 547 | return distancePointsVec[4] 548 | 549 | @classmethod 550 | def getVec2VecMinDistanceMaxChargeDist(cls, vec1, vec2): 551 | "Get min distance between two located vectors" 552 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 553 | vec1, vec2, isMinDistance=True, isMinCharge=False) 554 | return distancePointsVec[3] 555 | 556 | @classmethod 557 | def getVec2VecMinDistanceMinChargeDist(cls, vec1, vec2): 558 | "Get min distance between two located vectors" 559 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 560 | vec1, vec2, isMinDistance=True, isMinCharge=True) 561 | return distancePointsVec[3] 562 | 563 | @classmethod 564 | def getVec2VecMaxDistanceMaxChargeDist(cls, vec1, vec2): 565 | "Get max distance between two located vectors" 566 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 567 | vec1, vec2, isMinDistance=False, isMinCharge=False) 568 | return distancePointsVec[3] 569 | 570 | @classmethod 571 | def getVec2VecMaxDistanceMinChargeDist(cls, vec1, vec2): 572 | "Get max distance between two located vectors" 573 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 574 | vec1, vec2, isMinDistance=False, isMinCharge=True) 575 | return distancePointsVec[3] 576 | 577 | @classmethod 578 | def getVec2VecMinDistanceMaxChargeCharge(cls, vec1, vec2): 579 | "Get min distance between two located vectors" 580 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 581 | vec1, vec2, isMinDistance=True, isMinCharge=False) 582 | return distancePointsVec[4] 583 | 584 | @classmethod 585 | def getVec2VecMinDistanceMinChargeCharge(cls, vec1, vec2): 586 | "Get min distance between two located vectors" 587 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 588 | vec1, vec2, isMinDistance=True, isMinCharge=True) 589 | return distancePointsVec[4] 590 | 591 | @classmethod 592 | def getVec2VecMaxDistanceMaxChargeCharge(cls, vec1, vec2): 593 | "Get max distance between two located vectors" 594 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 595 | vec1, vec2, isMinDistance=False, isMinCharge=False) 596 | return distancePointsVec[4] 597 | 598 | @classmethod 599 | def getVec2VecMaxDistanceMinChargeCharge(cls, vec1, vec2): 600 | "Get max distance between two located vectors" 601 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 602 | vec1, vec2, isMinDistance=False, isMinCharge=True) 603 | return distancePointsVec[4] 604 | 605 | @classmethod 606 | def getVec2VecMinDistanceMaxChargeSPoint(cls, vec1, vec2): 607 | "Get min distance between two located vectors" 608 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 609 | vec1, vec2, isMinDistance=True, isMinCharge=False) 610 | return distancePointsVec[0] 611 | 612 | @classmethod 613 | def getVec2VecMinDistanceMinChargeSPoint(cls, vec1, vec2): 614 | "Get min distance between two located vectors" 615 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 616 | vec1, vec2, isMinDistance=True, isMinCharge=True) 617 | return distancePointsVec[0] 618 | 619 | @classmethod 620 | def getVec2VecMaxDistanceMaxChargeSPoint(cls, vec1, vec2): 621 | "Get max distance between two located vectors" 622 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 623 | vec1, vec2, isMinDistance=False, isMinCharge=False) 624 | return distancePointsVec[0] 625 | 626 | @classmethod 627 | def getVec2VecMaxDistanceMinChargeSPoint(cls, vec1, vec2): 628 | "Get max distance between two located vectors" 629 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 630 | vec1, vec2, isMinDistance=False, isMinCharge=True) 631 | return distancePointsVec[0] 632 | 633 | @classmethod 634 | def getVec2VecMinDistanceMaxChargeEPoint(cls, vec1, vec2): 635 | "Get min distance between two located vectors" 636 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 637 | vec1, vec2, isMinDistance=True, isMinCharge=False) 638 | return distancePointsVec[1] 639 | 640 | @classmethod 641 | def getVec2VecMinDistanceMinChargeEPoint(cls, vec1, vec2): 642 | "Get min distance between two located vectors" 643 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 644 | vec1, vec2, isMinDistance=True, isMinCharge=True) 645 | return distancePointsVec[1] 646 | 647 | @classmethod 648 | def getVec2VecMaxDistanceMaxChargeEPoint(cls, vec1, vec2): 649 | "Get max distance between two located vectors" 650 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 651 | vec1, vec2, isMinDistance=False, isMinCharge=False) 652 | return distancePointsVec[1] 653 | 654 | @classmethod 655 | def getVec2VecMaxDistanceMinChargeEPoint(cls, vec1, vec2): 656 | "Get max distance between two located vectors" 657 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 658 | vec1, vec2, isMinDistance=False, isMinCharge=True) 659 | return distancePointsVec[1] 660 | 661 | @classmethod 662 | def getVec2VecMinDistanceMaxChargeVec(cls, vec1, vec2): 663 | "Get min distance between two located vectors" 664 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 665 | vec1, vec2, isMinDistance=True, isMinCharge=False) 666 | return distancePointsVec[2] 667 | 668 | @classmethod 669 | def getVec2VecMinDistanceMinChargeVec(cls, vec1, vec2): 670 | "Get min distance between two located vectors" 671 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 672 | vec1, vec2, isMinDistance=True, isMinCharge=True) 673 | return distancePointsVec[2] 674 | 675 | @classmethod 676 | def getVec2VecMaxDistanceMaxChargeVec(cls, vec1, vec2): 677 | "Get max distance between two located vectors" 678 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 679 | vec1, vec2, isMinDistance=False, isMinCharge=False) 680 | return distancePointsVec[2] 681 | 682 | @classmethod 683 | def getVec2VecMaxDistanceMinChargeVec(cls, vec1, vec2): 684 | "Get max distance between two located vectors" 685 | distancePointsVec = cls._getVec2VecDistancePointChargeVec( 686 | vec1, vec2, isMinDistance=False, isMinCharge=True) 687 | return distancePointsVec[2] 688 | 689 | def getMinCharge2Vec(self, vec): 690 | "Get minimum charge to vector" 691 | return self.getVec2VecMinCharge(vec1=self, vec2=vec) 692 | 693 | def getMaxCharge2Vec(self, vec): 694 | "Get minimum charge to vector" 695 | return self.getVec2VecMaxCharge(vec1=self, vec2=vec) 696 | 697 | def getMinDistMaxCharge2VecDistance(self, vec) -> float: 698 | """ 699 | Get minimum distance with maximum charge to vector 700 | 701 | Return 702 | ------- 703 | distance 704 | """ 705 | return self.getVec2VecMinDistanceMaxChargeDist(vec1=self, vec2=vec) 706 | 707 | def getMinDistMinCharge2VecDistance(self, vec) -> float: 708 | """ 709 | Get minimum distance with minimum charge to vector 710 | 711 | Return 712 | ------- 713 | distance 714 | 715 | """ 716 | return self.getVec2VecMinDistanceMinChargeDist(vec1=self, vec2=vec) 717 | 718 | def getMaxDistMaxCharge2VecDistance(self, vec) -> float: 719 | """ 720 | Get maximum distance with maximum charge to vector 721 | 722 | Return 723 | ------- 724 | distance 725 | 726 | 727 | """ 728 | return self.getVec2VecMaxDistanceMaxChargeDist(vec1=self, vec2=vec) 729 | 730 | def getMaxDistMinCharge2VecDistance(self, vec) -> float: 731 | """ 732 | Get maximum distance with maximum charge to vector 733 | 734 | Return 735 | ------- 736 | distance 737 | 738 | """ 739 | return self.getVec2VecMaxDistanceMinChargeDist(vec1=self, vec2=vec) 740 | 741 | def getMinDistMaxCharge2VecCharge(self, vec) -> float: 742 | """ 743 | Get minimum distance with maximum charge to vector 744 | 745 | Return 746 | ------- 747 | charge 748 | """ 749 | return self.getVec2VecMinDistanceMaxChargeCharge(vec1=self, vec2=vec) 750 | 751 | def getMinDistMinCharge2VecCharge(self, vec) -> float: 752 | """ 753 | Get minimum distance with minimum charge to vector 754 | 755 | Return 756 | ------- 757 | charge 758 | 759 | """ 760 | return self.getVec2VecMinDistanceMinChargeCharge(vec1=self, vec2=vec) 761 | 762 | def getMaxDistMaxCharge2VecCharge(self, vec) -> float: 763 | """ 764 | Get maximum distance with maximum charge to vector 765 | 766 | Return 767 | ------- 768 | charge 769 | 770 | """ 771 | return self.getVec2VecMaxDistanceMaxChargeCharge(vec1=self, vec2=vec) 772 | 773 | def getMaxDistMinCharge2VecCharge(self, vec) -> float: 774 | """ 775 | Get maximum distance with maximum charge to vector 776 | 777 | Return 778 | ------- 779 | charge 780 | 781 | """ 782 | return self.getVec2VecMaxDistanceMinChargeCharge(vec1=self, vec2=vec) 783 | 784 | def getMinDistMaxCharge2VecSPoint(self, vec) -> ImagePoint2D: 785 | """ 786 | Get minimum distance with maximum charge to vector 787 | 788 | Return 789 | ------- 790 | spoint: starting point which is on self 791 | """ 792 | return self.getVec2VecMinDistanceMaxChargeSPoint(vec1=self, vec2=vec) 793 | 794 | def getMinDistMinCharge2VecSPoint(self, vec) -> ImagePoint2D: 795 | """ 796 | Get minimum distance with minimum charge to vector 797 | 798 | Return 799 | ------- 800 | spoint: starting point which is on self 801 | 802 | """ 803 | return self.getVec2VecMinDistanceMinChargeSPoint(vec1=self, vec2=vec) 804 | 805 | def getMaxDistMaxCharge2VecSPoint(self, vec) -> ImagePoint2D: 806 | """ 807 | Get maximum distance with maximum charge to vector 808 | 809 | Return 810 | ------- 811 | spoint: starting point which is on self 812 | 813 | """ 814 | return self.getVec2VecMaxDistanceMaxChargeSPoint(vec1=self, vec2=vec) 815 | 816 | def getMaxDistMinCharge2VecSPoint(self, vec) -> ImagePoint2D: 817 | """ 818 | Get maximum distance with maximum charge to vector 819 | 820 | Return 821 | ------- 822 | spoint: starting point which is on self 823 | 824 | """ 825 | return self.getVec2VecMaxDistanceMinChargeSPoint(vec1=self, vec2=vec) 826 | 827 | def getMinDistMaxCharge2VecEPoint(self, vec) -> ImagePoint2D: 828 | """ 829 | Get minimum distance with maximum charge to vector 830 | 831 | Return 832 | ------- 833 | epoint: ending point which is on vec 834 | """ 835 | return self.getVec2VecMinDistanceMaxChargeEPoint(vec1=self, vec2=vec) 836 | 837 | def getMinDistMinCharge2VecEPoint(self, vec) -> ImagePoint2D: 838 | """ 839 | Get minimum distance with minimum charge to vector 840 | 841 | Return 842 | ------- 843 | epoint: ending point which is on vec 844 | 845 | """ 846 | return self.getVec2VecMinDistanceMinChargeEPoint(vec1=self, vec2=vec) 847 | 848 | def getMaxDistMaxCharge2VecEPoint(self, vec) -> ImagePoint2D: 849 | """ 850 | Get maximum distance with maximum charge to vector 851 | 852 | Return 853 | ------- 854 | epoint: ending point which is on vec 855 | 856 | """ 857 | return self.getVec2VecMaxDistanceMaxChargeEPoint(vec1=self, vec2=vec) 858 | 859 | def getMaxDistMinCharge2VecEPoint(self, vec) -> ImagePoint2D: 860 | """ 861 | Get maximum distance with maximum charge to vector 862 | 863 | Return 864 | ------- 865 | epoint: ending point which is on vec 866 | 867 | """ 868 | return self.getVec2VecMaxDistanceMinChargeEPoint(vec1=self, vec2=vec) 869 | 870 | def getMinDistMaxCharge2VecVec(self, vec) -> ImageLocatedVector2D: 871 | """ 872 | Get minimum distance with maximum charge to vector 873 | 874 | Return 875 | ------- 876 | vec: vector between the vec and self fulfilling the conditions 877 | """ 878 | return self.getVec2VecMinDistanceMaxChargeVec(vec1=self, vec2=vec) 879 | 880 | def getMinDistMinCharge2VecVec(self, vec) -> ImageLocatedVector2D: 881 | """ 882 | Get minimum distance with minimum charge to vector 883 | 884 | Return 885 | ------- 886 | vec: vector between the vec and self fulfilling the conditions 887 | 888 | """ 889 | return self.getVec2VecMinDistanceMinChargeVec(vec1=self, vec2=vec) 890 | 891 | def getMaxDistMaxCharge2VecVec(self, vec) -> ImageLocatedVector2D: 892 | """ 893 | Get maximum distance with maximum charge to vector 894 | 895 | Return 896 | ------- 897 | vec: vector between the vec and self fulfilling the conditions 898 | 899 | """ 900 | return self.getVec2VecMaxDistanceMaxChargeVec(vec1=self, vec2=vec) 901 | 902 | def getMaxDistMinCharge2VecVec(self, vec) -> ImageLocatedVector2D: 903 | """ 904 | Get maximum distance with maximum charge to vector 905 | 906 | Return 907 | ------- 908 | vec: vector between the vec and self fulfilling the conditions 909 | 910 | """ 911 | return self.getVec2VecMaxDistanceMinChargeVec(vec1=self, vec2=vec) 912 | 913 | def setLine(self) -> None: 914 | "Overrides base class method" 915 | plist = self._getStraightLine(point1=self.p_init, point2=self.p_final) 916 | plist = [ 917 | ImagePoint2D(spacePoint=p, image=self.image).setPointProperties() 918 | for p in plist 919 | ] 920 | self.pointList = plist 921 | return None 922 | 923 | def setVecCharge(self) -> None: 924 | "Set vector charge" 925 | counter = 0 926 | for p in self.pointList: 927 | counter += p.pixel_energy 928 | self.charge = counter 929 | return None 930 | 931 | def setVecProperties(self) -> None: 932 | "Overrides base class method" 933 | self.setLine() 934 | self.setVecCharge() 935 | return None 936 | 937 | def getNearestPoint2Point(self, point) -> ImagePoint2D: 938 | "Overrides base class method" 939 | assert point.ndim == self.ndim 940 | npoint = self._getNearestPointOnVec(vec=self, point=point) 941 | impoint = ImagePoint2D(image=self.image, spacePoint=npoint) 942 | impoint.setPointProperties() 943 | return impoint 944 | 945 | def getFarthestPoint2Point(self, point) -> ImagePoint2D: 946 | "Overrides base class method to return imagepoint" 947 | assert point.ndim == self.ndim 948 | npoint = self._getFarthestPointOnVec(vec=self, point=point) 949 | impoint = ImagePoint2D(image=self.image, spacePoint=npoint) 950 | impoint.setPointProperties() 951 | return impoint 952 | 953 | def getMinVec2Vec(self, vec): # -> imagelocatedvector2d 954 | "Overrides base class method to return image located vector" 955 | assert self.ndim == vec.ndim 956 | nvec = self.getVec2VecMinVec(vec1=self, vec2=vec) 957 | imvec = ImageLocatedVector2D(vec=nvec, image=self.image) 958 | imvec.setVecProperties() 959 | return imvec 960 | 961 | def getMaxVec2Vec(self, vec): # -> ImageLocatedVector2D 962 | "Overrides base class method to return image located vector" 963 | assert self.ndim == vec.ndim 964 | nvec = self.getVec2VecMaxVec(vec1=self, vec2=vec) 965 | imvec = ImageLocatedVector2D(vec=nvec, image=self.image) 966 | imvec.setVecProperties() 967 | return imvec 968 | -------------------------------------------------------------------------------- /core/block.py: -------------------------------------------------------------------------------- 1 | # Regroups objects with respect to point blocks 2 | # Author: Kaan Eraslan 3 | # Licensing: see, LICENSE 4 | 5 | # Packages 6 | 7 | import numpy as np 8 | from sympy.geometry import polygon 9 | 10 | from point import ImagePoint2D, Point2D 11 | from vector import ImageLocatedVector2D, LocatedVector2D 12 | 13 | # Point methods: 14 | # Given: a point 15 | 16 | # Operations: 17 | 18 | # - find the nearest side in block to the given point using closest point 19 | # on side. 20 | # - find the nearest side in block to the given point using farthest point 21 | # on side. 22 | # - find the point in block with least charge given the point 23 | # - find the nearest side in block with least charge given the point using 24 | # closest point on side 25 | # - find the nearest side in block with least charge given the point using 26 | # farthest point on side 27 | # - find the nearest side in block with least vector charge given the point 28 | # using closest point on side 29 | # - find the nearest side in block with least vector charge given the point 30 | # using farthest point on side 31 | # - find the farthest side in block with max charge given the point using 32 | # closest point on side 33 | # - find the farthest side in block with max charge given the point using 34 | # nearest point on side 35 | # - find the farthest side in block with least vector charge given the point 36 | # using closest point on side 37 | # - find the farthest side in block with least vector charge given the point 38 | # using farthest point on side 39 | # - find the farthest side in block with max vector charge given the point 40 | # using closest point on side 41 | # - find the farthest side in block with max vector charge given the point 42 | # using farthest point on side 43 | 44 | # Each of these operations can give distance, charge, vector, point, side as 45 | # output 46 | 47 | # Vector methods: 48 | 49 | # Given: an image located vector2d 50 | 51 | # Operations: 52 | 53 | # - find the nearest point in block to the given vector 54 | # - find the nearest point in block with least charge given the vector using 55 | # nearest point on vector 56 | # - find the nearest point in block with least charge given the vector using 57 | # farthest point on vector 58 | # - find the nearest point in block with least vector charge given the vector 59 | # using nearest point on vector 60 | # - find the nearest point in block with least vector charge given the vector 61 | # using farthest point on vector 62 | # - find the farthest point in block with max charge given the vector using 63 | # nearest point on vector 64 | # - find the farthest point in block with max charge given the vector using 65 | # farthest point on vector 66 | # - find the farthest point in block with least vector charge given the vector using 67 | # nearest point on vector 68 | # - find the farthest point in block with least vector charge given the vector using 69 | # farthest point on vector 70 | # - find the farthest point in block with max vector charge given the vector using 71 | # nearest point on vector 72 | # - find the farthest point in block with max vector charge given the vector using 73 | # farthest point on vector 74 | 75 | # - find the nearest side in block to the given vector 76 | # - find the nearest side in block with least charge given the vector using 77 | # nearest point on vector with nearest point in side 78 | # - find the nearest side in block with least charge given the vector using 79 | # nearest point on vector with farthest point in side 80 | # - find the nearest side in block with least charge given the vector using 81 | # farthest point on vector with nearest point in side 82 | # - find the nearest side in block with least charge given the vector using 83 | # farthest point on vector with farthest point in side 84 | # - find the nearest side in block with least vector charge given the vector 85 | # using nearest point on vector with nearest point in side 86 | # - find the nearest side in block with least vector charge given the vector 87 | # using nearest point on vector with farthest point in side 88 | # - find the nearest side in block with least vector charge given the vector 89 | # using farthest point on vector with nearest point in side 90 | # - find the nearest side in block with least vector charge given the vector 91 | # using farthest point on vector with farthest point in side 92 | 93 | # - find the farthest side in block with max charge given the vector using 94 | # nearest point on vector with nearest point in side 95 | # - find the farthest side in block with max charge given the vector using 96 | # nearest point on vector with farthest point in side 97 | # - find the farthest side in block with max charge given the vector using 98 | # farthest point on vector with nearest point in side 99 | # - find the farthest side in block with least vector charge given the vector using 100 | # nearest point on vector with nearest point in side 101 | # - find the farthest side in block with least vector charge given the vector using 102 | # farthest point on vector with nearest point in side 103 | # - find the farthest side in block with max vector charge given the vector using 104 | # nearest point on vector with nearest point in side 105 | # - find the farthest side in block with max vector charge given the vector using 106 | # farthest point on vector with nearest point in side 107 | # - find the farthest side in block with max charge given the vector using 108 | # farthest point on vector with farthest point in side 109 | # - find the farthest side in block with least vector charge given the vector using 110 | # using 111 | # farthest point on vector with nearest point in side 112 | # - find the farthest side in block with max vector charge given the vector us 113 | # ing 114 | # nearest point on vector with nearest point in side 115 | # - find the farthest side in block with max vector charge given the vector us 116 | # ing 117 | # farthest point on vector with nearest point in side 118 | # - find the farthest side in block with max charge given the vector using 119 | # farthest point on vector with farthest point in side 120 | # - find the farthest side in block with least vector charge given the vector 121 | # using 122 | # nearest point on vector with farthest point in side 123 | # - find the farthest side in block with least vector charge given the vector using 124 | # farthest point on vector with farthest point in side 125 | # - find the farthest side in block with max vector charge given the vector using 126 | # nearest point on vector with farthest point in side 127 | # - find the farthest side in block with max vector charge given the vector using 128 | # farthest point on vector with farthest point in side 129 | 130 | 131 | class Point2DBlock(polygon.Polygon): 132 | """ 133 | A grouping of a euclidean points 134 | """ 135 | 136 | def __init__( 137 | self, 138 | radius=None, # :int: of the circle that circumscribes the 139 | # polygon 140 | centerPoint=None, # :Point2D: 141 | pointList=None, # :[Point2D]: 142 | nb_sides=None): # :int: 143 | # Initiate either a polygon or a regular polygon 144 | if pointList is None and nb_sides is None: 145 | raise ValueError( 146 | 'please provide either a pointlist or number of sides to' 147 | ' instantiate') 148 | elif pointList is not None and nb_sides is not None: 149 | raise ValueError( 150 | 'please provide either a pointlist or number of sides not both' 151 | ) 152 | elif nb_sides is not None: 153 | if radius is None or centerPoint is None: 154 | raise ValueError('Please provide both radius and center point') 155 | else: 156 | super().__init__(centerPoint, radius, n=nb_sides) 157 | elif pointList is not None: 158 | super().__init__(pointList) 159 | 160 | self.blockpoints = [] 161 | return None 162 | 163 | @staticmethod 164 | def _getPointsInBlock(block) -> list: # 165 | "Get a list of points contained in the block" 166 | xmin, ymin, xmax, ymax = block.bounds # xmin, ymin, xmax, ymax 167 | plist = [] 168 | for i in range(xmin, xmax + 1): 169 | for k in range(ymin, ymax + 1): 170 | point = Point2D(i, k) 171 | if point in block: 172 | plist.append(point) 173 | return plist 174 | 175 | def setBlockpoints(self): 176 | "Set block points" 177 | self.blockpoints = self._getPointsInBlock(block=self) 178 | 179 | @staticmethod 180 | def _getPointInBlockByDistance(block, 181 | point: Point2D, 182 | minDist: bool): 183 | "Get min/max distance block point to given point" 184 | if point in block: 185 | return point, 0 186 | if minDist is True: 187 | dist = float('inf') 188 | else: 189 | dist = float('-inf') 190 | points = block.vertices 191 | result = None 192 | for p in points: 193 | distance = p.distance(point) 194 | if minDist is True: 195 | condition = distance <= dist 196 | else: 197 | condition = distance > dist 198 | if condition: 199 | dist = distance 200 | result = p 201 | return result, dist 202 | 203 | @classmethod 204 | def _getNearestPointInBlock(cls, block, 205 | point: Point2D) -> Point2D: 206 | "Get the point in block that is closest to given point " 207 | return cls._getPointInBlockByDistance(block, 208 | point, minDist=True)[0] 209 | 210 | def getNearestPointInBlock(self, point) -> Point2D: 211 | "Wrapper method for class instance" 212 | return self._getNearestPointInBlock(block=self, 213 | point=point) 214 | 215 | @classmethod 216 | def _getFarthestPointInBlockWithDist(cls, block, point: Point2D): 217 | "Get farthest point in block to the given point" 218 | return cls._getPointInBlockByDistance(block, point, minDist=False) 219 | 220 | @classmethod 221 | def _getFarthestDistanceInBlock2Point(cls, block, point: Point2D) -> float: 222 | "Get farthest distance from a point in block to the given point" 223 | return cls._getFarthestPointInBlockWithDist(block, point)[0] 224 | 225 | @classmethod 226 | def _getFarthestPointInBlock2Point(cls, block, point) -> Point2D: 227 | "Get farthest distance from a point in block to the given point" 228 | return cls._getFarthestPointInBlockWithDist(block, point)[1] 229 | 230 | def getFarthestDistanceInBlock2Point(self, point: Point2D) -> float: 231 | "Get farthest distance from block to the given point" 232 | return self._getFarthestDistanceInBlock2Point(block=self, point=point) 233 | 234 | def getFarthestPointInBlock2Point(self, point: Point2D) -> Point2D: 235 | "Get farthest distance from block to the given point" 236 | return self._getFarthestPointInBlock2Point(block=self, point=point) 237 | 238 | @staticmethod 239 | def _getBlockSideByDistance(block, 240 | point: Point2D, 241 | isMaxFuncs: bool, 242 | isNear: bool): 243 | """ 244 | Give the block side corresponding to distance based criteria 245 | 246 | Possible output options are following: 247 | Block side with shortest distance to given point where 248 | the distance is calculated from the closest point on side 249 | 250 | Block side with shortest distance to given point where 251 | the distance is calculated from the farthest point on side 252 | 253 | Block side with farthest distance to given point where 254 | the distance is calculated from the closest point on side 255 | 256 | Block side with farthest distance to given point where 257 | the distance is calculated from the farthest point on side 258 | """ 259 | sides = block.sides 260 | if isNear is True: 261 | dist = float('inf') 262 | else: 263 | dist = float('-inf') 264 | sideInBlock = None 265 | for side in sides: 266 | # side is a Segment 267 | vec = LocatedVector2D(segment=side) 268 | vec.setVecProperties() 269 | p, distance = vec._getPoint2VecDistancePoint(aVec=vec, 270 | point=point, 271 | isMin=isMaxFuncs) 272 | if isNear is True: 273 | condition = distance <= dist 274 | else: 275 | condition = distance > dist 276 | if condition: 277 | dist = distance 278 | sideInBlock = side 279 | 280 | sideInBlock = LocatedVector2D(segment=sideInBlock) 281 | sideInBlock.setVecProperties() 282 | return dist, sideInBlock 283 | 284 | @classmethod 285 | def _getCloseOrFarSideAndDistanceInBlock2Point(block, 286 | point: Point2D, 287 | isNear: bool): 288 | "Get nearest side in block to the given point" 289 | sides = block.sides 290 | if isNear is True: 291 | dist = float('inf') 292 | else: 293 | dist = float('-inf') 294 | sideInBlock = None 295 | for side in sides: 296 | # side is a Segment 297 | distance = side.distance(point) 298 | if isNear is True: 299 | condition = distance <= dist 300 | else: 301 | condition = distance > dist 302 | if condition: 303 | dist = distance 304 | sideInBlock = side 305 | 306 | sideInBlock = LocatedVector2D(segment=sideInBlock) 307 | return dist, sideInBlock 308 | 309 | @classmethod 310 | def _getClosestSideAndDistanceInBlock2Point(cls, block, point): 311 | "Get nearest side and distance in block to given point" 312 | return cls._getCloseOrFarSideAndDistanceInBlock2Point( 313 | block, point, isNear=True) 314 | 315 | @classmethod 316 | def _getClosestSideInBlock2Point(cls, block, point) -> LocatedVector2D: 317 | "get nearest side in block to given point" 318 | return cls._getClosestSideAndDistanceInBlock2Point(block, point)[1] 319 | 320 | @classmethod 321 | def _getNearestDist2SideInBlock2Point(cls, block, point) -> float: 322 | "get nearest side in block to given point" 323 | return cls._getClosestSideAndDistanceInBlock2Point(block, point)[0] 324 | 325 | @classmethod 326 | def _getFarSideAndDistanceInBlock2Point(cls, block, point): 327 | "Get nearest side and distance in block to given point" 328 | return cls._getCloseOrFarSideAndDistanceInBlock2Point( 329 | block, point, isNear=False) 330 | 331 | @classmethod 332 | def _getFarSideInBlock2Point(cls, block, point) -> LocatedVector2D: 333 | "get nearest side in block to given point" 334 | return cls._getFarSideAndDistanceInBlock2Point(block, point)[1] 335 | 336 | @classmethod 337 | def _getFarthestDist2SideInBlock2Point(cls, block, point): 338 | "get nearest side in block to given point" 339 | return cls._getFarSideAndDistanceInBlock2Point(block, point)[0] 340 | 341 | @classmethod 342 | def _getSideInBlock2VecByDistance( 343 | cls, 344 | block, 345 | vec: LocatedVector2D, 346 | isMin: bool, # get minimum side or distance overall 347 | isMaxFuncs: bool # use maximum or minimum distance function 348 | ): 349 | "Get nearest side in block to the given vec" 350 | sides = block.sides 351 | sideInBlock = None 352 | 353 | if isMin is True: 354 | dist = float('inf') 355 | else: 356 | dist = float('-inf') 357 | 358 | for side in sides: 359 | # side is a Segment 360 | sidevec = LocatedVector2D(segment=side) 361 | 362 | distance = sidevec.getMinMaxDistance2Vec(isMin=isMaxFuncs, 363 | vec=vec) 364 | 365 | if isMin is True: 366 | condition = distance < dist 367 | else: 368 | condition = distance > dist 369 | 370 | if condition: 371 | dist = distance 372 | sideInBlock = side 373 | 374 | sideInBlock = LocatedVector2D(segment=sideInBlock) 375 | return dist, sideInBlock 376 | 377 | @classmethod 378 | def _getClosestSideAndDistanceInBlock2VecWithMaxDist(cls, block, vec): 379 | "Get nearest side and distance in block to given vec"\ 380 | " using maximum distance function" 381 | return cls._getSideInBlock2VecByDistance( 382 | block=block, vec=vec, isMin=True, isMaxFuncs=True) 383 | 384 | @classmethod 385 | def _getClosestSideInBlock2VecWithMaxDist(cls, block, 386 | vec) -> LocatedVector2D: 387 | "Get nearest side in block to given vector using maximum distance" 388 | return cls._getClosestSideAndDistanceInBlock2VecWithMaxDist( 389 | block=block, vec=vec)[1] 390 | 391 | @classmethod 392 | def _getClosestSideDistInBlock2VecWithMaxDist(cls, block, vec) -> float: 393 | "Get nearest side in block to given vector using maximum distance" 394 | return cls._getClosestSideAndDistanceInBlock2VecWithMaxDist( 395 | block=block, vec=vec)[0] 396 | 397 | @classmethod 398 | def _getFarSideAndDistanceInBlock2VecWithMaxDist(cls, block, vec): 399 | "Get farthest side and distance in block to given vec"\ 400 | " using maximum distance function" 401 | return cls._getSideInBlock2VecByDistance( 402 | block=block, vec=vec, isMin=False, isMaxFuncs=True) 403 | 404 | @classmethod 405 | def _getFarSideInBlock2VecWithMaxDist(cls, block, vec) -> LocatedVector2D: 406 | "Get farthest side in block to given vector using maximum distance" 407 | return cls._getFarSideAndDistanceInBlock2VecWithMaxDist( 408 | block=block, vec=vec)[1] 409 | 410 | @classmethod 411 | def _getFarSideDistInBlock2VecWithMaxDist(cls, block, vec) -> float: 412 | "Get farthest side in block to given vector using maximum distance" 413 | return cls._getFarSideAndDistanceInBlock2VecWithMaxDist( 414 | block=block, vec=vec)[0] 415 | 416 | @classmethod 417 | def _getClosestSideAndDistanceInBlock2VecWithMinDist(cls, block, vec): 418 | "Get nearest side and distance in block to given vec"\ 419 | " using minimum distance function" 420 | return cls._getSideInBlock2VecByDistance( 421 | block=block, vec=vec, isMin=True, isMaxFuncs=False) 422 | 423 | @classmethod 424 | def _getClosestSideInBlock2VecWithMinDist(cls, block, 425 | vec) -> LocatedVector2D: 426 | "Get nearest side in block to given vector using maximum distance" 427 | return cls._getClosestSideAndDistanceInBlock2VecWithMinDist( 428 | block=block, vec=vec)[1] 429 | 430 | @classmethod 431 | def _getClosestSideDistInBlock2VecWithMinDist(cls, block, vec) -> float: 432 | "Get nearest side in block to given vector using maximum distance" 433 | return cls._getClosestSideAndDistanceInBlock2VecWithMinDist( 434 | block=block, vec=vec)[0] 435 | 436 | @classmethod 437 | def _getFarSideAndDistanceInBlock2VecWithMinDist(cls, block, vec): 438 | "Get farthest side and distance in block to given vec"\ 439 | " using maximum distance function" 440 | return cls._getSideInBlock2VecByDistance( 441 | block=block, vec=vec, isMin=False, isMaxFuncs=False) 442 | 443 | @classmethod 444 | def _getFarSideInBlock2VecWithMinDist(cls, block, vec) -> LocatedVector2D: 445 | "Get farthest side in block to given vector using maximum distance" 446 | return cls._getFarSideAndDistanceInBlock2VecWithMinDist( 447 | block=block, vec=vec)[1] 448 | 449 | @classmethod 450 | def _getFarSideDistInBlock2VecWithMinDist(cls, block, vec) -> float: 451 | "Get farthest side in block to given vector using maximum distance" 452 | return cls._getFarSideAndDistanceInBlock2VecWithMinDist( 453 | block=block, vec=vec)[0] 454 | 455 | def getClosestSideOrDistanceWithDistFunc( 456 | self, 457 | other, # segment or 458 | # locatedvector2d 459 | useMaxDistance: bool, 460 | justDistance: bool): 461 | "Regroups methods related closest distance or side" 462 | if useMaxDistance is True: 463 | if justDistance is False: 464 | return self._getClosestSideInBlock2VecWithMaxDist( 465 | block=self, vec=other) # LocatedVector2D 466 | else: 467 | return self._getClosestSideDistInBlock2VecWithMaxDist( 468 | block=self, vec=other) 469 | else: 470 | if justDistance is False: 471 | return self._getClosestSideInBlock2VecWithMinDist( 472 | block=self, vec=other) # LocatedVector2D 473 | else: 474 | return self._getClosestSideDistInBlock2VecWithMinDist( 475 | block=self, vec=other) 476 | 477 | def getFarSideOrDistanceWithDistFunc(self, other, useMaxDistance, 478 | justDistance): 479 | "Regroups methods related to farthest distance or side" 480 | if useMaxDistance is True: 481 | if justDistance is False: 482 | return self._getFarSideInBlock2VecWithMaxDist( 483 | block=self, vec=other) # LocatedVector2D 484 | else: 485 | return self._getFarSideDistInBlock2VecWithMaxDist( 486 | block=self, vec=other) 487 | else: 488 | if justDistance is False: 489 | return self._getFarSideInBlock2VecWithMinDist( 490 | block=self, vec=other) # LocatedVector2D 491 | else: 492 | return self._getFarSideDistInBlock2VecWithMinDist( 493 | block=self, vec=other) 494 | 495 | def getCloseFarSide2OtherDistFunc(self, other, justDistance: bool, 496 | isNearest: bool, useMaxDistance: bool): 497 | "Get nearest side to other" 498 | # other should be either a point or a segment or locatedvector2d 499 | if (issubclass(other, Point2D) is not True 500 | and issubclass(other, polygon.Segment) is not True 501 | and issubclass(other, LocatedVector2D) is not True): 502 | raise ValueError('other should be either a point2d' 503 | ' or a segment or a locatedvector2d' 504 | 'you have provided: {}'.format(type(other))) 505 | # 506 | if isNearest is True: 507 | if isinstance(other, Point2D): 508 | if justDistance is False: 509 | return self._getClosestSideInBlock2Point( 510 | block=self, point=other) 511 | else: 512 | return self._getNearestDist2SideInBlock2Point( 513 | block=self, point=other) 514 | else: 515 | return self.getClosestSideOrDistanceWithDistFunc( 516 | other, useMaxDistance, justDistance) 517 | else: 518 | if isinstance(other, Point2D): 519 | return self._getFarSideInBlock2Point(block=self, point=other) 520 | else: 521 | return self.getFarSideOrDistanceWithDistFunc( 522 | other, useMaxDistance, justDistance) 523 | 524 | def getClosestSide2OtherMaxDist(self, other) -> LocatedVector2D: 525 | "Get nearest side to other" 526 | # other should be either a point or a segment or locatedvector2d 527 | return self.getCloseFarSide2OtherDistFunc( 528 | other, isNearest=True, justDistance=False, useMaxDistance=True) 529 | 530 | def getClosestSide2OtherMinDist(self, other) -> LocatedVector2D: 531 | "Get nearest side to other with minimum distance functions" 532 | # other should be either a point or a segment or locatedvector2d 533 | return self.getCloseFarSide2OtherDistFunc( 534 | other, isNearest=True, justDistance=False, useMaxDistance=False) 535 | 536 | def getFarSide2OtherMaxDist(self, other) -> LocatedVector2D: 537 | "Get farthest side to other" 538 | # other should be either a point or a segment or locatedvector2d 539 | return self.getCloseFarSide2OtherDistFunc( 540 | other, isNearest=False, justDistance=False, useMaxDistance=True) 541 | 542 | def getFarSide2OtherMinDist(self, other) -> LocatedVector2D: 543 | "Get far side to other" 544 | # other should be either a point or a segment or locatedvector2d 545 | return self.getCloseFarSide2OtherDistFunc( 546 | other, isNearest=False, justDistance=False, useMaxDistance=False) 547 | 548 | def getClosestSideDist2OtherMaxDist(self, other): 549 | "Get closest side's distance to other using max distance function" 550 | return self.getCloseFarSide2OtherDistFunc( 551 | other, isNearest=True, justDistance=True, useMaxDistance=True) 552 | 553 | def getClosestSideDist2OtherMinDist(self, other): 554 | "Get closest side's distance to other using max distance function" 555 | return self.getCloseFarSide2OtherDistFunc( 556 | other, isNearest=True, justDistance=True, useMaxDistance=False) 557 | 558 | def getFarSideDist2OtherMinDist(self, other): 559 | "Get closest side's distance to other using max distance function" 560 | return self.getCloseFarSide2OtherDistFunc( 561 | other, isNearest=False, justDistance=True, useMaxDistance=False) 562 | 563 | def getFarSideDist2OtherMaxDist(self, other): 564 | "Get closest side's distance to other using max distance function" 565 | return self.getCloseFarSide2OtherDistFunc( 566 | other, isNearest=False, justDistance=True, useMaxDistance=True) 567 | 568 | @staticmethod 569 | def _checkConsecutive(block1, block2): 570 | "Check if 2 blocks are consecutive" 571 | checkval = False 572 | # 2 blocks are consecutive if they intersect 573 | if len(block1.intersect(block2)) > 0: 574 | checkval = True 575 | return checkval 576 | 577 | @staticmethod 578 | def filterContainedBlocksInBlock(block1, blocks): 579 | 'Filter out blocks that are contained in block1' 580 | return [block for block in blocks if block not in block1] 581 | 582 | @classmethod 583 | def getUncontainedBlocks(cls, block, blocks): 584 | "Filter blocks for contained and then add containing block to list" 585 | uncontained = cls.filterContainedBlocksInBlock(block1=block, 586 | blocks=blocks) 587 | uncontained.append(block) 588 | return uncontained 589 | 590 | @classmethod 591 | def filterUnconsecutiveBlocks(cls, block, blocks): 592 | "Filter out blocks that are not consecutive to the block" 593 | return [ 594 | b for b in blocks if cls._checkConsecutive(block1=block, block2=b) 595 | ] 596 | 597 | @classmethod 598 | def _addBlock2Block(cls, block1, block2): 599 | "Add one block to another if they are consecutive" 600 | if cls._checkConsecutive(block1, block2) is False: 601 | raise ValueError( 602 | 'Blocks need to be consecutive (intersect) for addition') 603 | else: 604 | v1 = block1.vertices 605 | v2 = block2.vertices 606 | v1.extend(v2) 607 | newblock = Point2DBlock(pointList=v1) 608 | newblock.setBlockpoints() 609 | return newblock 610 | 611 | @classmethod 612 | def _addBlocks2Block(cls, block, blocks): 613 | "Add consecutive blocks to given block" 614 | consecutive_blocks = cls.filterUnconsecutiveBlocks(block, blocks) 615 | if len(consecutive_blocks) == 0: 616 | return None 617 | for cblock in consecutive_blocks: 618 | block = cls._addBlock2Block(block1=block, block2=cblock) 619 | return block 620 | 621 | @classmethod 622 | def foldrBlocks(cls, blocks: list): 623 | "Merge blocks after filtering unmergeable ones" 624 | if len(blocks) == 1: 625 | return blocks[0] 626 | block = blocks.pop() 627 | block = cls._addBlocks2Block(block, blocks) 628 | if block is not None: 629 | blocks.append(block) 630 | cls.foldrBlocks(blocks) 631 | 632 | def add2Block(self, block): 633 | "Add block to current block" 634 | return self._addBlock2Block(block1=self, block2=block) 635 | 636 | def mergeBlocksWithSelf(self, blocks): 637 | "Merge blocks with instance block" 638 | blockscp = blocks.copy() 639 | blockscp.append(self) 640 | mergedBlock = self.foldrBlocks(blocks) 641 | if self in mergedBlock is not True: 642 | raise ValueError('List of blocks that are not mergeable' 643 | ' with self block') 644 | else: 645 | return mergedBlock 646 | 647 | 648 | class ImagePoint2DBlock(Point2DBlock): 649 | "Extends point block object to images" 650 | 651 | def __init__( 652 | self, 653 | image: np.ndarray[[np.uint8]], 654 | nb_sides=None, 655 | radius=None, # :int: of the circle that circumscribes the 656 | # polygon 657 | centerPoint=None, # :Point2D: 658 | pointList=None) -> None: 659 | super().__init__( 660 | centerPoint=centerPoint, 661 | pointList=pointList, 662 | radius=radius, 663 | nb_sides=nb_sides) 664 | self.image = image 665 | self.charge = 0 666 | 667 | return None 668 | 669 | # Should override the instance methods of base class 670 | @staticmethod 671 | def _getDistanceChargeVariables(isMinDist, isMinCharge): 672 | "Wrapper around image located vector for setting variables" 673 | return ImageLocatedVector2D.getDistanceChargeVariables( 674 | minDist=isMinDist, 675 | minCharge=isMinCharge) 676 | 677 | @staticmethod 678 | def _getConditionDistanceCharge(isMinDist, isMinCharge, 679 | distanceParentScope, 680 | distanceLocalScope, 681 | chargeParentScope, 682 | chargeLocalScope): 683 | "Wrapper around image located vector for setting condition" 684 | return ImageLocatedVector2D.getConditionDistanceCharge( 685 | isMinDist, 686 | isMinCharge, 687 | distanceParentScope, 688 | distanceLocalScope, 689 | chargeParentScope, 690 | chargeLocalScope) 691 | 692 | @staticmethod 693 | def _getFarNearPointInBlockWithDistMinMaxCharge(block, 694 | point: ImagePoint2D, 695 | isMinCharge: bool, 696 | isPoint: bool, 697 | isMinDist: bool): 698 | """ 699 | Given a point and a block give either farthest or nearest point 700 | with maximum or minimum charge in block 701 | 702 | Note: For calculating charge we have two options, we can either look 703 | for the charge of the block point, or charge of the vector that 704 | reunites the block point to the given point 705 | note: isPoint: True -> point, False -> vec 706 | 707 | """ 708 | bpoint = None 709 | bpvec = None 710 | 711 | bpoints = block.blockpoints 712 | dist, charge = block._getDistanceChargeVariables( 713 | isMinCharge=isMinCharge, 714 | isMinDist=isMinDist) 715 | for bp in bpoints: 716 | tempdist = bp.distance(point) 717 | if isPoint is True: 718 | tempcharge = bp.pixel_energy 719 | vec = None 720 | else: 721 | vec = ImageLocatedVector2D(initial_point=bp, 722 | image=block.image, 723 | final_point=point) 724 | vec.setVecProperties() 725 | tempcharge = vec.charge 726 | 727 | checkval = block._getConditionDistanceCharge( 728 | isMinDist=isMinDist, 729 | isMinCharge=isMinCharge, 730 | distanceParentScope=dist, 731 | distanceLocalScope=tempdist, 732 | chargeParentScope=charge, 733 | chargeLocalScope=tempcharge) 734 | if checkval: 735 | dist = tempdist 736 | charge = tempcharge 737 | bpoint = bp 738 | bpvec = vec 739 | return dist, charge, bpoint, bpvec 740 | 741 | @classmethod 742 | def _getNearestPointInBlock(cls, block, point) -> ImagePoint2D: 743 | "Overrides the base class method" 744 | (dist, charge, 745 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 746 | block=block, 747 | point=point, 748 | isMinCharge=None, 749 | isPoint=True, 750 | isMinDist=True) 751 | point.setPointProperties() 752 | 753 | return point 754 | 755 | @classmethod 756 | def _getFarthestPointInBlockWithDist(cls, block, 757 | point: Point2D) -> ImagePoint2D: 758 | "Overrides the base class method" 759 | (dist, charge, 760 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 761 | block=block, 762 | point=point, 763 | isMinCharge=None, 764 | isPoint=True, 765 | isMinDist=False) 766 | point.setPointProperties() 767 | 768 | return dist, point 769 | 770 | @classmethod 771 | def _getNearestPointVecInBlockWithDist(cls, block, point) -> ImagePoint2D: 772 | "Overrides the base class method" 773 | (dist, charge, 774 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 775 | block=block, 776 | point=point, 777 | isMinCharge=None, 778 | isPoint=False, 779 | isMinDist=True) 780 | vec.setVecProperties() 781 | 782 | return dist, vec 783 | 784 | @classmethod 785 | def _getFarthestPointVecInBlockWithDist(cls, block, 786 | point: Point2D) -> ImagePoint2D: 787 | "Overrides the base class method" 788 | (dist, charge, 789 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 790 | block=block, 791 | point=point, 792 | isMinCharge=None, 793 | isPoint=False, 794 | isMinDist=False) 795 | vec.setVecProperties() 796 | 797 | return dist, vec 798 | 799 | @classmethod 800 | def _getFarthestPointVecInBlock(cls, 801 | block, 802 | point: Point2D) -> ImageLocatedVector2D: 803 | "Get the vector between farthest point in block and given point" 804 | return cls._getFarthestPointVecInBlockWithDist(block, point)[1] 805 | 806 | @classmethod 807 | def _getNearestPointVecInBlock(cls, 808 | block, 809 | point: Point2D) -> ImageLocatedVector2D: 810 | "Get the vector between farthest point in block and given point" 811 | return cls._getNearestPointVecInBlockWithDist(block, point)[1] 812 | 813 | @classmethod 814 | def _getMinChargePointChargeInBlock(cls, block) -> list: 815 | "Get minimum charged point in block" 816 | p = Point2D(x=0, y=0) 817 | (dist, charge, 818 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 819 | block=block, 820 | point=p, 821 | isMinCharge=True, 822 | isPoint=True, 823 | isMinDist=None) 824 | return point, charge 825 | 826 | @classmethod 827 | def _getMinimumPointChargeInBlock(cls, block) -> float: 828 | "Get minimum point charge in block" 829 | return cls._getMinChargePointChargeInBlock(block)[1] 830 | 831 | @classmethod 832 | def _getMinChargePointInBlock(cls, block) -> float: 833 | "Get minimum point charge in block" 834 | return cls._getMinChargePointChargeInBlock(block)[0] 835 | 836 | @classmethod 837 | def _getMaxChargePointChargeInBlock(cls, block) -> list: 838 | "Get point with maximum charge in block and its charge" 839 | p = Point2D(x=0, y=0) 840 | (dist, charge, 841 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 842 | block=block, 843 | point=p, 844 | isMinCharge=False, 845 | isPoint=True, 846 | isMinDist=None) 847 | return point, charge 848 | 849 | @classmethod 850 | def _getMaximumPointChargeInBlock(cls, block) -> float: 851 | "Get minimum point charge in block" 852 | return cls._getMaxChargePointChargeInBlock(block)[1] 853 | 854 | @classmethod 855 | def _getMaxChargePointInBlock(cls, block) -> float: 856 | "Get minimum point charge in block" 857 | return cls._getMaxChargePointChargeInBlock(block)[0] 858 | 859 | @classmethod 860 | def _getNearestMinChargePointChargeDistInBlock(cls, 861 | block, 862 | point) -> list: 863 | """ 864 | Get nearest point with minimum charge 865 | outputs charge, distance, and point 866 | """ 867 | (dist, charge, 868 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 869 | block=block, 870 | point=point, 871 | isMinCharge=True, 872 | isPoint=True, 873 | isMinDist=True) 874 | return point, charge, dist 875 | 876 | @classmethod 877 | def _getNearestMinChargePointDistInBlock(cls, block, point) -> float: 878 | "Get distance of the point with minimum charge and minimum distance" 879 | return cls._getNearestMinChargePointChargeDistInBlock(block, point)[2] 880 | 881 | @classmethod 882 | def _getNearestMinChargePointChargeInBlock(cls, block, point) -> float: 883 | "Get distance of the point with minimum charge and minimum distance" 884 | return cls._getNearestMinChargePointChargeDistInBlock(block, point)[1] 885 | 886 | @classmethod 887 | def _getNearestMinChargePointInBlock(cls, block, point) -> float: 888 | "Get distance of the point with minimum charge and minimum distance" 889 | return cls._getNearestMinChargePointChargeDistInBlock(block, point)[0] 890 | 891 | @classmethod 892 | def _getNearestMinChargePointVecChargeDistInBlock(cls, 893 | block, 894 | point) -> list: 895 | """ 896 | Get nearest point with minimum charge 897 | outputs charge, distance, and point 898 | """ 899 | (dist, charge, 900 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 901 | block=block, 902 | point=point, 903 | isMinCharge=True, 904 | isPoint=False, 905 | isMinDist=True) 906 | return vec, charge, dist 907 | 908 | @classmethod 909 | def _getNearestMinChargePointVecChargeInBlock(cls, block, point) -> float: 910 | "Get the charge of the vector between nearest point in block and " \ 911 | "given point" 912 | return cls._getNearestMinChargePointVecChargeDistInBlock(block, 913 | point)[1] 914 | 915 | @classmethod 916 | def _getNearestMinChargePointVecInBlock(cls, 917 | block, 918 | point) -> ImageLocatedVector2D: 919 | "Get the charge of the vector between nearest point in block and " \ 920 | "given point" 921 | return cls._getNearestMinChargePointVecChargeDistInBlock(block, 922 | point)[0] 923 | 924 | @classmethod 925 | def _getNearestMaxChargePointChargeDistInBlock(cls, 926 | block, 927 | point) -> list: 928 | """ 929 | Get nearest point with minimum charge 930 | outputs charge, distance, and point 931 | """ 932 | (dist, charge, 933 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 934 | block=block, 935 | point=point, 936 | isMinCharge=False, 937 | isPoint=True, 938 | isMinDist=True) 939 | return point, charge, dist 940 | 941 | @classmethod 942 | def _getNearestMaxChargePointDistInBlock(cls, block, point): 943 | "Get distance of nearest point with maximum charge in block to point" 944 | return cls._getNearestMaxChargePointDistInBlock(block, point)[2] 945 | 946 | @classmethod 947 | def _getNearestMaxChargePointChargeInBlock(cls, block, point): 948 | "Get distance of nearest point with maximum charge in block to point" 949 | return cls._getNearestMaxChargePointDistInBlock(block, point)[1] 950 | 951 | @classmethod 952 | def _getNearestMaxChargePointInBlock(cls, block, point): 953 | "Get distance of nearest point with maximum charge in block to point" 954 | return cls._getNearestMaxChargePointDistInBlock(block, point)[0] 955 | 956 | @classmethod 957 | def _getNearestMaxChargePointVecChargeDistInBlock(cls, 958 | block, 959 | point) -> list: 960 | """ 961 | Get nearest point with minimum charge 962 | outputs charge, distance, and point 963 | """ 964 | (dist, charge, 965 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 966 | block=block, 967 | point=point, 968 | isMinCharge=False, 969 | isPoint=False, 970 | isMinDist=True) 971 | return vec, charge, dist 972 | 973 | @classmethod 974 | def _getNearestMaxChargePointVecChargeInBlock(cls, block, point): 975 | "Get charge of vec nearest point with maximum charge in block to point" 976 | return cls._getNearestMaxChargePointVecDistInBlock(block, point)[1] 977 | 978 | @classmethod 979 | def _getNearestMaxChargePointVecInBlock(cls, block, point): 980 | "Get distance of nearest point with maximum charge in block to point" 981 | return cls._getNearestMaxChargePointVecDistInBlock(block, point)[0] 982 | 983 | @classmethod 984 | def _getFarthestMinChargePointChargeDistInBlock(cls, 985 | block, 986 | point) -> list: 987 | """ 988 | Get nearest point with minimum charge 989 | outputs charge, distance, and point 990 | """ 991 | (dist, charge, 992 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 993 | block=block, 994 | point=point, 995 | isMinCharge=True, 996 | isPoint=True, 997 | isMinDist=False) 998 | return point, charge, dist 999 | 1000 | @classmethod 1001 | def _getFarthestMinChargePointDistInBlock(cls, block, point) -> float: 1002 | "Get distance of the point with minimum charge and minimum distance" 1003 | return cls._getFarthestMinChargePointChargeDistInBlock(block, point)[2] 1004 | 1005 | @classmethod 1006 | def _getFarthestMinChargePointChargeInBlock(cls, block, point) -> float: 1007 | "Get distance of the point with minimum charge and minimum distance" 1008 | return cls._getFarthestMinChargePointChargeDistInBlock(block, point)[1] 1009 | 1010 | @classmethod 1011 | def _getFarthestMinChargePointInBlock(cls, block, point) -> float: 1012 | "Get distance of the point with minimum charge and minimum distance" 1013 | return cls._getFarthestMinChargePointChargeDistInBlock(block, point)[0] 1014 | 1015 | @classmethod 1016 | def _getFarthestMinChargePointVecChargeDistInBlock(cls, 1017 | block, 1018 | point) -> list: 1019 | """ 1020 | Get nearest point with minimum charge 1021 | outputs charge, distance, and point 1022 | """ 1023 | (dist, charge, 1024 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 1025 | block=block, 1026 | point=point, 1027 | isMinCharge=True, 1028 | isPoint=False, 1029 | isMinDist=False) 1030 | return vec, charge, dist 1031 | 1032 | @classmethod 1033 | def _getFarthestMinChargePointVecChargeInBlock(cls, block, point) -> float: 1034 | "Get the charge of the vector between nearest point in block and " \ 1035 | "given point" 1036 | return cls._getFarthestMinChargePointVecChargeDistInBlock(block, 1037 | point)[1] 1038 | 1039 | @classmethod 1040 | def _getFarthestMinChargePointVecInBlock(cls, 1041 | block, 1042 | point) -> ImageLocatedVector2D: 1043 | "Get the charge of the vector between nearest point in block and " \ 1044 | "given point" 1045 | return cls._getFarthestMinChargePointVecChargeDistInBlock(block, 1046 | point)[0] 1047 | 1048 | @classmethod 1049 | def _getFarthestMaxChargePointChargeDistInBlock(cls, 1050 | block, 1051 | point) -> list: 1052 | """ 1053 | Get nearest point with minimum charge 1054 | outputs charge, distance, and point 1055 | """ 1056 | (dist, charge, 1057 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 1058 | block=block, 1059 | point=point, 1060 | isMinCharge=False, 1061 | isPoint=True, 1062 | isMinDist=False) 1063 | return point, charge, dist 1064 | 1065 | @classmethod 1066 | def _getFarthestMaxChargePointDistInBlock(cls, block, point): 1067 | "Get distance of nearest point with maximum charge in block to point" 1068 | return cls._getFarthestMaxChargePointDistInBlock(block, point)[2] 1069 | 1070 | @classmethod 1071 | def _getFarthestMaxChargePointChargeInBlock(cls, block, point): 1072 | "Get distance of nearest point with maximum charge in block to point" 1073 | return cls._getFarthestMaxChargePointDistInBlock(block, point)[1] 1074 | 1075 | @classmethod 1076 | def _getFarthestMaxChargePointInBlock(cls, block, point): 1077 | "Get distance of nearest point with maximum charge in block to point" 1078 | return cls._getFarthestMaxChargePointDistInBlock(block, point)[0] 1079 | 1080 | @classmethod 1081 | def _getFarthestMaxChargePointVecChargeDistInBlock(cls, 1082 | block, 1083 | point) -> list: 1084 | """ 1085 | Get nearest point with minimum charge 1086 | outputs charge, distance, and point 1087 | """ 1088 | (dist, charge, 1089 | point, vec) = cls._getFarNearPointInBlockWithDistMinMaxCharge( 1090 | block=block, 1091 | point=point, 1092 | isMinCharge=False, 1093 | isPoint=False, 1094 | isMinDist=False) 1095 | return vec, charge, dist 1096 | 1097 | @classmethod 1098 | def _getFarthestMaxChargePointVecChargeInBlock(cls, block, point): 1099 | "Get charge of vec nearest point with maximum charge in block to point" 1100 | return cls._getFarthestMaxChargePointVecDistInBlock(block, point)[1] 1101 | 1102 | @classmethod 1103 | def _getFarthestMaxChargePointVecInBlock(cls, block, point): 1104 | "Get distance of nearest point with maximum charge in block to point" 1105 | return cls._getFarthestMaxChargePointVecDistInBlock(block, point)[0] 1106 | 1107 | def setBlockpoints(self): 1108 | "Overrides the base class method" 1109 | blockpoints = self._getPointsInBlock(block=self) 1110 | self.blockpoints = [ 1111 | ImagePoint2D(spacePoint=p, image=self.image).setPointProperties() 1112 | for p in blockpoints 1113 | ] 1114 | return None 1115 | 1116 | def setBlockCharge(self) -> None: 1117 | "Sets the total energy charge for the block" 1118 | counter = 0 1119 | for p in self.blockpoints: 1120 | counter += p.pixel_energy 1121 | self.charge = counter 1122 | return None 1123 | 1124 | def setBlockProperties(self) -> None: 1125 | "Set block properties" 1126 | self.setBlockpoints() 1127 | self.setBlockCharge() 1128 | 1129 | def getNearestPointInBlock(self, point) -> ImagePoint2D: 1130 | """ 1131 | Overrides base class method to return image point 1132 | 1133 | Desciption 1134 | ----------- 1135 | Given a point the function returns the closest point to the 1136 | given point that is inside the current block 1137 | """ 1138 | bpoint = self._getNearestPointInBlock(block=self, point=point) 1139 | impoint = ImagePoint2D(spacePoint=bpoint, image=self.image) 1140 | impoint.setPointProperties() 1141 | return impoint 1142 | 1143 | def getFarthestPointFromBlock2Point(self, point) -> ImagePoint2D: 1144 | """ 1145 | Overrides base class method to return image point 1146 | 1147 | Desciption 1148 | ----------- 1149 | Given a point the function returns the farthest point contained 1150 | in the block to the given point 1151 | """ 1152 | bpoint = self._getFarthestPointInBlock2Point(block=self, point=point) 1153 | impoint = ImagePoint2D(spacePoint=bpoint, image=self.image) 1154 | impoint.setPointProperties() 1155 | return impoint 1156 | 1157 | def getClosestSide2OtherMaxDist(self, other) -> ImageLocatedVector2D: 1158 | """ 1159 | Overrides base class method to return image locatedvector2d 1160 | 1161 | Description 1162 | ------------ 1163 | Given a point or a segment or a located vector, function returns 1164 | closest side contained in the block. 1165 | Closest side is calculated using maximum distance formula, meaning that 1166 | the distance between the side and the other is calculated using the point 1167 | on our side that is farthest to the given other. This does not necessarily 1168 | imply that the side itself is farthest, it is just that the distance 1169 | is calculated using the farthest point on the side 1170 | """ 1171 | vec = self.getCloseFarSide2OtherDistFunc( 1172 | other, isNearest=True, justDistance=False, useMaxDistance=True) 1173 | imvec = ImageLocatedVector2D(vec=vec, image=self.image) 1174 | imvec.setVecProperties() 1175 | return imvec 1176 | 1177 | def getClosestSide2OtherMinDist(self, other) -> ImageLocatedVector2D: 1178 | """ 1179 | Overrides base class method to return image locatedvector2d 1180 | 1181 | Description 1182 | ------------ 1183 | Given a point or a segment or a located vector, function returns 1184 | closest side contained in the block. 1185 | Closest side is calculated using minimum distance formula, meaning that 1186 | the distance between the side and the other is calculated using the point 1187 | on our side that is closest to the given other. This does not necessarily 1188 | imply that the side itself is closest, it is just that the distance 1189 | is calculated using the closest point on the side 1190 | 1191 | """ 1192 | vec = self.getCloseFarSide2OtherDistFunc( 1193 | other, isNearest=True, justDistance=False, useMaxDistance=False) 1194 | imvec = ImageLocatedVector2D(vec=vec, image=self.image) 1195 | imvec.setVecProperties() 1196 | return imvec 1197 | 1198 | def getFarSide2OtherMaxDist(self, other) -> ImageLocatedVector2D: 1199 | """ 1200 | Get farthest side to other 1201 | 1202 | Description 1203 | ------------ 1204 | Given a point or a segment or a located vector, function returns 1205 | farthest side contained in the block. 1206 | Farthest side is calculated using maximum distance formula, meaning that 1207 | the distance between the side and the other is calculated using the point 1208 | on our side that is farthest to the given other. This does not necessarily 1209 | imply that the side itself is farthest, it is just that the distance 1210 | is calculated using the farthest point on the side 1211 | """ 1212 | # other should be either a point or a segment or locatedvector2d 1213 | vec = self.getCloseFarSide2OtherDistFunc( 1214 | other, isNearest=False, justDistance=False, useMaxDistance=True) 1215 | imvec = ImageLocatedVector2D(vec=vec, image=self.image) 1216 | imvec.setVecProperties() 1217 | return imvec 1218 | 1219 | def getFarSide2OtherMinDist(self, other) -> ImageLocatedVector2D: 1220 | """ 1221 | Get far side to other 1222 | 1223 | Description 1224 | ------------ 1225 | Given a point or a segment or a located vector, function returns 1226 | farthest side contained in the block. 1227 | Farthest side is calculated using minimum distance formula, meaning that 1228 | the distance between the side and the other is calculated using the point 1229 | on our side that is closest to the given other. This does not necessarily 1230 | imply that the side itself is closest, it is just that the distance 1231 | is calculated using the closest point on the side 1232 | """ 1233 | # other should be either a point or a segment or locatedvector2d 1234 | vec = self.getCloseFarSide2OtherDistFunc( 1235 | other, isNearest=False, justDistance=False, useMaxDistance=False) 1236 | imvec = ImageLocatedVector2D(vec=vec, image=self.image) 1237 | imvec.setVecProperties() 1238 | return imvec 1239 | 1240 | def add2Block(self, block): 1241 | "Overrides base class method to return image block" 1242 | newblock = self._addBlock2Block(block1=self, block2=block) 1243 | imblock = ImagePoint2DBlock(pointList=newblock.vertices, 1244 | image=self.image) 1245 | imblock.setBlockProperties() 1246 | return imblock 1247 | 1248 | def foldImageBlocks(self, blocks): 1249 | "Overrides foldrBlocks method of baseclass" 1250 | mergeBlock = self.foldrBlocks(blocks) 1251 | imblock = ImagePoint2DBlock(pointList=mergeBlock.vertices, 1252 | image=self.image) 1253 | imblock.setBlockProperties() 1254 | return imblock 1255 | 1256 | def mergeBlocksWithSelf(self, blocks): 1257 | "Overrides base class method" 1258 | blockscp = blocks.copy() 1259 | blockscp.append(self) 1260 | mergedBlock = self.foldImageBlocks(blocks) 1261 | if self in mergedBlock is not True: 1262 | raise ValueError('List of blocks that are not mergeable' 1263 | ' with self block') 1264 | else: 1265 | return mergedBlock 1266 | --------------------------------------------------------------------------------