olinox 8 anos atrás
pai
commit
17dae6af8a

+ 35 - 39
gridviewer/GridViewer.py

@@ -1,7 +1,6 @@
 '''
 '''
-Created on 26 nov. 2016
 
 
-@author: olinox
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 from PyQt5.QtCore import QPointF, QMimeData
 from PyQt5.QtCore import QPointF, QMimeData
 from PyQt5.QtWidgets import QMainWindow, \
 from PyQt5.QtWidgets import QMainWindow, \
@@ -9,7 +8,7 @@ from PyQt5.QtWidgets import QMainWindow, \
 import ipdb  # until I find another way to print traceback with pyqt5
 import ipdb  # until I find another way to print traceback with pyqt5
 
 
 from gridviewer.GridViewerCell import GridViewerCell
 from gridviewer.GridViewerCell import GridViewerCell
-from gridviewer.main import Ui_window
+from gridviewer.viewer import Ui_window
 from pypog import geometry
 from pypog import geometry
 
 
 
 
@@ -17,9 +16,6 @@ if __name__ == "__main__":
     import os, sys
     import os, sys
     pypog_path = (os.path.abspath("..\\..\\"))
     pypog_path = (os.path.abspath("..\\..\\"))
     sys.path.append(pypog_path)
     sys.path.append(pypog_path)
-    
-
-
 
 
 class GridViewer(QMainWindow):
 class GridViewer(QMainWindow):
 
 
@@ -28,78 +24,78 @@ class GridViewer(QMainWindow):
         self.cells = {}
         self.cells = {}
         self.selection = []
         self.selection = []
         self.createWidgets()
         self.createWidgets()
-        
+
     def createWidgets(self):
     def createWidgets(self):
         self.ui = Ui_window()
         self.ui = Ui_window()
-        self.ui.setupUi(self)                      
-        
+        self.ui.setupUi(self)
+
         self._scene = QGraphicsScene()
         self._scene = QGraphicsScene()
         self.ui.view.setScene(self._scene)
         self.ui.view.setScene(self._scene)
         self.ui.view.scale(0.5, 0.5)
         self.ui.view.scale(0.5, 0.5)
-        self.ui.view.centerOn(QPointF(0,0))
+        self.ui.view.centerOn(QPointF(0, 0))
         self.ui.view.setDragMode(QGraphicsView.NoDrag)
         self.ui.view.setDragMode(QGraphicsView.NoDrag)
-        
+
         self.ui.txt_coords.setPlainText("[]")
         self.ui.txt_coords.setPlainText("[]")
-        
+
         self.ui.btn_make.clicked.connect(self.make_grid)
         self.ui.btn_make.clicked.connect(self.make_grid)
         self.ui.btn_updateSelection.clicked.connect(self.update_selected_cells)
         self.ui.btn_updateSelection.clicked.connect(self.update_selected_cells)
         self.ui.btn_toClipboard.clicked.connect(self.to_clipboard)
         self.ui.btn_toClipboard.clicked.connect(self.to_clipboard)
         self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
         self.ui.btn_zoom_plus.clicked.connect(self.zoom_plus)
         self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
         self.ui.btn_zoom_minus.clicked.connect(self.zoom_minus)
-        
+
         self.ui.chk_displayCoords.toggled.connect(self.update_cell_labels)
         self.ui.chk_displayCoords.toggled.connect(self.update_cell_labels)
-        
+
         self.make_grid()
         self.make_grid()
-        
+
     def make_grid(self):
     def make_grid(self):
-        
+
         self.selection = []
         self.selection = []
-        shape = geometry.HEX if self.ui.opt_hex.isChecked() else geometry.SQUARE
+        shape = geometry.FLAT_HEX if self.ui.opt_hex.isChecked() else geometry.SQUARE
         width = self.ui.spb_width.value()
         width = self.ui.spb_width.value()
         height = self.ui.spb_height.value()
         height = self.ui.spb_height.value()
-        
+
         kx = 1 if shape == geometry.SQUARE else 0.866
         kx = 1 if shape == geometry.SQUARE else 0.866
 
 
-        margin = 240 
+        margin = 240
         cell_height = 120
         cell_height = 120
-        
+
         self._scene.clear()
         self._scene.clear()
-        
+
         self._scene.setSceneRect(0 - margin, 0 - margin, (kx * cell_height * (width + 2)) + margin, (cell_height * (height + 2)) + margin)
         self._scene.setSceneRect(0 - margin, 0 - margin, (kx * cell_height * (width + 2)) + margin, (cell_height * (height + 2)) + margin)
-        
+
         for x in range(width):
         for x in range(width):
             for y in range(height):
             for y in range(height):
-                
+
                 cell = GridViewerCell(self, x, y)
                 cell = GridViewerCell(self, x, y)
                 cell.generate(shape)
                 cell.generate(shape)
-                
-                self._scene.addItem(cell)   
-                             
+
+                self._scene.addItem(cell)
+
                 self.cells[(x, y)] = cell
                 self.cells[(x, y)] = cell
 
 
 
 
     def add_to_selection(self, x, y):
     def add_to_selection(self, x, y):
-        self.selection.append( (x, y) )
-    
-        self.ui.txt_coords.setText( str(self.selection) )
-    
+        self.selection.append((x, y))
+
+        self.ui.txt_coords.setText(str(self.selection))
+
     def remove_from_selection(self, x, y):
     def remove_from_selection(self, x, y):
-        self.selection.remove( (x, y) )
-        self.ui.txt_coords.setText( str(self.selection) )
-        
+        self.selection.remove((x, y))
+        self.ui.txt_coords.setText(str(self.selection))
+
     def update_selected_cells(self):
     def update_selected_cells(self):
         try:
         try:
             new_selection = list(eval(self.ui.txt_coords.toPlainText()))
             new_selection = list(eval(self.ui.txt_coords.toPlainText()))
         except SyntaxError:
         except SyntaxError:
             QMessageBox.warning(self, "Error", "Invalid string")
             QMessageBox.warning(self, "Error", "Invalid string")
-            return 
-        
+            return
+
         for x, y in tuple(self.selection):
         for x, y in tuple(self.selection):
             self.cells[(x, y)].unselect()
             self.cells[(x, y)].unselect()
-            
+
         for x, y in new_selection:
         for x, y in new_selection:
             self.cells[(x, y)].select()
             self.cells[(x, y)].select()
-            
+
     def to_clipboard(self):
     def to_clipboard(self):
         data = QMimeData()
         data = QMimeData()
         data.setText(self.ui.txt_coords.toPlainText())
         data.setText(self.ui.txt_coords.toPlainText())
@@ -107,7 +103,7 @@ class GridViewer(QMainWindow):
 
 
     def update_cell_labels(self):
     def update_cell_labels(self):
         for cell in self.cells.values():
         for cell in self.cells.values():
-            cell.show_label( bool(self.ui.chk_displayCoords.isChecked()) )
+            cell.show_label(bool(self.ui.chk_displayCoords.isChecked()))
 
 
     def zoom_plus(self):
     def zoom_plus(self):
         self.ui.view.scale(1.1, 1.1)
         self.ui.view.scale(1.1, 1.1)
@@ -118,7 +114,7 @@ class GridViewer(QMainWindow):
 
 
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
-    
+
     app = QApplication(sys.argv)
     app = QApplication(sys.argv)
     gv = GridViewer()
     gv = GridViewer()
     gv.show()
     gv.show()

+ 25 - 26
gridviewer/GridViewerCell.py

@@ -1,7 +1,6 @@
 '''
 '''
-Created on 26 nov. 2016
 
 
-@author: olinox
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 from PyQt5.QtCore import QPointF
 from PyQt5.QtCore import QPointF
 from PyQt5.QtGui import QPolygonF, QPen, QBrush, QColor, QFont
 from PyQt5.QtGui import QPolygonF, QPen, QBrush, QColor, QFont
@@ -12,48 +11,48 @@ from pypog import geometry
 from pypog import graphic
 from pypog import graphic
 
 
 class GridViewerCell(QGraphicsPolygonItem):
 class GridViewerCell(QGraphicsPolygonItem):
-    
+
     def __init__(self, gridViewer, x, y):
     def __init__(self, gridViewer, x, y):
         super(GridViewerCell, self).__init__()
         super(GridViewerCell, self).__init__()
         self.gridViewer = gridViewer
         self.gridViewer = gridViewer
         self.x = x
         self.x = x
         self.y = y
         self.y = y
         self.selected = False
         self.selected = False
-        
+
     def generate(self, shape, scale=120):
     def generate(self, shape, scale=120):
-        
-        points = [QPointF(xp, yp) for xp, yp in graphic.polygon(shape, self.x, self.y, scale)]
-        qpolygon = QPolygonF( points )
-        
+
+        points = [QPointF(xp, yp) for xp, yp in graphic.g_cell(shape, self.x, self.y, scale)]
+        qpolygon = QPolygonF(points)
+
         self.setPolygon(qpolygon)
         self.setPolygon(qpolygon)
-        
+
         pen = QPen()
         pen = QPen()
         pen.setWidth(3)
         pen.setWidth(3)
         self.setPen(pen)
         self.setPen(pen)
-        
-        self.setFlag(QGraphicsItem.ItemIsFocusable)   
-        
+
+        self.setFlag(QGraphicsItem.ItemIsFocusable)
+
         self.label = QGraphicsSimpleTextItem("{}-{}".format(self.x, self.y), parent=self)
         self.label = QGraphicsSimpleTextItem("{}-{}".format(self.x, self.y), parent=self)
         k = 0
         k = 0
-        if (self.x % 2) != 0: 
+        if (self.x % 2) != 0:
             k = 0.5
             k = 0.5
-            
-        if shape == geometry.HEX:
-            self.label.setPos(QPointF(((self.x*0.866)+0.2886)*scale,  (self.y+k+0.5)*scale))
+
+        if shape == geometry.FLAT_HEX:
+            self.label.setPos(QPointF(((self.x * 0.866) + 0.2886) * scale, (self.y + k + 0.5) * scale))
         else:
         else:
-            self.label.setPos(QPointF(self.x*scale,  self.y*scale))
-        
+            self.label.setPos(QPointF(self.x * scale, self.y * scale))
+
         font = QFont()
         font = QFont()
         font.setPointSize(20)
         font.setPointSize(20)
-        self.label.setFont( font )
-        
+        self.label.setFont(font)
+
     def select(self):
     def select(self):
-        self.setBrush( QBrush( QColor(200,0,0, 100) ) )
+        self.setBrush(QBrush(QColor(200, 0, 0, 100)))
         self.selected = True
         self.selected = True
-        self.gridViewer.add_to_selection(self.x, self.y)        
+        self.gridViewer.add_to_selection(self.x, self.y)
 
 
     def unselect(self):
     def unselect(self):
-        self.setBrush( QBrush(  ) )
+        self.setBrush(QBrush())
         self.selected = False
         self.selected = False
         self.gridViewer.remove_from_selection(self.x, self.y)
         self.gridViewer.remove_from_selection(self.x, self.y)
 
 
@@ -63,8 +62,8 @@ class GridViewerCell(QGraphicsPolygonItem):
             self.unselect()
             self.unselect()
         else:
         else:
             self.select()
             self.select()
-    
+
     def show_label(self, visible):
     def show_label(self, visible):
         self.label.setVisible(visible)
         self.label.setVisible(visible)
-        
-    
+
+

+ 0 - 0
gridviewer/main.ui → gridviewer/qt_viewer.ui


+ 0 - 0
gridviewer/main.py → gridviewer/viewer.py


+ 0 - 159
pypog/Grid.py

@@ -1,159 +0,0 @@
-'''
-Created on 7 nov. 2016
-    Game Grid
-@author: olinox
-'''
-from pypog import geometry
-from pypog import pathfinder
-
-
-ORIGIN_HPOSITION_LEFT = 0
-ORIGIN_HPOSITION_MIDDLE = 1
-ORIGIN_HPOSITION_RIGHT = 2
-ORIGIN_VPOSITION_TOP = 10
-ORIGIN_VPOSITION_MIDDLE = 11
-ORIGIN_VPOSITION_BOTTOM = 12
-
-
-class Grid(object):
-    def __init__(self, cell_shape, width, height, roof = None):
-        self._cell_shape = None
-        self.cell_shape = cell_shape
-        
-        self._width = 0
-        self.width = width
-        self._height = 0
-        self.height = height
-        
-        self._roof = roof
-
-        self._cells = {}
-        self._build()
-        
-    def _build(self):
-        for x in range(self.width):
-            for y in range(self.height):
-                cell = Cell(self.cell_shape, x, y)
-                self._cells[(x, y)] = cell
-
-    # properties
-    @property
-    def cell_shape(self):
-        return self._cell_shape
-    
-    @cell_shape.setter
-    def cell_shape(self, cell_shape):
-        if not cell_shape in geometry.GRID_GEOMETRIES:
-            raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")
-        self._cell_shape = cell_shape
-        
-    @property
-    def width(self):
-        return self._width
-    
-    @width.setter
-    def width(self, width):
-        if not isinstance(width, int) or not width > 0:
-            raise ValueError("'width' has to be a strictly positive integer")
-        self._width = width
-        
-    @property
-    def height(self):
-        return self._height
-    
-    @height.setter
-    def height(self, height):
-        if not isinstance(height, int) or not height > 0:
-            raise ValueError("'width' has to be a strictly positive integer")
-        self._height = height    
-    
-    @property
-    def roof(self):
-        return self._roof
-    
-    def cell(self, x, y):
-        return self._cells[(x, y)]
-    
-    @property
-    def cells(self):
-        return self._cells
-    
-    
-    # geometric methods
-    def cases_number(self):
-        return self.height * self.width
-    
-    def in_grid(self, x, y):
-        """return True if the coordinates are in the grid"""
-        return (x > 0 and x <= self._width and y > 0 and y <= self._height)
-    
-    def line(self, x1, y1, x2, y2):
-        return geometry.line2d(self.cell_shape, x1, y1, x2, y2)
-    
-    def line3d(self, x1, y1, z1, x2, y2, z2):
-        return geometry.line3d(self.cell_shape, x1, y1, z1, x2, y2, z2)
-    
-    def zone(self, x, y, radius):
-        return geometry.zone(self.cell_shape, x, y, radius)
-    
-    def triangle(self, xa, ya, xh, yh, iAngle):
-        return geometry.triangle(self.cell_shape, xa, ya, xh, yh, iAngle)
-    
-    def triangle3d(self, xa, ya, za, xh, yh, zh, iAngle):
-        return geometry.triangle3d(self.cell_shape, xa, ya, za, xh, yh, zh, iAngle)
-
-    def rect(self, x1, y1, x2, y2):
-        return geometry.rect(x1, y1, x2, y2)
-    
-    def hollow_rect(self, x1, y1, x2, y2):
-        return geometry.hollow_rect(x1, y1, x2, y2)
-
-
-    # pathfinding methods
-    def moving_cost(self, *args):
-        return 1
-    
-    def path(self, x1, y1, x2, y2):
-        return pathfinder.path( self, (x1, y1), (x2,y2), self.moving_cost_function )
-
-
-class HexGrid(Grid):
-    def __init__(self, width, height):
-        Grid.__init__(self, geometry.HEX, width, height)
-
-class SquareGrid(Grid):
-    def __init__(self, width, height):
-        Grid.__init__(self, geometry.SQUARE, width, height)
-
-
-
-class Cell(object):
-    def __init__(self, cell_shape, x, y, z = 0):
-        self._cell_shape = cell_shape
-        self._x = x
-        self._y = y
-        self._z = z
-
-    @property
-    def x(self):
-        return self._x
-    
-    @property
-    def y(self):
-        return self._y
-    
-    @property
-    def z(self):
-        return self._z
-    
-    @property
-    def coord(self):
-        return (self._x, self._y)
-    
-    @property
-    def coord3d(self):
-        return (self._x, self._y, self._z)
-    
-    def __repr__(self):
-        return "Cell {}".format(self.coord)
-

+ 248 - 262
pypog/geometry.py

@@ -3,7 +3,7 @@
 
 
     2D functions return lists of (x, y) coordinates
     2D functions return lists of (x, y) coordinates
     3D functions return lists of (x, y, z) coordinates
     3D functions return lists of (x, y, z) coordinates
-    
+
     * neighbours_of function return the list of the cells around the (x, y) cell
     * neighbours_of function return the list of the cells around the (x, y) cell
     * zone function return the list of the cells surrounding the (x, y) cell within a 'radius' distance
     * zone function return the list of the cells surrounding the (x, y) cell within a 'radius' distance
     * line2d function return the list of the cells on a line between the (x1, y1) cell and the (x2, y2) cell
     * line2d function return the list of the cells on a line between the (x1, y1) cell and the (x2, y2) cell
@@ -13,44 +13,48 @@
     * triangle function return the list of the cells in a triangle from its apex (xa, ya) to its base (xh, yh)
     * triangle function return the list of the cells in a triangle from its apex (xa, ya) to its base (xh, yh)
     * triangle3d function return the list of the cells in a cone from its apex (xa, ya, za) to its base (xh, yh, zh)
     * triangle3d function return the list of the cells in a cone from its apex (xa, ya, za) to its base (xh, yh, zh)
     * pivot function return a list of coordinates after a counterclockwise rotation of a given list of coordinates, around a given center
     * pivot function return a list of coordinates after a counterclockwise rotation of a given list of coordinates, around a given center
-    
-@author: olinox14
+
+
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 from math import sqrt
 from math import sqrt
 
 
+CELL_SHAPES = (4, 6)
 
 
-GRID_GEOMETRIES = (4, 6)
 SQUARE = 4
 SQUARE = 4
-HEX = 6
+FLAT_HEX = 61
+TOP_HEX = 62
+CELL_SHAPES = (SQUARE, FLAT_HEX, TOP_HEX)
+
 ANGLES = (1, 2, 3)
 ANGLES = (1, 2, 3)
 
 
-## neighbours
+class UnknownCellShape(ValueError): pass
+
 
 
-def neighbours_of(cell_shape, x, y):
+
+# ## NEIGHBOURS
+
+def neighbours(cell_shape, x, y):
     """ returns the list of coords of the neighbours of a cell"""
     """ returns the list of coords of the neighbours of a cell"""
     if cell_shape == SQUARE:
     if cell_shape == SQUARE:
-        return squ_neighbours_of(x, y)
-    elif cell_shape == HEX: 
-        return hex_neighbours_of(x, y)
+        return squ_neighbours(x, y)
+    elif cell_shape == FLAT_HEX:
+        return fhex_neighbours(x, y)
     else:
     else:
-        raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")
+        raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
 
 
-def hex_neighbours_of(x, y):
+def fhex_neighbours(x, y):
     """ returns the list of coords of the neighbours of a cell on an hexagonal grid"""
     """ returns the list of coords of the neighbours of a cell on an hexagonal grid"""
-    if x%2 == 0:
-        return [(x, y-1), (x+1, y-1), (x+1, y), (x,  y+1), (x-1, y), (x-1, y-1)]
+    if x % 2 == 0:
+        return [(x, y - 1), (x + 1, y - 1), (x + 1, y), (x, y + 1), (x - 1, y), (x - 1, y - 1)]
     else:
     else:
-        return [(x, y-1), (x+1, y), (x+1, y+1), (x,  y+1), (x-1, y+1), (x-1, y)]        
+        return [(x, y - 1), (x + 1, y), (x + 1, y + 1), (x, y + 1), (x - 1, y + 1), (x - 1, y)]
 
 
-def squ_neighbours_of(x, y):
+def squ_neighbours(x, y):
     """ returns the list of coords of the neighbours of a cell on an square grid"""
     """ returns the list of coords of the neighbours of a cell on an square grid"""
-    return [(x-1, y-1), (x, y-1), (x+1, y-1), \
-            (x-1, y), (x+1, y)  , \
-            (x-1, y+1), (x, y+1),(x+1, y+1)]
-    
-
-
-## zones
+    return [(x - 1, y - 1), (x, y - 1), (x + 1, y - 1), \
+            (x - 1, y), (x + 1, y)  , \
+            (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)]
 
 
 def zone(cell_shape, x0, y0, radius):
 def zone(cell_shape, x0, y0, radius):
     """ returns the list of the coordinates of the cells in the zone around (x0, y0)
     """ returns the list of the coordinates of the cells in the zone around (x0, y0)
@@ -59,29 +63,29 @@ def zone(cell_shape, x0, y0, radius):
         raise TypeError("x0, y0, radius have to be integers")
         raise TypeError("x0, y0, radius have to be integers")
     if not radius >= 0:
     if not radius >= 0:
         raise ValueError("radius has to be positive")
         raise ValueError("radius has to be positive")
-    buffer = frozenset( [ (x0, y0) ] )
+    buffer = frozenset([ (x0, y0) ])
 
 
     for _ in range(0, radius):
     for _ in range(0, radius):
         current = buffer
         current = buffer
         for x, y in current:
         for x, y in current:
-            buffer |= frozenset( neighbours_of( cell_shape, x, y ) )
+            buffer |= frozenset(neighbours(cell_shape, x, y))
 
 
     return list(buffer)
     return list(buffer)
 
 
 
 
-## line : bresenham algorithm
+# ## LINES (implementations of bresenham algorithm)
 
 
 def line2d(cell_shape, x1, y1, x2, y2):
 def line2d(cell_shape, x1, y1, x2, y2):
     """returns a line from x1,y1 to x2,y2
     """returns a line from x1,y1 to x2,y2
     grid could be one of the GRIDTYPES values"""
     grid could be one of the GRIDTYPES values"""
     if not all(isinstance(c, int) for c in [x1, y1, x2, y2]):
     if not all(isinstance(c, int) for c in [x1, y1, x2, y2]):
         raise TypeError("x1, y1, x2, y2 have to be integers")
         raise TypeError("x1, y1, x2, y2 have to be integers")
-    if cell_shape == HEX:
-        return _brH(x1, y1, x2, y2)
-    elif cell_shape == SQUARE: 
-        return _brC(x1, y1, x2, y2)
+    if cell_shape == FLAT_HEX:
+        return fhex_line(x1, y1, x2, y2)
+    elif cell_shape == SQUARE:
+        return squ2_line(x1, y1, x2, y2)
     else:
     else:
-        raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")
+        raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
 
 
 def line3d(cell_shape, x1, y1, z1, x2, y2, z2):
 def line3d(cell_shape, x1, y1, z1, x2, y2, z2):
     """returns a line from x1,y1,z1 to x2,y2,z2
     """returns a line from x1,y1,z1 to x2,y2,z2
@@ -92,10 +96,10 @@ def line3d(cell_shape, x1, y1, z1, x2, y2, z2):
     if z1 == z2:
     if z1 == z2:
         return [(x, y, z1) for x, y in hoLine]
         return [(x, y, z1) for x, y in hoLine]
     else:
     else:
-        ligneZ = _brC(0, z1, (len(hoLine)-1), z2)
+        ligneZ = squ2_line(0, z1, (len(hoLine) - 1), z2)
         return [(hoLine[d][0], hoLine[d][1], z) for d, z in ligneZ]
         return [(hoLine[d][0], hoLine[d][1], z) for d, z in ligneZ]
 
 
-def _brC(x1, y1, x2, y2):
+def squ2_line(x1, y1, x2, y2):
     """Line Bresenham algorithm for square grid"""
     """Line Bresenham algorithm for square grid"""
     result = []
     result = []
 
 
@@ -103,160 +107,149 @@ def _brC(x1, y1, x2, y2):
         return [(x1, y1)]
         return [(x1, y1)]
 
 
     # DIAGONAL SYMETRY
     # DIAGONAL SYMETRY
-    V = ( abs(y2 - y1) > abs(x2 - x1) )
+    V = (abs(y2 - y1) > abs(x2 - x1))
     if V: y1, x1, y2, x2 = x1, y1, x2, y2
     if V: y1, x1, y2, x2 = x1, y1, x2, y2
-    
+
     # VERTICAL SYMETRY
     # VERTICAL SYMETRY
     reversed_sym = (x1 > x2)
     reversed_sym = (x1 > x2)
-    if reversed_sym:  
+    if reversed_sym:
         x2, y2, x1, y1 = x1, y1, x2, y2
         x2, y2, x1, y1 = x1, y1, x2, y2
-    
+
     DX = x2 - x1 ; DY = y2 - y1
     DX = x2 - x1 ; DY = y2 - y1
     offset = 0.0
     offset = 0.0
     step = 1 if DY > 0 else -1
     step = 1 if DY > 0 else -1
-    alpha = ( abs( DY ) / DX )
-    
+    alpha = (abs(DY) / DX)
+
     y = y1
     y = y1
     for x in range(x1, x2 + 1):
     for x in range(x1, x2 + 1):
         coord = (y, x) if V else (x, y)
         coord = (y, x) if V else (x, y)
         result.append(coord)
         result.append(coord)
-        
+
         offset += alpha
         offset += alpha
         if offset > 0.5:
         if offset > 0.5:
             y += step
             y += step
             offset -= 1.0
             offset -= 1.0
-    
-    if reversed_sym: 
+
+    if reversed_sym:
         result.reverse()
         result.reverse()
     return result
     return result
-    
-def _brH(x1, y1, x2, y2):
+
+def fhex_line(x1, y1, x2, y2):
     """Line Bresenham algorithm for hexagonal grid"""
     """Line Bresenham algorithm for hexagonal grid"""
     if (x1, y1) == (x2, y2):
     if (x1, y1) == (x2, y2):
         return [(x1, y1)]
         return [(x1, y1)]
-    
+
     reversed_sym = (x1 > x2)
     reversed_sym = (x1 > x2)
     if reversed_sym:
     if reversed_sym:
         x1, x2 = x2, x1
         x1, x2 = x2, x1
         y1, y2 = y2, y1
         y1, y2 = y2, y1
-    
-    if abs(x2 - x1) < (2*abs((y2-y1)) + abs(x2 % 2) - abs(x1 % 1)):
-        result = _brH_v(x1, y1, x2, y2)
-    else:
-        result = _brH_h(x1, y1, x2, y2)   
 
 
-    if reversed_sym: 
-        result.reverse()
-    return result
-         
-def _brH_h(x1, y1, x2, y2):
-    """Line Bresenham algorithm for hexagonal grid (horizontal quadrants)"""  
-    dx = x2 - x1 ; dy = y2 - y1 
-    if (x1 + x2) % 2 == 1: 
-        dy += 0.5 if x1 % 2 == 0 else -0.5
-                
-    k = dy / dx
-    pas = 1
-    
-    result = []
-    d = 0.0
-    pos = (x1, y1)
-    result.append(pos)
-    
-    while pos != (x2, y2):
-        d += k*pas
-        if d > 0:
-            x, y = pos
-            if x % 2 == 0:
-                pos = x + 1, y 
+    if abs(x2 - x1) < (2 * abs((y2 - y1)) + abs(x2 % 2) - abs(x1 % 1)):
+        # vertical quadrants
+
+        # unit is half the width: u = 0.5773
+        # half-height is then 0.8860u, or sqrt(3)/2
+        direction = 1 if y2 > y1 else -1
+
+        dx = 1.5 * (x2 - x1)
+        dy = direction * (y2 - y1)
+        if (x1 + x2) % 2 == 1:
+            if x1 % 2 == 0:
+                dy += direction * 0.5
             else:
             else:
-                pos = x + 1, y + 1 
-            result.append(pos)
-            d -= 0.5
-        else:
-            x, y = pos
-            if x % 2 == 0:
-                pos = x + 1, y - 1   
+                dy -= direction * 0.5
+
+        k = dx / (dy * sqrt(3))
+        pas = 0.5 * sqrt(3)
+
+        result = []
+        offset = 0.0
+        pos = (x1, y1)
+        result.append(pos)
+
+        while pos != (x2, y2):
+            offset += (k * pas)
+            if offset <= 0.5:
+                x, y = pos
+                pos = x, y + direction
+                result.append(pos)
+                offset += (k * pas)
             else:
             else:
-                pos = x + 1, y         
-            result.append(pos)
-            d += 0.5
-        
-        # in case of error in the algorithm, we should avoid infinite loop:
-        if pos[0] > x2:
-            result = []
-            break
-                      
-    return result
-     
-def _brH_v(x1, y1, x2, y2):
-    """Line Bresenham algorithm for hexagonal grid (vertical quadrants)"""  
-    # unit is half the width: u = 0.5773
-    # half-height is then 0.8860u, or sqrt(3)/2
-    direction = 1 if y2 > y1 else -1
- 
-    dx = 1.5 * (x2 - x1)  
-    dy = direction * (y2 - y1)    
-    if (x1 + x2) % 2 == 1: 
-        if x1 % 2 == 0:
-            dy += direction*0.5
-        else:
-            dy -= direction*0.5
- 
-    k = dx/(dy*sqrt(3)) 
-    pas = 0.5*sqrt(3)
- 
-    result = []
-    offset = 0.0
-    pos = (x1, y1)
-    result.append(pos)
-    
-    while pos != (x2, y2):
-        offset += (k*pas)
-        if offset <= 0.5:
-            x, y = pos
-            pos = x, y + direction
-            result.append(pos)
-            offset += (k*pas)
-        else:
-            x, y = pos
-            if (x %2 == 0 and direction == 1) or (x % 2 == 1 and direction == -1):
-                pos = x + 1, y
+                x, y = pos
+                if (x % 2 == 0 and direction == 1) or (x % 2 == 1 and direction == -1):
+                    pos = x + 1, y
+                else:
+                    pos = x + 1, y + direction
+                result.append(pos)
+                offset -= 1.5
+
+            # in case of error in the algorithm, we should avoid infinite loop:
+            if direction * pos[1] > direction * y2:
+                result = []
+                break
+
+    else:
+        # horizontal quadrants
+        dx = x2 - x1 ; dy = y2 - y1
+        if (x1 + x2) % 2 == 1:
+            dy += 0.5 if x1 % 2 == 0 else -0.5
+
+        k = dy / dx
+        pas = 1
+
+        result = []
+        d = 0.0
+        pos = (x1, y1)
+        result.append(pos)
+
+        while pos != (x2, y2):
+            d += k * pas
+            if d > 0:
+                x, y = pos
+                if x % 2 == 0:
+                    pos = x + 1, y
+                else:
+                    pos = x + 1, y + 1
+                result.append(pos)
+                d -= 0.5
             else:
             else:
-                pos = x + 1, y + direction            
-            result.append(pos)
-            offset -= 1.5
-        
-        # in case of error in the algorithm, we should avoid infinite loop:
-        if direction*pos[1] > direction*y2:
-            result = []
-            break
- 
-    return result 
+                x, y = pos
+                if x % 2 == 0:
+                    pos = x + 1, y - 1
+                else:
+                    pos = x + 1, y
+                result.append(pos)
+                d += 0.5
+
+            # in case of error in the algorithm, we should avoid infinite loop:
+            if pos[0] > x2:
+                result = []
+                break
+
+    if reversed_sym:
+        result.reverse()
+    return result
 
 
 
 
-## rectangles
+# ## RECTANGLES
 
 
-def rect(x1, y1, x2, y2):
+def rectangle(x1, y1, x2, y2):
     """return a list of cells in a rectangle between (X1, Y1), (X2, Y2)"""
     """return a list of cells in a rectangle between (X1, Y1), (X2, Y2)"""
     if not all(isinstance(val, int) for val in [x1, y1, x2, y2]):
     if not all(isinstance(val, int) for val in [x1, y1, x2, y2]):
         raise TypeError("x1, y1, x2, y2 should be integers")
         raise TypeError("x1, y1, x2, y2 should be integers")
     xa, ya, xb, yb = min([x1, x2]), min([y1, y2]), max([x1, x2]), max([y1, y2])
     xa, ya, xb, yb = min([x1, x2]), min([y1, y2]), max([x1, x2]), max([y1, y2])
     return [(x, y) for x in range(xa, xb + 1) for y in range(ya, yb + 1)]
     return [(x, y) for x in range(xa, xb + 1) for y in range(ya, yb + 1)]
 
 
-def hollow_rect(x1, y1, x2, y2):
+def hollow_rectangle(x1, y1, x2, y2):
     """return a list of cells composing the sides of the rectangle between (X1, Y1), (X2, Y2)"""
     """return a list of cells composing the sides of the rectangle between (X1, Y1), (X2, Y2)"""
     if not all(isinstance(val, int) for val in [x1, y1, x2, y2]):
     if not all(isinstance(val, int) for val in [x1, y1, x2, y2]):
         raise TypeError("x1, y1, x2, y2 should be integers")
         raise TypeError("x1, y1, x2, y2 should be integers")
-    return [(x, y) for x, y in rect(x1, y1, x2, y2)
+    return [(x, y) for x, y in rectangle(x1, y1, x2, y2)
             if (x == x1 or x == x2 or y == y1 or y == y2)]
             if (x == x1 or x == x2 or y == y1 or y == y2)]
-    
-    
-    
-## triangles
-    
 
 
 
 
+# ## TRIANGLES
+
 def triangle(cell_shape, xa, ya, xh, yh, iAngle):
 def triangle(cell_shape, xa, ya, xh, yh, iAngle):
     """Returns a list of (x, y) coordinates in a triangle
     """Returns a list of (x, y) coordinates in a triangle
     A is the top of the triangle, H if the middle of the base
     A is the top of the triangle, H if the middle of the base
@@ -264,219 +257,219 @@ def triangle(cell_shape, xa, ya, xh, yh, iAngle):
     if not all(isinstance(c, int) for c in [xa, ya, xh, yh]):
     if not all(isinstance(c, int) for c in [xa, ya, xh, yh]):
         raise TypeError("xa, ya, xh, yh should be integers")
         raise TypeError("xa, ya, xh, yh should be integers")
     if not iAngle in ANGLES:
     if not iAngle in ANGLES:
-        raise ValueError("iAngle should be one of the ANGLES values")   
-    
+        raise ValueError("iAngle should be one of the ANGLES values")
+
     if cell_shape == SQUARE:
     if cell_shape == SQUARE:
-        return _triangle_sq(xa, ya, xh, yh, iAngle)
-    elif cell_shape == HEX: 
-        return _triangle_hex(xa, ya, xh, yh, iAngle)
+        return squ2_triangle(xa, ya, xh, yh, iAngle)
+    elif cell_shape == FLAT_HEX:
+        return fhex2_triangle(xa, ya, xh, yh, iAngle)
     else:
     else:
-        raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")
+        raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
 
 
 def triangle3d(cell_shape, xa, ya, za, xh, yh, zh, iAngle):
 def triangle3d(cell_shape, xa, ya, za, xh, yh, zh, iAngle):
     """Returns a list of (x, y, z) coordinates in a 3d-cone
     """Returns a list of (x, y, z) coordinates in a 3d-cone
     A is the top of the cone, H if the center of the base
     A is the top of the cone, H if the center of the base
-    
+
     WARNING: result is a dictionnary of the form {(x, y): (-z, +z)}
     WARNING: result is a dictionnary of the form {(x, y): (-z, +z)}
-    
+
     This is for performance reason, because on a 2d grid, you generrally don't need a complete list of z coordinates
     This is for performance reason, because on a 2d grid, you generrally don't need a complete list of z coordinates
     as you don't want to display them: you just want to know if an altitude is inside a range.
     as you don't want to display them: you just want to know if an altitude is inside a range.
-    
+
     That could change in later version
     That could change in later version
     """
     """
     # TODO: review the result form
     # TODO: review the result form
-    
+
     if not all(isinstance(c, int) for c in [za, zh]):
     if not all(isinstance(c, int) for c in [za, zh]):
         raise TypeError("xa, ya, za, xh, yh, zh should be integers")
         raise TypeError("xa, ya, za, xh, yh, zh should be integers")
         # a triangle2d will be built during algo, so other args will be checked later
         # a triangle2d will be built during algo, so other args will be checked later
-    
+
     if cell_shape == SQUARE:
     if cell_shape == SQUARE:
-        return _triangle_sq_3d(xa, ya, za, xh, yh, zh, iAngle)
-    elif cell_shape == HEX: 
-        return _triangle_hex_3d(xa, ya, za, xh, yh, zh, iAngle)
+        return squ3_triangle(xa, ya, za, xh, yh, zh, iAngle)
+    elif cell_shape == FLAT_HEX:
+        return fhex3_triangle(xa, ya, za, xh, yh, zh, iAngle)
     else:
     else:
-        raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")    
-    
+        raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
 
 
-def _triangle_sq(xa, ya, xh, yh, iAngle):   
+
+def squ2_triangle(xa, ya, xh, yh, iAngle):
     """ triangle algorithm on square grid
     """ triangle algorithm on square grid
     """
     """
     if (xa, ya) == (xh, yh):
     if (xa, ya) == (xh, yh):
-        return [(xa, ya)] 
-    
+        return [(xa, ya)]
+
     result = []
     result = []
-    
+
     # direction vector
     # direction vector
     dx_dir, dy_dir = xh - xa, yh - ya
     dx_dir, dy_dir = xh - xa, yh - ya
-    
+
     # normal vector
     # normal vector
-    dx_n, dy_n = - dy_dir, dx_dir
+    dx_n, dy_n = -dy_dir, dx_dir
 
 
     # B and C positions
     # B and C positions
-    k = 1 / ( iAngle * sqrt(3) )
+    k = 1 / (iAngle * sqrt(3))
     xb, yb = xh + (k * dx_n), yh + (k * dy_n)
     xb, yb = xh + (k * dx_n), yh + (k * dy_n)
     xc, yc = xh + (-k * dx_n), yh + (-k * dy_n)
     xc, yc = xh + (-k * dx_n), yh + (-k * dy_n)
-    
+
     xb, yb = round(xb), round(yb)
     xb, yb = round(xb), round(yb)
     xc, yc = round(xc), round(yc)
     xc, yc = round(xc), round(yc)
 
 
     # sides:
     # sides:
     lines = [(xa, ya, xb, yb), (xb, yb, xc, yc), (xc, yc, xa, ya)]
     lines = [(xa, ya, xb, yb), (xb, yb, xc, yc), (xc, yc, xa, ya)]
-    
+
     # base (lower slope)
     # base (lower slope)
-    x1, y1, x2, y2 = min(lines, key=lambda x: (abs ( (x[3] - x[1]) / (x[2] - x[0]) ) if x[2] != x[0] else 10**10))
+    x1, y1, x2, y2 = min(lines, key=lambda x: (abs ((x[3] - x[1]) / (x[2] - x[0])) if x[2] != x[0] else 10 ** 10))
     base = line2d(SQUARE, x1, y1, x2, y2)
     base = line2d(SQUARE, x1, y1, x2, y2)
     y_base = y1
     y_base = y1
-    lines.remove( (x1, y1, x2, y2) )
-    
+    lines.remove((x1, y1, x2, y2))
+
     # 'hat' (2 other sides)
     # 'hat' (2 other sides)
     hat = []
     hat = []
     y_top = None
     y_top = None
     for x1, y1, x2, y2 in lines:
     for x1, y1, x2, y2 in lines:
-        if y_top == None: 
+        if y_top == None:
             y_top = y2
             y_top = y2
-        hat.extend( line2d(SQUARE, x1, y1, x2, y2) )
-    
+        hat.extend(line2d(SQUARE, x1, y1, x2, y2))
+
     # sense (1 if top is under base, -1 if not)
     # sense (1 if top is under base, -1 if not)
     sense = 1 if y_top > y_base else -1
     sense = 1 if y_top > y_base else -1
-    
+
     # rove over y values from base to hat
     # rove over y values from base to hat
     for x, y in base:
     for x, y in base:
         while not (x, y) in hat:
         while not (x, y) in hat:
-            result.append( (x, y) )
+            result.append((x, y))
             y += sense
             y += sense
     result.extend(hat)
     result.extend(hat)
 
 
     return result
     return result
 
 
-def _triangle_hex(xa, ya, xh, yh, iAngle):   
+def fhex2_triangle(xa, ya, xh, yh, iAngle):
     """  triangle algorithm on hexagonal grid
     """  triangle algorithm on hexagonal grid
     """
     """
     if (xa, ya) == (xh, yh):
     if (xa, ya) == (xh, yh):
-        return [(xa, ya)]    
-    
+        return [(xa, ya)]
+
     result = []
     result = []
-    
+
     # convert to cubic coodinates (see 'cube_coords' lib)
     # convert to cubic coodinates (see 'cube_coords' lib)
-    xua, yua, _ = cv_off_cube( xa, ya )
-    xuh, yuh, zuh = cv_off_cube( xh, yh )
-    
+    xua, yua, _ = cv_off_cube(xa, ya)
+    xuh, yuh, zuh = cv_off_cube(xh, yh)
+
     # direction vector
     # direction vector
     dx_dir, dy_dir = xuh - xua, yuh - yua
     dx_dir, dy_dir = xuh - xua, yuh - yua
-    
+
     # normal vector
     # normal vector
-    dx_n, dy_n = - (2* dy_dir + dx_dir ), (2* dx_dir + dy_dir ) 
-    dz_n = (- dx_n - dy_n)        
+    dx_n, dy_n = -(2 * dy_dir + dx_dir), (2 * dx_dir + dy_dir)
+    dz_n = (-dx_n - dy_n)
 
 
     # B and C positions
     # B and C positions
-    k = 1 / ( iAngle * sqrt(3) )
+    k = 1 / (iAngle * sqrt(3))
     xub, yub, zub = xuh + (k * dx_n), yuh + (k * dy_n), zuh + (k * dz_n)
     xub, yub, zub = xuh + (k * dx_n), yuh + (k * dy_n), zuh + (k * dz_n)
     xuc, yuc, zuc = xuh + (-k * dx_n), yuh + (-k * dy_n), zuh + (-k * dz_n)
     xuc, yuc, zuc = xuh + (-k * dx_n), yuh + (-k * dy_n), zuh + (-k * dz_n)
-    
+
     xub, yub, zub = cube_round(xub, yub, zub)
     xub, yub, zub = cube_round(xub, yub, zub)
     xuc, yuc, zuc = cube_round(xuc, yuc, zuc)
     xuc, yuc, zuc = cube_round(xuc, yuc, zuc)
-    
+
     xb, yb = cv_cube_off(xub, yub, zub)
     xb, yb = cv_cube_off(xub, yub, zub)
     xc, yc = cv_cube_off(xuc, yuc, zuc)
     xc, yc = cv_cube_off(xuc, yuc, zuc)
 
 
     # sides
     # sides
     segments = [(xa, ya, xb, yb), (xb, yb, xc, yc), (xc, yc, xa, ya)]
     segments = [(xa, ya, xb, yb), (xb, yb, xc, yc), (xc, yc, xa, ya)]
-    
+
     # base (lower slope)
     # base (lower slope)
-    x1, y1, x2, y2 = min(segments, key=lambda x: (abs ( (x[3] - x[1]) / (x[2] - x[0]) ) if x[2] != x[0] else 10**10))
-    base = line2d(HEX, x1, y1, x2, y2)
+    x1, y1, x2, y2 = min(segments, key=lambda x: (abs ((x[3] - x[1]) / (x[2] - x[0])) if x[2] != x[0] else 10 ** 10))
+    base = line2d(FLAT_HEX, x1, y1, x2, y2)
     y_base = y1
     y_base = y1
-    segments.remove( (x1, y1, x2, y2) )
-    
+    segments.remove((x1, y1, x2, y2))
+
     # 'hat' (the 2 other sides)
     # 'hat' (the 2 other sides)
     chapeau = []
     chapeau = []
     y_sommet = None
     y_sommet = None
     for x1, y1, x2, y2 in segments:
     for x1, y1, x2, y2 in segments:
-        if y_sommet == None: 
+        if y_sommet == None:
             y_sommet = y2
             y_sommet = y2
-        chapeau.extend( line2d(HEX, x1, y1, x2, y2) )
-    
+        chapeau.extend(line2d(FLAT_HEX, x1, y1, x2, y2))
+
     # sense (1 if top is under base, -1 if not)
     # sense (1 if top is under base, -1 if not)
     sens = 1 if y_sommet > y_base else -1
     sens = 1 if y_sommet > y_base else -1
-    
+
     # rove over y values from base to hat
     # rove over y values from base to hat
     for x, y in base:
     for x, y in base:
         while not (x, y) in chapeau:
         while not (x, y) in chapeau:
-            result.append( (x, y) )
+            result.append((x, y))
             y += sens
             y += sens
     result.extend(chapeau)
     result.extend(chapeau)
 
 
     return result
     return result
 
 
 
 
-def _triangle_sq_3d(xa, ya, za, xh, yh, zh, iAngle):
+def squ3_triangle(xa, ya, za, xh, yh, zh, iAngle):
     """ 3d triangle algorithm on square grid"""
     """ 3d triangle algorithm on square grid"""
     result = []
     result = []
-    
+
     flat_triangle = triangle(SQUARE, xa, ya, xh, yh, iAngle)
     flat_triangle = triangle(SQUARE, xa, ya, xh, yh, iAngle)
-    k = 1 / ( iAngle * sqrt(3) )
+    k = 1 / (iAngle * sqrt(3))
 
 
-    length = max( abs(xh - xa), abs(yh - ya) )
+    length = max(abs(xh - xa), abs(yh - ya))
 
 
     vertical_line = line2d(SQUARE, 0, za, length, zh)
     vertical_line = line2d(SQUARE, 0, za, length, zh)
-    
+
     # build a dict with X key and value is a list of Z values
     # build a dict with X key and value is a list of Z values
     vertical_line_dict = {d:[] for d, z in vertical_line}
     vertical_line_dict = {d:[] for d, z in vertical_line}
     for d, z in vertical_line:
     for d, z in vertical_line:
         vertical_line_dict[d].append(z)
         vertical_line_dict[d].append(z)
-        
+
     # this is approximative: height is update according to the manhattan distance to center
     # this is approximative: height is update according to the manhattan distance to center
     for x, y in flat_triangle:
     for x, y in flat_triangle:
-        distance = int( max( abs(x - xa), abs(y - ya) ) )
+        distance = int(max(abs(x - xa), abs(y - ya)))
         try:
         try:
             z_list = vertical_line_dict[ distance ]
             z_list = vertical_line_dict[ distance ]
         except KeyError:
         except KeyError:
             distance = length
             distance = length
             z_list = vertical_line_dict[ distance ]
             z_list = vertical_line_dict[ distance ]
-        dh = int( k * distance ) + 1 if distance > 0 else 0
-        result[ (x, y) ] = ( (min(z_list) - dh) , (max(z_list) + dh) ) 
+        dh = int(k * distance) + 1 if distance > 0 else 0
+        result[ (x, y) ] = ((min(z_list) - dh) , (max(z_list) + dh))
     return result
     return result
 
 
-def _triangle_hex_3d(xa, ya, za, xh, yh, zh, iAngle):
+def fhex3_triangle(xa, ya, za, xh, yh, zh, iAngle):
     """ 3d triangle algorithm on hexagonal grid """
     """ 3d triangle algorithm on hexagonal grid """
-    
-    flat_triangle = triangle(HEX, xa, ya, xh, yh, iAngle)
 
 
-    result = {} 
-    
-    k = 1 / ( iAngle * sqrt(3) )
-    
+    flat_triangle = triangle(FLAT_HEX, xa, ya, xh, yh, iAngle)
+
+    result = {}
+
+    k = 1 / (iAngle * sqrt(3))
+
     # use cubic coordinates
     # use cubic coordinates
     xua, yua, zua = cv_off_cube(xa, ya)
     xua, yua, zua = cv_off_cube(xa, ya)
     xuh, yuh, zuh = cv_off_cube(xh, yh)
     xuh, yuh, zuh = cv_off_cube(xh, yh)
-    
-    length = max( abs(xuh - xua), abs(yuh - yua), abs(zuh - zua) )
+
+    length = max(abs(xuh - xua), abs(yuh - yua), abs(zuh - zua))
 
 
     vertical_line = line2d(SQUARE, 0, za, length, zh)
     vertical_line = line2d(SQUARE, 0, za, length, zh)
-    
+
     # build a dict with X key and value is a list of Z values
     # build a dict with X key and value is a list of Z values
     vertical_line_dict = {d:[] for d, z in vertical_line}
     vertical_line_dict = {d:[] for d, z in vertical_line}
     for d, z in vertical_line:
     for d, z in vertical_line:
         vertical_line_dict[d].append(z)
         vertical_line_dict[d].append(z)
-        
+
     # this is approximative: height is update according to the manhattan distance to center
     # this is approximative: height is update according to the manhattan distance to center
     for x, y in flat_triangle:
     for x, y in flat_triangle:
         xu, yu, zu = cv_off_cube(x, y)
         xu, yu, zu = cv_off_cube(x, y)
-        distance = int( max( abs(xu - xua), abs(yu - yua), abs(zu - zua) ) )
+        distance = int(max(abs(xu - xua), abs(yu - yua), abs(zu - zua)))
         try:
         try:
             z_list = vertical_line_dict[ distance ]
             z_list = vertical_line_dict[ distance ]
         except KeyError:
         except KeyError:
             distance = length
             distance = length
             z_list = vertical_line_dict[ distance ]
             z_list = vertical_line_dict[ distance ]
-        dh = int( k * distance ) + 1 if distance > 0 else 0
-        result[ (x, y) ] = ( (min(z_list) - dh) , (max(z_list) + dh) ) 
+        dh = int(k * distance) + 1 if distance > 0 else 0
+        result[ (x, y) ] = ((min(z_list) - dh) , (max(z_list) + dh))
     return result
     return result
 
 
 
 
-## pivot
+# ## TRANSLATIONS / ROTATIONS
 
 
 def pivot(cell_shape, center, coordinates, rotations):
 def pivot(cell_shape, center, coordinates, rotations):
-    """pivot 'rotations' times the coordinates (list of (x, y) tuples) 
+    """pivot 'rotations' times the coordinates (list of (x, y) tuples)
     around the center coordinates (x,y)
     around the center coordinates (x,y)
     Rotation is counterclockwise"""
     Rotation is counterclockwise"""
     # check the args:
     # check the args:
@@ -486,41 +479,40 @@ def pivot(cell_shape, center, coordinates, rotations):
         raise TypeError("'center' should be an tuple of (x, y) coordinates with x and y integers (given: {})".format(center))
         raise TypeError("'center' should be an tuple of (x, y) coordinates with x and y integers (given: {})".format(center))
     if not isinstance(x, int) or not isinstance(y, int):
     if not isinstance(x, int) or not isinstance(y, int):
         raise ValueError("'center' should be an tuple of (x, y) coordinates with x and y integers (given: {})".format(center))
         raise ValueError("'center' should be an tuple of (x, y) coordinates with x and y integers (given: {})".format(center))
-        
+
     try:
     try:
         for coord in coordinates:
         for coord in coordinates:
             try:
             try:
                 x, y = coord
                 x, y = coord
                 if not isinstance(x, int) or not isinstance(y, int):
                 if not isinstance(x, int) or not isinstance(y, int):
-                    raise ValueError() 
+                    raise ValueError()
             except ValueError:
             except ValueError:
                 raise ValueError("'coordinates' should be an list of (x, y) coordinates with x and y integers (given: {})".format(coordinates))
                 raise ValueError("'coordinates' should be an list of (x, y) coordinates with x and y integers (given: {})".format(coordinates))
     except TypeError:
     except TypeError:
         raise TypeError("'coordinates' should be an list of (x, y) coordinates with x and y integers (given: {})".format(coordinates))
         raise TypeError("'coordinates' should be an list of (x, y) coordinates with x and y integers (given: {})".format(coordinates))
-    
+
     if not isinstance(rotations, int):
     if not isinstance(rotations, int):
         raise TypeError("'rotations' should be an integer (given: {})".format(rotations))
         raise TypeError("'rotations' should be an integer (given: {})".format(rotations))
-    
+
     # call the method according to cells shape
     # call the method according to cells shape
     if cell_shape == SQUARE:
     if cell_shape == SQUARE:
-        return _squ_pivot(center, coordinates, rotations)
-    elif cell_shape == HEX: 
-        return _hex_pivot(center, coordinates, rotations)
+        return squ_pivot(center, coordinates, rotations)
+    elif cell_shape == FLAT_HEX:
+        return fhex_pivot(center, coordinates, rotations)
     else:
     else:
-        raise ValueError("'cell_shape' has to be a value from GRID_GEOMETRIES")
+        raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
 
 
 
 
-def _hex_pivot(center, coordinates, rotations):
-    """pivot 'rotations' times the coordinates (list of (x, y) tuples) 
+def fhex_pivot(center, coordinates, rotations):
+    """pivot 'rotations' times the coordinates (list of (x, y) tuples)
     around the center coordinates (x,y)
     around the center coordinates (x,y)
     On hexagonal grid, rotates of 60 degrees each time"""
     On hexagonal grid, rotates of 60 degrees each time"""
-    if coordinates == [center] or rotations%6 == 0:
+    if coordinates == [center] or rotations % 6 == 0:
         return coordinates
         return coordinates
-    
     x0, y0 = center
     x0, y0 = center
     xu0, yu0, zu0 = cv_off_cube(x0, y0)
     xu0, yu0, zu0 = cv_off_cube(x0, y0)
     result = []
     result = []
-    
+
     for x, y in coordinates:
     for x, y in coordinates:
         xu, yu, zu = cv_off_cube(x, y)
         xu, yu, zu = cv_off_cube(x, y)
         dxu, dyu, dzu = xu - xu0, yu - yu0, zu - zu0
         dxu, dyu, dzu = xu - xu0, yu - yu0, zu - zu0
@@ -528,69 +520,63 @@ def _hex_pivot(center, coordinates, rotations):
             dxu, dyu, dzu = -dzu, -dxu, -dyu
             dxu, dyu, dzu = -dzu, -dxu, -dyu
         xru, yru, zru = dxu + xu0, dyu + yu0, dzu + zu0
         xru, yru, zru = dxu + xu0, dyu + yu0, dzu + zu0
         xr, yr = cv_cube_off(xru, yru, zru)
         xr, yr = cv_cube_off(xru, yru, zru)
-        result.append( (xr, yr) )
-        
+        result.append((xr, yr))
     return result
     return result
 
 
-def _squ_pivot(center, coordinates, rotations):
-    """pivot 'rotations' times the coordinates (list of (x, y) tuples) 
+def squ_pivot(center, coordinates, rotations):
+    """pivot 'rotations' times the coordinates (list of (x, y) tuples)
     around the center coordinates (x,y)
     around the center coordinates (x,y)
     On square grid, rotates of 90 degrees each time"""
     On square grid, rotates of 90 degrees each time"""
-    if coordinates == [center] or rotations%4 == 0:
+    if coordinates == [center] or rotations % 4 == 0:
         return coordinates
         return coordinates
-    
     x0, y0 = center
     x0, y0 = center
     result = []
     result = []
-    
     for x, y in coordinates:
     for x, y in coordinates:
-        
         dx, dy = x - x0, y - y0
         dx, dy = x - x0, y - y0
         for _ in range(rotations):
         for _ in range(rotations):
             dx, dy = dy, -dx
             dx, dy = dy, -dx
-            
         xr, yr = dx + x0, dy + y0
         xr, yr = dx + x0, dy + y0
-        result.append( (xr, yr) )
-        
+        result.append((xr, yr))
     return result
     return result
 
 
-## cubic coordinates
+
+# ## CUBIC COORDINATES
 def cv_cube_off(xu, yu, zu):
 def cv_cube_off(xu, yu, zu):
     """convert cubic coordinates (xu, yu, zu) in standards coordinates (x, y) [offset]"""
     """convert cubic coordinates (xu, yu, zu) in standards coordinates (x, y) [offset]"""
-    y = int( xu + ( zu - (zu & 1) ) / 2 )
+    y = int(xu + (zu - (zu & 1)) / 2)
     x = zu
     x = zu
-    return (x, y)        
+    return (x, y)
 
 
 def cv_off_cube(x, y):
 def cv_off_cube(x, y):
     """converts standards coordinates (x, y) [offset] in cubic coordinates (xu, yu, zu)"""
     """converts standards coordinates (x, y) [offset] in cubic coordinates (xu, yu, zu)"""
     zu = x
     zu = x
-    xu = int( y - ( x - (x & 1) ) / 2 )
-    yu = int( -xu -zu )
-    return (xu, yu, zu)    
+    xu = int(y - (x - (x & 1)) / 2)
+    yu = int(-xu - zu)
+    return (xu, yu, zu)
 
 
-# unused
+# > unused
 def cube_round(x, y, z):
 def cube_round(x, y, z):
     """returns the nearest cell (in cubic coords)
     """returns the nearest cell (in cubic coords)
     x, y, z can be floating numbers, no problem."""
     x, y, z can be floating numbers, no problem."""
     rx, ry, rz = round(x), round(y), round(z)
     rx, ry, rz = round(x), round(y), round(z)
     x_diff, y_diff, z_diff = abs(rx - x), abs(ry - y), abs(rz - z)
     x_diff, y_diff, z_diff = abs(rx - x), abs(ry - y), abs(rz - z)
     if x_diff > y_diff and x_diff > z_diff:
     if x_diff > y_diff and x_diff > z_diff:
-        rx = -ry-rz
+        rx = -ry - rz
     elif y_diff > z_diff:
     elif y_diff > z_diff:
-        ry = -rx-rz
+        ry = -rx - rz
     else:
     else:
-        rz = -rx-ry
+        rz = -rx - ry
     return (rx, ry, rz)
     return (rx, ry, rz)
 
 
-# unused
+# > unused
 def hex_distance_cube(xa, ya, za, xb, yb, zb):
 def hex_distance_cube(xa, ya, za, xb, yb, zb):
     """returns the manhattan distance between the two cells"""
     """returns the manhattan distance between the two cells"""
     return max(abs(xa - xb), abs(ya - yb), abs(za - zb))
     return max(abs(xa - xb), abs(ya - yb), abs(za - zb))
 
 
-# unused
+# > unused
 def distance_off(xa, ya, xb, yb):
 def distance_off(xa, ya, xb, yb):
     """ distance between A and B (offset coordinates)"""
     """ distance between A and B (offset coordinates)"""
     # 10 times quicker if no conversion...
     # 10 times quicker if no conversion...
     xua, yua, zua = cv_off_cube(xa, ya)
     xua, yua, zua = cv_off_cube(xa, ya)
     xub, yub, zub = cv_off_cube(xb, yb)
     xub, yub, zub = cv_off_cube(xb, yb)
     return max(abs(xua - xub), abs(yua - yub), abs(zua - zub))
     return max(abs(xua - xub), abs(yua - yub), abs(zua - zub))
-    

+ 28 - 28
pypog/graphic.py

@@ -1,35 +1,35 @@
 '''
 '''
-Created on 5 dec. 2016
+    Graphical functions
 
 
-@author: olinox
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
-
 from pypog import geometry
 from pypog import geometry
 
 
-
-def polygon(shape, x, y, scale = 120):
-    if shape == geometry.HEX:
-        
-        if 1 == (x % 2): 
-            y += 0.5
-            
-        return [
-                   ( ((x*0.866)+0.2886) * scale ,   y * scale), \
-                   ( ((x*0.866)+0.866) * scale  ,   y * scale), \
-                   ( ((x*0.866)+1.1547) * scale ,   (y+0.5) * scale), \
-                   ( ((x*0.866)+0.866) * scale  ,   (y+1) * scale), \
-                   ( ((x*0.866)+0.2886) * scale ,   (y+1) * scale),  \
-                   ( (x*0.866) * scale          ,   (y+0.5) * scale) 
-                ]
-
+def g_cell(shape, *args):
+    if shape == geometry.FLAT_HEX:
+        return g_flathex(*args)
     elif shape == geometry.SQUARE :
     elif shape == geometry.SQUARE :
-        
-        return  [ 
-                    (x * scale,      y * scale), \
-                    ((x+1) * scale,  y * scale), \
-                    ((x+1) * scale,  (y+1) * scale), \
-                    (x * scale,       (y+1) * scale) 
-                ]   
-        
+        return g_square(*args)
     else:
     else:
-        raise ValueError("'shape' has to be a value from GEOMETRIES")
+        raise geometry.UnknownCellShape()
+
+def g_flathex(x, y, scale=120):
+    if x % 2 != 0:
+        y += 0.5
+    return [
+               (((x * 0.866) + 0.2886) * scale , y * scale), \
+               (((x * 0.866) + 0.866) * scale  , y * scale), \
+               (((x * 0.866) + 1.1547) * scale , (y + 0.5) * scale), \
+               (((x * 0.866) + 0.866) * scale  , (y + 1) * scale), \
+               (((x * 0.866) + 0.2886) * scale , (y + 1) * scale), \
+               ((x * 0.866) * scale          , (y + 0.5) * scale)
+            ]
+
+def g_square(x, y, scale=120):
+    return  [
+                (x * scale, y * scale), \
+                ((x + 1) * scale, y * scale), \
+                ((x + 1) * scale, (y + 1) * scale), \
+                (x * scale, (y + 1) * scale)
+            ]
+

+ 171 - 20
pypog/Piece.py → pypog/grid_objects.py

@@ -1,9 +1,161 @@
 '''
 '''
-Created on 6 dec. 2016
-    Piece could represent any object on the grid: player, creature, pawn...etc
-@author: olinox
+    Game Grid
+
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 from pypog import geometry
 from pypog import geometry
+from pypog import pathfinding
+
+
+ORIGIN_HPOSITION_LEFT = 0
+ORIGIN_HPOSITION_MIDDLE = 1
+ORIGIN_HPOSITION_RIGHT = 2
+ORIGIN_VPOSITION_TOP = 10
+ORIGIN_VPOSITION_MIDDLE = 11
+ORIGIN_VPOSITION_BOTTOM = 12
+
+
+class Grid(object):
+    def __init__(self, cell_shape, width, height, roof=None):
+        self._cell_shape = None
+        self.cell_shape = cell_shape
+
+        self._width = 0
+        self.width = width
+        self._height = 0
+        self.height = height
+
+        self._roof = roof
+
+        self._cells = {}
+        self._build()
+
+    def _build(self):
+        for x in range(self.width):
+            for y in range(self.height):
+                cell = Cell(self.cell_shape, x, y)
+                self._cells[(x, y)] = cell
+
+    # properties
+    @property
+    def cell_shape(self):
+        return self._cell_shape
+
+    @cell_shape.setter
+    def cell_shape(self, cell_shape):
+        if not cell_shape in geometry.CELL_SHAPES:
+            raise ValueError("'cell_shape' has to be a value from CELL_SHAPES")
+        self._cell_shape = cell_shape
+
+    @property
+    def width(self):
+        return self._width
+
+    @width.setter
+    def width(self, width):
+        if not isinstance(width, int) or not width > 0:
+            raise ValueError("'width' has to be a strictly positive integer")
+        self._width = width
+
+    @property
+    def height(self):
+        return self._height
+
+    @height.setter
+    def height(self, height):
+        if not isinstance(height, int) or not height > 0:
+            raise ValueError("'width' has to be a strictly positive integer")
+        self._height = height
+
+    @property
+    def roof(self):
+        return self._roof
+
+    def cell(self, x, y):
+        return self._cells[(x, y)]
+
+    @property
+    def cells(self):
+        return self._cells
+
+
+    # geometric methods
+    def cases_number(self):
+        return self.height * self.width
+
+    def in_grid(self, x, y):
+        """return True if the coordinates are in the grid"""
+        return (x > 0 and x <= self._width and y > 0 and y <= self._height)
+
+    def line(self, x1, y1, x2, y2):
+        return geometry.line2d(self.cell_shape, x1, y1, x2, y2)
+
+    def line3d(self, x1, y1, z1, x2, y2, z2):
+        return geometry.line3d(self.cell_shape, x1, y1, z1, x2, y2, z2)
+
+    def zone(self, x, y, radius):
+        return geometry.zone(self.cell_shape, x, y, radius)
+
+    def triangle(self, xa, ya, xh, yh, iAngle):
+        return geometry.triangle(self.cell_shape, xa, ya, xh, yh, iAngle)
+
+    def triangle3d(self, xa, ya, za, xh, yh, zh, iAngle):
+        return geometry.triangle3d(self.cell_shape, xa, ya, za, xh, yh, zh, iAngle)
+
+    def rect(self, x1, y1, x2, y2):
+        return geometry.rectangle(x1, y1, x2, y2)
+
+    def hollow_rect(self, x1, y1, x2, y2):
+        return geometry.hollow_rectangle(x1, y1, x2, y2)
+
+
+    # pathfinding methods
+    def moving_cost(self, *args):
+        return 1
+
+    def path(self, x1, y1, x2, y2):
+        return pathfinding.path(self, (x1, y1), (x2, y2), self.moving_cost_function)
+
+
+class HexGrid(Grid):
+    def __init__(self, width, height):
+        Grid.__init__(self, geometry.FLAT_HEX, width, height)
+
+class SquareGrid(Grid):
+    def __init__(self, width, height):
+        Grid.__init__(self, geometry.SQUARE, width, height)
+
+
+
+class Cell(object):
+    def __init__(self, cell_shape, x, y, z=0):
+        self._cell_shape = cell_shape
+        self._x = x
+        self._y = y
+        self._z = z
+
+    @property
+    def x(self):
+        return self._x
+
+    @property
+    def y(self):
+        return self._y
+
+    @property
+    def z(self):
+        return self._z
+
+    @property
+    def coord(self):
+        return (self._x, self._y)
+
+    @property
+    def coord3d(self):
+        return (self._x, self._y, self._z)
+
+    def __repr__(self):
+        return "Cell {}".format(self.coord)
 
 
 
 
 class Piece(object):
 class Piece(object):
@@ -14,14 +166,14 @@ class Piece(object):
         self._height = 1
         self._height = 1
         self._zR = 0
         self._zR = 0
         self._cell_shape = None
         self._cell_shape = None
-        self._shape = [ (0,0) ]
-        
+        self._shape = [ (0, 0) ]
+
     # properties
     # properties
     @property
     @property
     def position(self):
     def position(self):
         """return the (x, y) position of the Piece"""
         """return the (x, y) position of the Piece"""
         return self._position
         return self._position
-        
+
     @position.setter
     @position.setter
     def position(self, position):
     def position(self, position):
         """update the (x, y) position of the Piece
         """update the (x, y) position of the Piece
@@ -33,7 +185,7 @@ class Piece(object):
         except ValueError:
         except ValueError:
             raise ValueError("'position' have to be an (x, y) tuple, with x and y integers")
             raise ValueError("'position' have to be an (x, y) tuple, with x and y integers")
         self._position = position
         self._position = position
-    
+
     @property
     @property
     def x(self):
     def x(self):
         """x coordinate of the Piece"""
         """x coordinate of the Piece"""
@@ -99,12 +251,12 @@ class Piece(object):
         """return the 'cell_shape' from GRID_GEOMETRIES for which the Piece is made for.
         """return the 'cell_shape' from GRID_GEOMETRIES for which the Piece is made for.
         Cell's shape is needed for pivot algorithm, and for graphical purposes"""
         Cell's shape is needed for pivot algorithm, and for graphical purposes"""
         return self._cell_shape
         return self._cell_shape
-    
+
     @cell_shape.setter
     @cell_shape.setter
     def cell_shape(self, cell_shape):
     def cell_shape(self, cell_shape):
         """set the 'cell_shape' of the piece (see cell_shape property for more informations)"""
         """set the 'cell_shape' of the piece (see cell_shape property for more informations)"""
         self._cell_shape = cell_shape
         self._cell_shape = cell_shape
-    
+
     @property
     @property
     def rotation(self):
     def rotation(self):
         """return the current rotation of the piece.
         """return the current rotation of the piece.
@@ -115,35 +267,34 @@ class Piece(object):
     def rotation(self, rotation):
     def rotation(self, rotation):
         """set the 'rotation' of the piece (see rotation property for more informations)"""
         """set the 'rotation' of the piece (see rotation property for more informations)"""
         if not isinstance(rotation, int):
         if not isinstance(rotation, int):
-            raise TypeError("'rotation' has to be an integer")        
-        self._rotation = rotation       
-    
+            raise TypeError("'rotation' has to be an integer")
+        self._rotation = rotation
+
     # methods
     # methods
     def occupation(self):
     def occupation(self):
         """return the list of the (x, y) coordinates currently occupied by the Piece"""
         """return the list of the (x, y) coordinates currently occupied by the Piece"""
         result = [ (xr + self.x, yr + self.y) for xr, yr in self._shape ]
         result = [ (xr + self.x, yr + self.y) for xr, yr in self._shape ]
         if self._rotation != 0:
         if self._rotation != 0:
-            result = geometry.pivot( self._cell_shape, self.position, result, self.rotation )
+            result = geometry.pivot(self._cell_shape, self.position, result, self.rotation)
         return result
         return result
 
 
-    def occupation3d(self, dz = 0):
+    def occupation3d(self, dz=0):
         """return the list of the (x, y, z) coordinates currently occupied by the Piece
         """return the list of the (x, y, z) coordinates currently occupied by the Piece
-        
+
         Because Pieces altitude zR is relative, the z coordinate returned is not an absolute altitude
         Because Pieces altitude zR is relative, the z coordinate returned is not an absolute altitude
         If you want an absolute altitude, use the 'dz' modifier to correct the result."""
         If you want an absolute altitude, use the 'dz' modifier to correct the result."""
         occupation = self.occupation()
         occupation = self.occupation()
         return [(x, y, z) for x, y in occupation for z in range(dz + self.zR, dz + self.zR + self.height)]
         return [(x, y, z) for x, y in occupation for z in range(dz + self.zR, dz + self.zR + self.height)]
 
 
-    def move_to(self, x, y, zR = None):
+    def move_to(self, x, y, zR=None):
         """move the piece to (x, y) position and is requested to zR relative altitude"""
         """move the piece to (x, y) position and is requested to zR relative altitude"""
         self.position = x, y
         self.position = x, y
         if zR != None:
         if zR != None:
             self.zR = zR
             self.zR = zR
-    
+
     def rotate(self, i):
     def rotate(self, i):
         """pivot the Piece i times (counterclockwise rotation, i can be negative)"""
         """pivot the Piece i times (counterclockwise rotation, i can be negative)"""
         new_rotation = self.rotation + i
         new_rotation = self.rotation + i
         self.rotation = new_rotation % self.cell_shape
         self.rotation = new_rotation % self.cell_shape
-        
-        
-        
+
+

+ 78 - 79
pypog/pencil.py → pypog/painting.py

@@ -1,43 +1,42 @@
 '''
 '''
-Created on 5 dec. 2016
     Pencil classes allow you to get an evolving selection of coordinates, according to the type of pencil you use.
     Pencil classes allow you to get an evolving selection of coordinates, according to the type of pencil you use.
-    
+
     Start it, set size (default: 1), update it as many times you want with new positions on the grid, then
     Start it, set size (default: 1), update it as many times you want with new positions on the grid, then
     get the list of selected coordinates, or the list of added / removed coorinates by the last update.
     get the list of selected coordinates, or the list of added / removed coorinates by the last update.
-    
+
     Connect those functions to your graphical grid, and let it do the job.
     Connect those functions to your graphical grid, and let it do the job.
-    
+
     Example of use:
     Example of use:
         On mouse left button down on a (x, y) cell: pencil.start(x, y)
         On mouse left button down on a (x, y) cell: pencil.start(x, y)
         On hover event on cells: pencil.update(), then display the result on your grid
         On hover event on cells: pencil.update(), then display the result on your grid
         On mouse left button up: Apply the modification on your grid, then delete your pencil object
         On mouse left button up: Apply the modification on your grid, then delete your pencil object
-        
-@author: olinox
+
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 
 
-from pypog import geometry, Grid
+from pypog import geometry, grid_objects
 
 
-class NotStartedException(Exception): 
+class NotStartedException(Exception):
     pass
     pass
 
 
-class AlreadyStartedException(Exception): 
+class AlreadyStartedException(Exception):
     pass
     pass
 
 
 
 
 class BasePencil(object):
 class BasePencil(object):
     """Base class of all pencils
     """Base class of all pencils
     This class does not  paint anything: override it!"""
     This class does not  paint anything: override it!"""
-    
+
     def __init__(self, grid):
     def __init__(self, grid):
-        
+
         # do we really need the grid ref? cell_shape could be enough?
         # do we really need the grid ref? cell_shape could be enough?
-        if not isinstance(grid, Grid.Grid):
+        if not isinstance(grid, grid_objects.Grid):
             raise TypeError("'grid' should be a Grid object (given: {})".format(grid))
             raise TypeError("'grid' should be a Grid object (given: {})".format(grid))
         self._grid = grid
         self._grid = grid
-        
+
         self._origin = None
         self._origin = None
         self._position = None
         self._position = None
-        
+
         self._size = 1
         self._size = 1
         self._selection = set()
         self._selection = set()
 
 
@@ -74,25 +73,25 @@ class BasePencil(object):
     @property
     @property
     def selection(self):
     def selection(self):
         """return the current list of coordinates selected by the pencil (read-only)"""
         """return the current list of coordinates selected by the pencil (read-only)"""
-        return list( self._selection )
-        
+        return list(self._selection)
+
     @property
     @property
     def added(self):
     def added(self):
         """return the list of coordinates added to the last selection by the last update (read-only)
         """return the list of coordinates added to the last selection by the last update (read-only)
-        
-        This property exists for performances reasons: you probably don't want to update your whole graphic scene if 
+
+        This property exists for performances reasons: you probably don't want to update your whole graphic scene if
         just one or two cells where added or removed from the selection!
         just one or two cells where added or removed from the selection!
         """
         """
-        return list( self._added )
+        return list(self._added)
 
 
     @property
     @property
     def removed(self):
     def removed(self):
         """return the list of coordinates removed from the last selection by the last update (read-only)
         """return the list of coordinates removed from the last selection by the last update (read-only)
-                
-        This property exists for performances reasons: you probably don't want to update your whole graphic scene if 
+
+        This property exists for performances reasons: you probably don't want to update your whole graphic scene if
         just one or two cells where added or removed from the selection!
         just one or two cells where added or removed from the selection!
         """
         """
-        return list( self._removed )
+        return list(self._removed)
 
 
     def _update(self):
     def _update(self):
         """this method update the selection, added and removed lists, according to the current size, position, origin
         """this method update the selection, added and removed lists, according to the current size, position, origin
@@ -117,26 +116,26 @@ class BasePencil(object):
             raise NotStartedException("Pencil has to be started before any update: use 'start' method")
             raise NotStartedException("Pencil has to be started before any update: use 'start' method")
         self._position = (x, y)
         self._position = (x, y)
         self._update()
         self._update()
-        
+
 class LinePencil(BasePencil):
 class LinePencil(BasePencil):
     """Paint a 2d line between origin and position"""
     """Paint a 2d line between origin and position"""
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
-        
+
     def _update(self):
     def _update(self):
         x0, y0 = self._origin
         x0, y0 = self._origin
         x, y = self._position
         x, y = self._position
-        
+
         # use a set because of performance (should we generalize the use of sets for coordinates lists?)
         # use a set because of performance (should we generalize the use of sets for coordinates lists?)
         result = set([])
         result = set([])
-        
-        line = set( geometry.line2d(self._grid.cell_shape, x0, y0, x, y) )
-        
+
+        line = set(geometry.line2d(self._grid.cell_shape, x0, y0, x, y))
+
         # apply size with geometry.zone
         # apply size with geometry.zone
-        if self._grid.size >= 1: 
+        if self._grid.size >= 1:
             for x, y in line:
             for x, y in line:
-                result |= set( geometry.zone(self._grid.cell_shape, x, y, self.size - 1) )
-        
+                result |= set(geometry.zone(self._grid.cell_shape, x, y, self.size - 1))
+
         self._added = result - self._selection
         self._added = result - self._selection
         self._removed = self._selection - result
         self._removed = self._selection - result
         self._selection = result
         self._selection = result
@@ -146,43 +145,43 @@ class FreePencil(BasePencil):
     """Free handed pencil"""
     """Free handed pencil"""
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
-        
+
     def _update(self):
     def _update(self):
         x, y = self.position
         x, y = self.position
-        zone_set = set( geometry.zone(self._grid.cell_shape, x, y, self.size) )
+        zone_set = set(geometry.zone(self._grid.cell_shape, x, y, self.size))
 
 
         self._added = zone_set - self._selection
         self._added = zone_set - self._selection
         # there can't be any removed coordinates with this pencil
         # there can't be any removed coordinates with this pencil
         self._selection = self._selection + zone_set
         self._selection = self._selection + zone_set
-        
-        
+
+
 class PaintPotPencil(BasePencil):
 class PaintPotPencil(BasePencil):
     """This particular pencil selects all cells of same nature from nearest to nearest
     """This particular pencil selects all cells of same nature from nearest to nearest
-    
+
     The 'same nature' is confirmed by passing a comparaison method to the pencil
     The 'same nature' is confirmed by passing a comparaison method to the pencil
     This method should take x1, y1, x2, y2 as args, and return a boolean: True for similar cells, False in other case
     This method should take x1, y1, x2, y2 as args, and return a boolean: True for similar cells, False in other case
-    
+
     WARNING: this pencil result is not modified by the update method, because the result is already defined when it starts
     WARNING: this pencil result is not modified by the update method, because the result is already defined when it starts
-    
+
     WARNING 2: take care of what you put in your comparing method, it could end with a infinite loop if you are not working on a finite grid!
     WARNING 2: take care of what you put in your comparing method, it could end with a infinite loop if you are not working on a finite grid!
-    
+
     example of use:
     example of use:
-        
+
         # your comparison function
         # your comparison function
         my_grid = HexGrid(30,30)
         my_grid = HexGrid(30,30)
-        
+
         def identical_cells_function(x1, y1, x2, y2):
         def identical_cells_function(x1, y1, x2, y2):
             if my_grid.cell(x1, y1).color == my_grid.cell(x2, y2).color:
             if my_grid.cell(x1, y1).color == my_grid.cell(x2, y2).color:
                 return True
                 return True
             return False
             return False
-            
+
         my_pencil = PaintPotPencil(my_grid)
         my_pencil = PaintPotPencil(my_grid)
         my_pencil.start(3, 3, identical_cells_function)
         my_pencil.start(3, 3, identical_cells_function)
-        
+
         print(my_pencil.selection)
         print(my_pencil.selection)
-    
+
     """
     """
-    
+
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
         self._comparing_method = (lambda x: False)
         self._comparing_method = (lambda x: False)
@@ -200,89 +199,89 @@ class PaintPotPencil(BasePencil):
         return self._selection
         return self._selection
 
 
     def _update(self):
     def _update(self):
-        x0, y0 = self._origin 
+        x0, y0 = self._origin
         current_selection = { (x0, y0) }
         current_selection = { (x0, y0) }
-        buffer = set( geometry.neighbours_of(self._grid._cell_shape, x0, y0) )
-        
+        buffer = set(geometry.neighbours(self._grid._cell_shape, x0, y0))
+
         while len(buffer) > 0:
         while len(buffer) > 0:
             x, y = buffer.pop()
             x, y = buffer.pop()
             if self._comparing_method_pointer(x0, y0, x, y):
             if self._comparing_method_pointer(x0, y0, x, y):
-                current_selection.add( (x, y) )
-                buffer |= ( set( geometry.neighbours_of(self._grid._cell_shape, x, y) ) - current_selection)
-                
+                current_selection.add((x, y))
+                buffer |= (set(geometry.neighbours(self._grid._cell_shape, x, y)) - current_selection)
+
         self._selection = current_selection
         self._selection = current_selection
-        
-        
+
+
 class RectanglePencil(BasePencil):
 class RectanglePencil(BasePencil):
-    """ RectanglePencil draw a plain rectangle with origin being the 
+    """ RectanglePencil draw a plain rectangle with origin being the
     top left corner, and position the bottom right corner"""
     top left corner, and position the bottom right corner"""
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
-        
+
     def _update(self):
     def _update(self):
         x1, y1 = self._origin
         x1, y1 = self._origin
         x2, y2 = self._position
         x2, y2 = self._position
-        
-        new_selection = set( geometry.rect(x1, y1, x2, y2) )
-        
+
+        new_selection = set(geometry.rectangle(x1, y1, x2, y2))
+
         self._added = new_selection - self._selection
         self._added = new_selection - self._selection
         self._removed = self._selection - new_selection
         self._removed = self._selection - new_selection
         self._selection = new_selection
         self._selection = new_selection
-        
+
 class HollowRectanglePencil(BasePencil):
 class HollowRectanglePencil(BasePencil):
-    """ HollowRectanglePencil draw an hollow rectangle with origin being the 
+    """ HollowRectanglePencil draw an hollow rectangle with origin being the
     top left corner, and position the bottom right corner"""
     top left corner, and position the bottom right corner"""
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
-        
+
     def _update(self):
     def _update(self):
         x1, y1 = self._origin
         x1, y1 = self._origin
         x2, y2 = self._position
         x2, y2 = self._position
-        
-        new_selection = set( geometry.hollow_rect(x1, y1, x2, y2) )
-        
+
+        new_selection = set(geometry.hollow_rectangle(x1, y1, x2, y2))
+
         self._added = new_selection - self._selection
         self._added = new_selection - self._selection
         self._removed = self._selection - new_selection
         self._removed = self._selection - new_selection
         self._selection = new_selection
         self._selection = new_selection
 
 
 class BoundaryPencil(BasePencil):
 class BoundaryPencil(BasePencil):
-    """ BoundaryPencil is a particular pencil which select all the cells 
+    """ BoundaryPencil is a particular pencil which select all the cells
     on the left of a straight line which could be oriented from 0, 45, 90, 135, 180, 225, 270, 315 degrees
     on the left of a straight line which could be oriented from 0, 45, 90, 135, 180, 225, 270, 315 degrees
     Orientation  of the boudary depends on position and origin."""
     Orientation  of the boudary depends on position and origin."""
-    
+
     def __init__(self, *args):
     def __init__(self, *args):
         BasePencil.__init__(self, *args)
         BasePencil.__init__(self, *args)
 
 
     def _update(self):
     def _update(self):
-        
+
         if self._position == self._origin:
         if self._position == self._origin:
             self._removed = self._selection.copy()
             self._removed = self._selection.copy()
             self._selection = set()
             self._selection = set()
             self._added = set()
             self._added = set()
             return
             return
-        
+
         x0, y0 = self._origin
         x0, y0 = self._origin
         x, y = self._position
         x, y = self._position
         dx, dy = x - x0, y - y0
         dx, dy = x - x0, y - y0
 
 
-        if dx == 0:   # vertical boudary
+        if dx == 0:  # vertical boudary
             selection = {(x, y) for x, y in self._grid.cells.keys() if (x - x0) * dy >= 0}
             selection = {(x, y) for x, y in self._grid.cells.keys() if (x - x0) * dy >= 0}
 
 
         elif dy == 0:  # horizontal boundary
         elif dy == 0:  # horizontal boundary
-            selection = {(x, y) for x, y in self._grid.cells.keys() if (y - y0) * (-dx) >= 0} 
-            
+            selection = {(x, y) for x, y in self._grid.cells.keys() if (y - y0) * (-dx) >= 0}
+
         elif dx > 0 and dy < 0:  # normal vector to the top left
         elif dx > 0 and dy < 0:  # normal vector to the top left
-            selection = {(x , y) for x, y in self._grid.cells.keys() if (x - x0) + (y - y0) <= 0} 
-            
-        elif dx > 0 and dy > 0: # normal vector to the top right
+            selection = {(x , y) for x, y in self._grid.cells.keys() if (x - x0) + (y - y0) <= 0}
+
+        elif dx > 0 and dy > 0:  # normal vector to the top right
             selection = {(x , y) for x, y in self._grid.cells.keys() if (x - x0) - (y - y0) >= 0}
             selection = {(x , y) for x, y in self._grid.cells.keys() if (x - x0) - (y - y0) >= 0}
-            
+
         elif dx < 0 and dy < 0:  # normal vector to bottom left
         elif dx < 0 and dy < 0:  # normal vector to bottom left
-            selection = {(x , y) for x, y in self._grid.cells.keys() if - (x - x0) + (y - y0) >= 0}
-            
+            selection = {(x , y) for x, y in self._grid.cells.keys() if -(x - x0) + (y - y0) >= 0}
+
         elif dx < 0 and dy > 0:  # normal vector to bottom right
         elif dx < 0 and dy > 0:  # normal vector to bottom right
-            selection = {(x , y) for x, y in self._grid.cells.keys() if - (x - x0) - (y - y0) <= 0}
-        
+            selection = {(x , y) for x, y in self._grid.cells.keys() if -(x - x0) - (y - y0) <= 0}
+
         self._added = selection - self._selection
         self._added = selection - self._selection
         self._removed = self._selection - selection
         self._removed = self._selection - selection
         self._selection = selection
         self._selection = selection

+ 33 - 34
pypog/pathfinder.py → pypog/pathfinding.py

@@ -1,35 +1,34 @@
 '''
 '''
-Created on 17 déc. 2015
    Implement the A* algorithm
    Implement the A* algorithm
-   
+
    Use the path function like that:
    Use the path function like that:
-   
+
        path(my_grid, (xs, ys), (xt, yt), my_moving_cost_function)
        path(my_grid, (xs, ys), (xt, yt), my_moving_cost_function)
        >> [(xs, ys), (x1, y1), (x2, y2), ...(xt, yt)]
        >> [(xs, ys), (x1, y1), (x2, y2), ...(xt, yt)]
-       
+
        where:
        where:
         - my_grid is a Grid, HexGrid, or SquareGrid object
         - my_grid is a Grid, HexGrid, or SquareGrid object
         - (xs, ys) is the starting cell
         - (xs, ys) is the starting cell
         - (xt, yt) is the targeted cell
         - (xt, yt) is the targeted cell
         - my_moving_cost_function is a pointer to your custom function. This function should be like:
         - my_moving_cost_function is a pointer to your custom function. This function should be like:
-        
+
         def my_moving_cost_function((x0, y0), (x1, y1)):
         def my_moving_cost_function((x0, y0), (x1, y1)):
             ...
             ...
             return cost
             return cost
-            
-        this function should return an INTEGER which represent the cost of a move from (x0, y0) to (x1, y1), 
+
+        this function should return an INTEGER which represent the cost of a move from (x0, y0) to (x1, y1),
         where (x0, y0) and (x1, y1) are adjacent cells
         where (x0, y0) and (x1, y1) are adjacent cells
-        
+
         If cost is negative, move is impossible.
         If cost is negative, move is impossible.
-        If move is strictly positive, it represents the difficulty to move from 0 to 1: 
-        the returned path will be the easiest from (xs, ys) to (xt, yt) 
-   
+        If move is strictly positive, it represents the difficulty to move from 0 to 1:
+        the returned path will be the easiest from (xs, ys) to (xt, yt)
+
     3D paths:
     3D paths:
-        The path method takes account of the differents altitudes of the cells, but it is not designed to 
-        work for a flying mover. 
+        The path method takes account of the differents altitudes of the cells, but it is not designed to
+        work for a flying mover.
         More clearly: the path will be on the ground: walking, climbing, but no flying for instance.
         More clearly: the path will be on the ground: walking, climbing, but no flying for instance.
 
 
-@author: olivier.massot
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 from pypog import geometry
 from pypog import geometry
 
 
@@ -43,7 +42,7 @@ def distance(coord1, coord2):
 
 
 def square_distance(coord1, coord2):
 def square_distance(coord1, coord2):
     """distance between 1 and 2 (quicker than distance)"""
     """distance between 1 and 2 (quicker than distance)"""
-    return (coord1[0] - coord2[0])**2 + (coord1[1] - coord2[1])**2
+    return (coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2
 
 
 class Path(object):
 class Path(object):
     def __init__(self):
     def __init__(self):
@@ -54,44 +53,44 @@ class Path(object):
 
 
 class Node():
 class Node():
     def __init__(self, coord):
     def __init__(self, coord):
-        self.parent = None    # coords of the previous node
+        self.parent = None  # coords of the previous node
         self.coord = coord
         self.coord = coord
         self.k_dep = 1
         self.k_dep = 1
         self.g_cost = 0
         self.g_cost = 0
         self.h_cost = 0
         self.h_cost = 0
         self.cost = 0
         self.cost = 0
- 
+
     def create(self, parent, target, k_dep):
     def create(self, parent, target, k_dep):
         self.parent = parent
         self.parent = parent
         self.k_dep = k_dep
         self.k_dep = k_dep
         self.h_cost = self.distance(self.coord, target)
         self.h_cost = self.distance(self.coord, target)
         self.g_cost = self.parent.g_cost + self.k_dep
         self.g_cost = self.parent.g_cost + self.k_dep
-        self.cout =  self.g_cost + self.h_cost
-    
+        self.cout = self.g_cost + self.h_cost
+
     def parent(self):
     def parent(self):
         return self.parent
         return self.parent
-    
+
     def distance(self, coord1, coord2):
     def distance(self, coord1, coord2):
         """distance (en cases) entre deux coordonnees"""
         """distance (en cases) entre deux coordonnees"""
         x1, y1 = coord1
         x1, y1 = coord1
         x2, y2 = coord2
         x2, y2 = coord2
         return geometry.distance_off(x1, y1, x2, y2)
         return geometry.distance_off(x1, y1, x2, y2)
-    
+
 def _default_moving_cost_function(from_coord, to_coord):
 def _default_moving_cost_function(from_coord, to_coord):
     return 1
     return 1
 
 
-def path(grid, origin, target, moving_cost_function = None):
+def path(grid, origin, target, moving_cost_function=None):
     """return the shorter path from origin to target on the Grid object
     """return the shorter path from origin to target on the Grid object
     the path is estimated following:
     the path is estimated following:
     - geometry of the grid
     - geometry of the grid
     - altitudes of the cells
     - altitudes of the cells
-    - cost of the move returned by the 'moving_cost_function' 
-    
+    - cost of the move returned by the 'moving_cost_function'
+
     origin and target should be Cell objects
     origin and target should be Cell objects
     """
     """
     if moving_cost_function == None:
     if moving_cost_function == None:
         moving_cost_function = _default_moving_cost_function
         moving_cost_function = _default_moving_cost_function
-    
+
     nodes = {}  # coord: node
     nodes = {}  # coord: node
 
 
     nO = Node(origin)
     nO = Node(origin)
@@ -101,20 +100,20 @@ def path(grid, origin, target, moving_cost_function = None):
 #     kept = [nO]
 #     kept = [nO]
     path = []
     path = []
     position = nO
     position = nO
-    
+
     while position.coord != target:
     while position.coord != target:
 
 
         # we maybe could avoid the re-computing by storing the neighbours coordinates?
         # we maybe could avoid the re-computing by storing the neighbours coordinates?
         neighbours = grid.cell(position.coord).neighbours
         neighbours = grid.cell(position.coord).neighbours
-        
+
         for coord in [coord for coord in neighbours if not coord in nodes.keys()]:
         for coord in [coord for coord in neighbours if not coord in nodes.keys()]:
 
 
                 cost = moving_cost_function(position.coord, coord)
                 cost = moving_cost_function(position.coord, coord)
                 if cost < 0:
                 if cost < 0:
                     continue
                     continue
-                
+
                 node = Node(coord)
                 node = Node(coord)
-                
+
                 node.create(position, target, cost)
                 node.create(position, target, cost)
 
 
                 try:
                 try:
@@ -123,21 +122,21 @@ def path(grid, origin, target, moving_cost_function = None):
                         continue
                         continue
                 except KeyError:
                 except KeyError:
                     pass
                     pass
-                
+
                 nodes[coord] = node
                 nodes[coord] = node
 
 
         if len(nodes) == 0:
         if len(nodes) == 0:
             print("No path found")
             print("No path found")
             return []
             return []
-        
+
         best = min(nodes.values(), key=lambda x: x.cost)
         best = min(nodes.values(), key=lambda x: x.cost)
         del nodes[best.coord]
         del nodes[best.coord]
         position = best
         position = best
-    
+
     else:
     else:
         # build the result
         # build the result
         while position.coord != origin:
         while position.coord != origin:
             path.insert(0, (position.coord, position.k_dep))
             path.insert(0, (position.coord, position.k_dep))
             position = position.parent
             position = position.parent
-    
-    return path   
+
+    return path

+ 0 - 0
tests/geometry/__init__.py


+ 0 - 93
tests/geometry/test_line.py

@@ -1,93 +0,0 @@
-'''
-Created on 20 nov. 2016
-
-@author: olinox
-'''
-import unittest
-
-from pypog import geometry
-
-
-class Test(unittest.TestCase):
-    """test line algorithms"""
-
-    def test_line_errors(self):
-        self.assertRaises( TypeError, geometry.line2d, geometry.HEX, "a", 1, 1, 1)
-        self.assertRaises( TypeError, geometry.line2d, geometry.HEX, 1, "a", 1, 1)
-        self.assertRaises( TypeError, geometry.line2d, geometry.HEX, 1, 1, "a", 1)
-        self.assertRaises( TypeError, geometry.line2d, geometry.HEX, 1, 1, 1, "a")
-        self.assertRaises( ValueError, geometry.line2d, 0, 1, 1, 1, 1)
-
-        self.assertRaises( TypeError, geometry.line3d, geometry.HEX, 1, 1, "a", 1, 1, 1)
-        self.assertRaises( TypeError, geometry.line3d, geometry.HEX, 1, 1, 1, 1, 1, "a")
-        
-    def test_line(self):
-        """ 2d line on square or hexagonal grid """
-        cell_shape = geometry.HEX
-        
-        attended = {
-                    geometry.HEX:    {
-                                      (1,1,1,1): [(1,1)], 
-                                      (0,0,1,1): [(0,0), (0,1), (1,1)], 
-                                      (1,1,0,0): [(1,1), (0,1), (0,0)], 
-                                      (0,0,7,3): [(0,0), (1,0), (2,1), (3,1), (4,2), (5,2), (6,3), (7,3)], 
-                                      (7,3,0,0): [(7,3), (6,3), (5,2), (4,2), (3,1), (2,1), (1,0), (0,0)], 
-                                      (4,3,0,3): [(4,3), (3,2), (2,3), (1,2), (0,3)], 
-                                      (0,3,4,3): [(0,3), (1,2), (2,3), (3,2), (4,3)], 
-                                      (3,0,3,3): [(3,0), (3,1), (3,2), (3,3)], 
-                                      (3,3,3,0): [(3,3), (3,2), (3,1), (3,0)]
-                                     }, 
-                    
-                    geometry.SQUARE: {
-                                      (1,1,1,1): [(1,1)], 
-                                      (0,0,0,1): [(0,0), (0,1)], 
-                                      (0,1,0,0): [(0,1), (0,0)], 
-                                      (0,0,1,1): [(0,0), (1,1)], 
-                                      (1,1,0,0): [(1,1), (0,0)], 
-                                      (0,0,7,3): [(0,0), (1,0), (2,1), (3,1), (4,2), (5,2), (6,3), (7,3)], 
-                                      (7,3,0,0): [(7,3), (6,3), (5,2), (4,2), (3,1), (2,1), (1,0), (0,0)], 
-                                      (4,3,0,3): [(4,3), (3,3), (2,3), (1,3), (0,3)], 
-                                      (0,3,4,3): [(0,3), (1,3), (2,3), (3,3), (4,3)], 
-                                      (3,0,3,3): [(3,0), (3,1), (3,2), (3,3)],                      
-                                      (3,3,3,0): [(3,3), (3,2), (3,1), (3,0)]                    
-                                     }
-                   }
-        
-        for cell_shape, tests in attended.items():
-            for args, result in tests.items():
-                line = geometry.line2d(cell_shape, *args)
-                self.assertEqual(line, result)
-        
-    
-    def test_line_3d(self):
-        """ 3d line on hexagonal and square grid """
-        cell_shape = geometry.HEX
-        
-        attended = {
-                    geometry.HEX:    {
-                                      (1,1,1,1,1,1) : [(1,1,1)], 
-                                      (1,1,0,1,1,1) : [(1,1,0), (1,1,1)], 
-                                      (0,0,0,1,1,1) : [(0,0,0), (0,1,0), (1,1,1)], 
-                                      (0,0,0,7,3,7) : [(0,0,0), (1,0,1), (2,1,2), (3,1,3), (4,2,4), (5,2,5), (6,3,6), (7,3,7)], 
-                                      (4,3,10,0,3,3): [(4,3,10), (3,2,9), (3,2,8), (2,3,7), (2,3,6), (1,2,5), (1,2,4), (0,3,3)], 
-                                      (3,0,0,3,3,0) : [(3,0,0), (3,1,0), (3,2,0), (3,3,0)]
-                                     }, 
-                    
-                    geometry.SQUARE: {
-                                      (1,1,1,1,1,1) : [(1,1,1)], 
-                                      (1,1,0,1,1,1) : [(1,1,0), (1,1,1)], 
-                                      (0,0,0,1,1,1) : [(0,0,0), (1,1,1)], 
-                                      (0,0,0,7,3,7) : [(0,0,0), (1,0,1), (2,1,2), (3,1,3), (4,2,4), (5,2,5), (6,3,6), (7,3,7)], 
-                                      (4,3,10,0,3,3): [(4,3,10), (3,3,9), (3,3,8), (2,3,7), (2,3,6), (1,3,5), (1,3,4), (0,3,3)], 
-                                      (3,0,0,3,3,0) : [(3,0,0), (3,1,0), (3,2,0), (3,3,0)]
-                                     }
-                   }
-        
-        for cell_shape, tests in attended.items():
-            for args, result in tests.items():
-                line = geometry.line3d(cell_shape, *args)
-                self.assertEqual(line, result)
-        
-
-if __name__ == "__main__":
-    unittest.main()

+ 0 - 29
tests/geometry/test_neighbours.py

@@ -1,29 +0,0 @@
-'''
-Created on 25 nov. 2016
-
-@author: olinox
-'''
-import unittest
-
-from pypog import geometry
-
-
-class Test(unittest.TestCase):
-
-
-    def test_neighbours_of(self):
-        for coord in ( (0,0), (-10,-10), (10,10) ):
-            x, y = coord
-            self.assertEqual( geometry.neighbours_of(geometry.HEX, x, y), geometry.hex_neighbours_of(x, y) )
-            self.assertEqual( geometry.neighbours_of(geometry.SQUARE, x, y), geometry.squ_neighbours_of(x, y) )
-
-    def test_hex_neighbours_of(self):
-        self.assertCountEqual( geometry.hex_neighbours_of(3,3), [(3,2), (4,3), (4,4), (3,4), (2,4), (2,3)] )
-        self.assertCountEqual( geometry.hex_neighbours_of(4,4), [(4,3), (5,3), (5,4), (4,5), (3,4), (3,3)] )
-
-    def test_squ_neighbours_of(self):
-        self.assertCountEqual( geometry.squ_neighbours_of(3,3), [(2,3), (2,2), (3,2), (4,2), (4,3), (4,4), (3,4), (2,4)] )
-        
-
-if __name__ == "__main__":
-    unittest.main()

+ 0 - 59
tests/geometry/test_pivot.py

@@ -1,59 +0,0 @@
-'''
-Created on 6 dec. 2016
-
-@author: olinox
-'''
-import unittest
-from pypog import geometry
-
-class Test(unittest.TestCase):
-
-    def test_pivot_errors(self):
-        # invalid cell shape
-        self.assertRaises(ValueError, geometry.pivot, 0, (0,0), [(0,0)], 1)
-        
-        self.assertRaises(TypeError, geometry.pivot, 0,  "a"    , [(0,0)], 1)
-        self.assertRaises(ValueError, geometry.pivot, 0, ("a",0), [(0,0)], 1)
-        
-        self.assertRaises(TypeError, geometry.pivot, 0, (0,0), 0, 1)
-        self.assertRaises(ValueError, geometry.pivot, 0, (0,0), ["a", (0,0)], 1)
-        self.assertRaises(ValueError, geometry.pivot, 0, (0,0), [("a",0), (0,0)], 1)
-
-        self.assertRaises(TypeError, geometry.pivot, 0, (0,0), 1, "a")
-
-    def test_hex_pivot(self):
-        """ pivot on hexagonal grid """
-        
-        attended = [
-                    [(5, 5), (4, 5), (6, 6)], 
-                    [(5, 6), (4, 7), (6, 6)],
-                    [(6, 7), (6, 8), (6, 6)],
-                    [(7, 6), (8, 7), (6, 6)],
-                    [(7, 5), (8, 5), (6, 6)],
-                    [(6, 5), (6, 4), (6, 6)],
-                    [(5, 5), (4, 5), (6, 6)]
-                   ]
-        
-        
-        for i in range( len(attended) ):
-            self.assertCountEqual(geometry.pivot( geometry.HEX, (6,6), [(6,6)], i), [(6,6)])
-            result = geometry.pivot(geometry.HEX, (6,6), [(5,5), (4,5), (6,6)], i)
-            self.assertCountEqual(result, attended[i])
-
-    def test_squ_pivot(self):
-        """ pivot on square grid """
-        attended = [
-                    [(6, 6), (6, 5), (5, 5), (5, 6)],
-                    [(6, 6), (5, 6), (5, 7), (6, 7)],
-                    [(6, 6), (6, 7), (7, 7), (7, 6)],
-                    [(6, 6), (7, 6), (7, 5), (6, 5)],
-                    [(6, 6), (6, 5), (5, 5), (5, 6)]
-                   ]
-
-        for i in range( len(attended) ):
-            self.assertCountEqual(geometry.pivot( geometry.SQUARE, (6,6), [(6,6)], i), [(6,6)])
-            result = geometry.pivot(geometry.SQUARE, (6,6), [(6,6), (6,5), (5,5), (5,6)], i)
-            self.assertCountEqual(result, attended[i])
-     
-if __name__ == "__main__":
-    unittest.main()

+ 0 - 42
tests/geometry/test_rect.py

@@ -1,42 +0,0 @@
-'''
-Created on 11 dec. 2016
-
-@author: olinox
-'''
-import unittest
-
-from pypog import geometry
-
-
-class Test(unittest.TestCase):
-
-    def test_rect_errors(self):
-        for method in (geometry.rect, geometry.hollow_rect):
-            self.assertRaises( TypeError, method, "a", 1, 1, 1)
-            self.assertRaises( TypeError, method, 1, "a", 1, 1)
-            self.assertRaises( TypeError, method, 1, 1, "a", 1)
-            self.assertRaises( TypeError, method, 1, 1, 1, "a")
-
-    def test_rect(self):
-        
-        self.assertEquals(geometry.rect(0,0,0,0), [(0,0)])
-        self.assertCountEqual(geometry.rect(0,0,1,1), [(0,0), (0,1), (1,1), (1,0)])
-        self.assertCountEqual(geometry.rect(1,1,0,0), [(0,0), (0,1), (1,1), (1,0)])
-        self.assertCountEqual(geometry.rect(4,3,7,5), [(4, 3), (4, 4), (4, 5), (5, 5), (6, 5), (7, 5), (7, 4), (7, 3), (6, 3), (5, 3), (6, 4), (5, 4)])
-        self.assertCountEqual(geometry.rect(3,3,9,9), [(3, 3), (9, 9), (9, 8), (9, 7), (9, 5), (9, 6), (9, 4), (9, 3), (8, 4), (7, 3), (6, 4), (4, 4), 
-                                                       (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), (4, 5), 
-                                                       (5, 4), (6, 5), (7, 4), (8, 5), (4, 6), (5, 5), (6, 6), (7, 5), (8, 6), (4, 7), (5, 6), (6, 7), 
-                                                       (7, 6), (8, 7), (4, 8), (5, 7), (6, 8), (7, 7), (8, 8), (7, 8), (5, 8), (8, 3), (6, 3), (4, 3), 
-                                                       (5, 3)])
-
-        self.assertEquals(geometry.hollow_rect(0,0,0,0), [(0,0)])
-        self.assertCountEqual(geometry.hollow_rect(0,0,1,1), [(0,0), (0,1), (1,1), (1,0)])
-        self.assertCountEqual(geometry.hollow_rect(1,1,0,0), [(0,0), (0,1), (1,1), (1,0)])
-        self.assertCountEqual(geometry.hollow_rect(4,3,7,5), [(4, 3), (4, 4), (4, 5), (5, 5), (6, 5), (7, 5), (7, 4), (7, 3), (6, 3), (5, 3)])
-        self.assertCountEqual(geometry.hollow_rect(3,3,9,9), [(3, 3), (9, 9), (9, 8), (9, 7), (9, 5), (9, 6), (9, 4), (9, 3), (7, 3), (3, 4), 
-                                                              (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), 
-                                                              (8, 3), (6, 3), (4, 3), (5, 3)])
-
-
-if __name__ == "__main__":
-    unittest.main()

+ 0 - 157
tests/geometry/test_triangle.py

@@ -1,157 +0,0 @@
-'''
-Created on 22 nov. 2016
-
-@author: olinox
-'''
-import unittest
-
-from pypog import geometry
-
-
-class Test(unittest.TestCase):
-    """test triangle algorithms"""
-
-    def test_triangle_errors(self):
-        
-        for cell_shape in (geometry.HEX, geometry.SQUARE):
-            self.assertRaises( TypeError, geometry.triangle, cell_shape, "a", 1, 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle, cell_shape, 1, "a", 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle, cell_shape, 1, 1, "a", 1, 1)
-            self.assertRaises( TypeError, geometry.triangle, cell_shape, 1, 1, 1, "a", 1)
-            self.assertRaises( ValueError, geometry.triangle, cell_shape, 1, 1, 1, 1, -1)
-    
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, "a", 1, 1, 1, 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, 1, "a", 1, 1, 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, 1, 1, "a", 1, 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, "a", 1, 1, 1)
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, "a", 1, 1)
-            self.assertRaises( TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, 1, "a", 1)
-            self.assertRaises( ValueError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, 1, 1, -1)
-            
-        self.assertRaises( ValueError, geometry.triangle, 0, 1, 1, 1, 1, 1)
-        self.assertRaises( ValueError, geometry.triangle3d, 0, 1, 1, 1, 1, 1, 1, 1)
-
-    def test_sq_triangle(self):
-        """test triangle algorithms on square grid"""
-        cell_shape = geometry.SQUARE
-        
-        for i in geometry.ANGLES:
-            self.assertCountEqual(geometry.triangle(cell_shape, 0, 0, 0, 0, i), [(0,0)])
-
-        # TODO: check and validate
-#         # left to right
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # top to bottom
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # right to left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # bottom to top
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # top left to bottom right
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # bottom right to top left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # top right to bottom left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # bottom right to top left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-
-        
-
-    def test_hex_triangle(self):
-        """test triangle algorithms on hexagonal grid"""
-        cell_shape = geometry.HEX
-        for i in geometry.ANGLES:
-            self.assertCountEqual(geometry.triangle(cell_shape, 0, 0, 0, 0, i), [(0,0)])
-
-        # left to right
-        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [(3, 3), (3, 4), (3, 3), (4, 5), (4, 4), (4, 3), (4, 2), (4, 1), (4, 1), (3, 1), (3, 2), (2, 3)])
-        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [(3, 3), (4, 4), (4, 3), (4, 2), (4, 2), (3, 2), (2, 3)])
-        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [(3, 3), (4, 4), (4, 3), (4, 2), (4, 2), (3, 2), (2, 3)])
-        
-        # TODO: check and validate
-        
-#         # top to bottom
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-        # right to left
-        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 1), [(3, 2), (3, 1), (3, 2), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 5), (3, 4), (3, 3), (4, 3)])
-        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 2), [(3, 2), (2, 2), (2, 3), (2, 4), (2, 4), (3, 3), (4, 3)])
-        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 3), [(3, 2), (2, 2), (2, 3), (2, 4), (2, 4), (3, 3), (4, 3)])
-         
-#         # bottom to top
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # top left to bottom right
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # bottom right to top left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # top right to bottom left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-#         
-#         # bottom right to top left
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
-#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
-
-        
-    
-    def test_sq_triangle_3d(self):
-        """test triangle3d algorithms on square grid"""
-        cell_shape = geometry.SQUARE
-        #TODO: complete
-     
-    def test_hex_triangle_3d(self):
-        """test triangle3d algorithms on hexagonal grid"""
-        cell_shape = geometry.HEX
-        #TODO: complete
-
-    def test_errors(self):
-        
-        for cell_shape in (geometry.HEX, geometry.SQUARE):
-            self.assertRaises(ValueError, geometry.triangle, cell_shape, 0, 0, 0, 0, 0)
-            self.assertRaises(TypeError, geometry.triangle, cell_shape, "a", 0, 0, 0, 1)
-            self.assertRaises(TypeError, geometry.triangle, cell_shape, 0, "a", 0, 0, 1)
-            self.assertRaises(TypeError, geometry.triangle, cell_shape, 0, 0, "a", 0, 1)
-            self.assertRaises(TypeError, geometry.triangle, cell_shape, 0, 0, 0, "a", 1)
-            self.assertRaises(ValueError, geometry.triangle, cell_shape, 0, 0, 0, 0, "a")
-    
-
-if __name__ == "__main__":
-    #import sys;sys.argv = ['', 'Test.test_sq_triangle']
-    unittest.main()

+ 0 - 44
tests/geometry/test_zone.py

@@ -1,44 +0,0 @@
-'''
-Created on 20 nov. 2016
-
-@author: olinox
-'''
-import unittest
-
-from pypog import geometry
-
-
-
-class Test(unittest.TestCase):
-    """ test the zone algorithm """
-
-
-    def test_hex_zone(self):
-        """ test the zone algo for hexagonal grid """
-        cell_shape = geometry.HEX
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 0 ), [(3,3)])
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 1 ), [(3, 2), (2, 3), (3, 3), (4, 3), (4, 4), (3, 4), (2, 4)])
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 2 ), [(3, 2), (1, 3), (5, 4), (4, 5), (1, 4), (2, 3), (4, 2), \
-                                                            (2, 5), (5, 3), (1, 2), (3, 5), (3, 3), (4, 4), (3, 1), \
-                                                            (4, 3), (2, 2), (3, 4), (2, 4), (5, 2)] )
-
-    def test_squ_zone(self):
-        """ test the zone algo for square grid """
-        cell_shape = geometry.SQUARE
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 0 ), [(3,3)])
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 1 ), [(3, 2), (3, 3), (4, 4), (2, 3), (4, 3), (2, 2), (4, 2), (3, 4), (2, 4)])
-        self.assertCountEqual( geometry.zone( cell_shape, 3, 3, 2 ), [(2, 4), (3, 2), (5, 4), (1, 3), (4, 5), (2, 1), (1, 4), (2, 3), (4, 2), \
-                                                                    (5, 1), (2, 5), (3, 5), (5, 3), (1, 2), (3, 3), (5, 5), (4, 4), (3, 1), \
-                                                                    (1, 5), (4, 3), (2, 2), (4, 1), (5, 2), (3, 4), (1, 1)])
-
-    def test_errors(self):
-        """test the errors due to bad parameters"""
-        self.assertRaises( TypeError, geometry.zone, 5, 0, 0, "a")
-        self.assertRaises( TypeError, geometry.zone, 5, "a", 0, 1)
-        self.assertRaises( TypeError, geometry.zone, 5, 0, "a", 1)
-        self.assertRaises( ValueError, geometry.zone, 5, 0, 0, -1)
-        self.assertRaises( ValueError, geometry.zone, -1, 0, 0, 1)
-        self.assertRaises( ValueError, geometry.zone, "a", 0, 0, 1)
-
-if __name__ == "__main__":
-    unittest.main()

+ 335 - 0
tests/test_geometry.py

@@ -0,0 +1,335 @@
+'''
+
+    ** By Cro-Ki l@b, 2017 **
+'''
+import unittest
+
+from pypog import geometry
+
+
+class Test(unittest.TestCase):
+
+    def test_line_errors(self):
+        self.assertRaises(TypeError, geometry.line2d, geometry.FLAT_HEX, "a", 1, 1, 1)
+        self.assertRaises(TypeError, geometry.line2d, geometry.FLAT_HEX, 1, "a", 1, 1)
+        self.assertRaises(TypeError, geometry.line2d, geometry.FLAT_HEX, 1, 1, "a", 1)
+        self.assertRaises(TypeError, geometry.line2d, geometry.FLAT_HEX, 1, 1, 1, "a")
+        self.assertRaises(ValueError, geometry.line2d, 0, 1, 1, 1, 1)
+
+        self.assertRaises(TypeError, geometry.line3d, geometry.FLAT_HEX, 1, 1, "a", 1, 1, 1)
+        self.assertRaises(TypeError, geometry.line3d, geometry.FLAT_HEX, 1, 1, 1, 1, 1, "a")
+
+    def test_line2d(self):
+        """ 2d line on square or hexagonal grid """
+        cell_shape = geometry.FLAT_HEX
+
+        attended = {
+                    geometry.FLAT_HEX:    {
+                                      (1, 1, 1, 1): [(1, 1)],
+                                      (0, 0, 1, 1): [(0, 0), (0, 1), (1, 1)],
+                                      (1, 1, 0, 0): [(1, 1), (0, 1), (0, 0)],
+                                      (0, 0, 7, 3): [(0, 0), (1, 0), (2, 1), (3, 1), (4, 2), (5, 2), (6, 3), (7, 3)],
+                                      (7, 3, 0, 0): [(7, 3), (6, 3), (5, 2), (4, 2), (3, 1), (2, 1), (1, 0), (0, 0)],
+                                      (4, 3, 0, 3): [(4, 3), (3, 2), (2, 3), (1, 2), (0, 3)],
+                                      (0, 3, 4, 3): [(0, 3), (1, 2), (2, 3), (3, 2), (4, 3)],
+                                      (3, 0, 3, 3): [(3, 0), (3, 1), (3, 2), (3, 3)],
+                                      (3, 3, 3, 0): [(3, 3), (3, 2), (3, 1), (3, 0)]
+                                     },
+
+                    geometry.SQUARE: {
+                                      (1, 1, 1, 1): [(1, 1)],
+                                      (0, 0, 0, 1): [(0, 0), (0, 1)],
+                                      (0, 1, 0, 0): [(0, 1), (0, 0)],
+                                      (0, 0, 1, 1): [(0, 0), (1, 1)],
+                                      (1, 1, 0, 0): [(1, 1), (0, 0)],
+                                      (0, 0, 7, 3): [(0, 0), (1, 0), (2, 1), (3, 1), (4, 2), (5, 2), (6, 3), (7, 3)],
+                                      (7, 3, 0, 0): [(7, 3), (6, 3), (5, 2), (4, 2), (3, 1), (2, 1), (1, 0), (0, 0)],
+                                      (4, 3, 0, 3): [(4, 3), (3, 3), (2, 3), (1, 3), (0, 3)],
+                                      (0, 3, 4, 3): [(0, 3), (1, 3), (2, 3), (3, 3), (4, 3)],
+                                      (3, 0, 3, 3): [(3, 0), (3, 1), (3, 2), (3, 3)],
+                                      (3, 3, 3, 0): [(3, 3), (3, 2), (3, 1), (3, 0)]
+                                     }
+                   }
+
+        for cell_shape, tests in attended.items():
+            for args, result in tests.items():
+                line = geometry.line2d(cell_shape, *args)
+                self.assertEqual(line, result)
+
+    def test_line3d(self):
+        """ 3d line on hexagonal and square grid """
+        cell_shape = geometry.FLAT_HEX
+
+        attended = {
+                    geometry.FLAT_HEX:    {
+                                      (1, 1, 1, 1, 1, 1) : [(1, 1, 1)],
+                                      (1, 1, 0, 1, 1, 1) : [(1, 1, 0), (1, 1, 1)],
+                                      (0, 0, 0, 1, 1, 1) : [(0, 0, 0), (0, 1, 0), (1, 1, 1)],
+                                      (0, 0, 0, 7, 3, 7) : [(0, 0, 0), (1, 0, 1), (2, 1, 2), (3, 1, 3), (4, 2, 4), (5, 2, 5), (6, 3, 6), (7, 3, 7)],
+                                      (4, 3, 10, 0, 3, 3): [(4, 3, 10), (3, 2, 9), (3, 2, 8), (2, 3, 7), (2, 3, 6), (1, 2, 5), (1, 2, 4), (0, 3, 3)],
+                                      (3, 0, 0, 3, 3, 0) : [(3, 0, 0), (3, 1, 0), (3, 2, 0), (3, 3, 0)]
+                                     },
+
+                    geometry.SQUARE: {
+                                      (1, 1, 1, 1, 1, 1) : [(1, 1, 1)],
+                                      (1, 1, 0, 1, 1, 1) : [(1, 1, 0), (1, 1, 1)],
+                                      (0, 0, 0, 1, 1, 1) : [(0, 0, 0), (1, 1, 1)],
+                                      (0, 0, 0, 7, 3, 7) : [(0, 0, 0), (1, 0, 1), (2, 1, 2), (3, 1, 3), (4, 2, 4), (5, 2, 5), (6, 3, 6), (7, 3, 7)],
+                                      (4, 3, 10, 0, 3, 3): [(4, 3, 10), (3, 3, 9), (3, 3, 8), (2, 3, 7), (2, 3, 6), (1, 3, 5), (1, 3, 4), (0, 3, 3)],
+                                      (3, 0, 0, 3, 3, 0) : [(3, 0, 0), (3, 1, 0), (3, 2, 0), (3, 3, 0)]
+                                     }
+                   }
+
+        for cell_shape, tests in attended.items():
+            for args, result in tests.items():
+                line = geometry.line3d(cell_shape, *args)
+                self.assertEqual(line, result)
+
+    def test_neighbours(self):
+        for coord in ((0, 0), (-10, -10), (10, 10)):
+            x, y = coord
+            self.assertEqual(geometry.neighbours(geometry.FLAT_HEX, x, y), geometry.fhex_neighbours(x, y))
+            self.assertEqual(geometry.neighbours(geometry.SQUARE, x, y), geometry.squ_neighbours(x, y))
+
+    def test_fhex_neighbours(self):
+        self.assertCountEqual(geometry.fhex_neighbours(3, 3), [(3, 2), (4, 3), (4, 4), (3, 4), (2, 4), (2, 3)])
+        self.assertCountEqual(geometry.fhex_neighbours(4, 4), [(4, 3), (5, 3), (5, 4), (4, 5), (3, 4), (3, 3)])
+
+    def test_squ_neighbours(self):
+        self.assertCountEqual(geometry.squ_neighbours(3, 3), [(2, 3), (2, 2), (3, 2), (4, 2), (4, 3), (4, 4), (3, 4), (2, 4)])
+
+    def test_pivot_errors(self):
+
+        # invalid cell shape
+        self.assertRaises(ValueError, geometry.pivot, 0, (0, 0), [(0, 0)], 1)
+
+        self.assertRaises(TypeError, geometry.pivot, 0, "a"    , [(0, 0)], 1)
+        self.assertRaises(ValueError, geometry.pivot, 0, ("a", 0), [(0, 0)], 1)
+
+        self.assertRaises(TypeError, geometry.pivot, 0, (0, 0), 0, 1)
+        self.assertRaises(ValueError, geometry.pivot, 0, (0, 0), ["a", (0, 0)], 1)
+        self.assertRaises(ValueError, geometry.pivot, 0, (0, 0), [("a", 0), (0, 0)], 1)
+
+        self.assertRaises(TypeError, geometry.pivot, 0, (0, 0), 1, "a")
+
+    def test_hex_pivot(self):
+        """ pivot on hexagonal grid """
+
+        attended = [
+                    [(5, 5), (4, 5), (6, 6)],
+                    [(5, 6), (4, 7), (6, 6)],
+                    [(6, 7), (6, 8), (6, 6)],
+                    [(7, 6), (8, 7), (6, 6)],
+                    [(7, 5), (8, 5), (6, 6)],
+                    [(6, 5), (6, 4), (6, 6)],
+                    [(5, 5), (4, 5), (6, 6)]
+                   ]
+
+
+        for i in range(len(attended)):
+            self.assertCountEqual(geometry.pivot(geometry.FLAT_HEX, (6, 6), [(6, 6)], i), [(6, 6)])
+            result = geometry.pivot(geometry.FLAT_HEX, (6, 6), [(5, 5), (4, 5), (6, 6)], i)
+            self.assertCountEqual(result, attended[i])
+
+    def test_squ_pivot(self):
+        """ pivot on square grid """
+        attended = [
+                    [(6, 6), (6, 5), (5, 5), (5, 6)],
+                    [(6, 6), (5, 6), (5, 7), (6, 7)],
+                    [(6, 6), (6, 7), (7, 7), (7, 6)],
+                    [(6, 6), (7, 6), (7, 5), (6, 5)],
+                    [(6, 6), (6, 5), (5, 5), (5, 6)]
+                   ]
+
+        for i in range(len(attended)):
+            self.assertCountEqual(geometry.pivot(geometry.SQUARE, (6, 6), [(6, 6)], i), [(6, 6)])
+            result = geometry.pivot(geometry.SQUARE, (6, 6), [(6, 6), (6, 5), (5, 5), (5, 6)], i)
+            self.assertCountEqual(result, attended[i])
+
+
+    def test_rectangle_errors(self):
+        for method in (geometry.rectangle, geometry.hollow_rectangle):
+            self.assertRaises(TypeError, method, "a", 1, 1, 1)
+            self.assertRaises(TypeError, method, 1, "a", 1, 1)
+            self.assertRaises(TypeError, method, 1, 1, "a", 1)
+            self.assertRaises(TypeError, method, 1, 1, 1, "a")
+
+    def test_rectangle(self):
+
+        self.assertEquals(geometry.rectangle(0, 0, 0, 0), [(0, 0)])
+        self.assertCountEqual(geometry.rectangle(0, 0, 1, 1), [(0, 0), (0, 1), (1, 1), (1, 0)])
+        self.assertCountEqual(geometry.rectangle(1, 1, 0, 0), [(0, 0), (0, 1), (1, 1), (1, 0)])
+        self.assertCountEqual(geometry.rectangle(4, 3, 7, 5), [(4, 3), (4, 4), (4, 5), (5, 5), (6, 5), (7, 5), (7, 4), (7, 3), (6, 3), (5, 3), (6, 4), (5, 4)])
+        self.assertCountEqual(geometry.rectangle(3, 3, 9, 9), [(3, 3), (9, 9), (9, 8), (9, 7), (9, 5), (9, 6), (9, 4), (9, 3), (8, 4), (7, 3), (6, 4), (4, 4),
+                                                       (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9), (4, 5),
+                                                       (5, 4), (6, 5), (7, 4), (8, 5), (4, 6), (5, 5), (6, 6), (7, 5), (8, 6), (4, 7), (5, 6), (6, 7),
+                                                       (7, 6), (8, 7), (4, 8), (5, 7), (6, 8), (7, 7), (8, 8), (7, 8), (5, 8), (8, 3), (6, 3), (4, 3),
+                                                       (5, 3)])
+
+        self.assertEquals(geometry.hollow_rectangle(0, 0, 0, 0), [(0, 0)])
+        self.assertCountEqual(geometry.hollow_rectangle(0, 0, 1, 1), [(0, 0), (0, 1), (1, 1), (1, 0)])
+        self.assertCountEqual(geometry.hollow_rectangle(1, 1, 0, 0), [(0, 0), (0, 1), (1, 1), (1, 0)])
+        self.assertCountEqual(geometry.hollow_rectangle(4, 3, 7, 5), [(4, 3), (4, 4), (4, 5), (5, 5), (6, 5), (7, 5), (7, 4), (7, 3), (6, 3), (5, 3)])
+        self.assertCountEqual(geometry.hollow_rectangle(3, 3, 9, 9), [(3, 3), (9, 9), (9, 8), (9, 7), (9, 5), (9, 6), (9, 4), (9, 3), (7, 3), (3, 4),
+                                                              (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 9), (5, 9), (6, 9), (7, 9), (8, 9),
+                                                              (8, 3), (6, 3), (4, 3), (5, 3)])
+
+    def test_triangle_errors(self):
+
+        for cell_shape in (geometry.FLAT_HEX, geometry.SQUARE):
+            self.assertRaises(TypeError, geometry.triangle, cell_shape, "a", 1, 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle, cell_shape, 1, "a", 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle, cell_shape, 1, 1, "a", 1, 1)
+            self.assertRaises(TypeError, geometry.triangle, cell_shape, 1, 1, 1, "a", 1)
+            self.assertRaises(ValueError, geometry.triangle, cell_shape, 1, 1, 1, 1, -1)
+
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, "a", 1, 1, 1, 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, 1, "a", 1, 1, 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, 1, 1, "a", 1, 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, "a", 1, 1, 1)
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, "a", 1, 1)
+            self.assertRaises(TypeError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, 1, "a", 1)
+            self.assertRaises(ValueError, geometry.triangle3d, cell_shape, 1, 1, 1, 1, 1, 1, -1)
+
+        self.assertRaises(ValueError, geometry.triangle, 0, 1, 1, 1, 1, 1)
+        self.assertRaises(ValueError, geometry.triangle3d, 0, 1, 1, 1, 1, 1, 1, 1)
+
+    def test_squ2_triangle(self):
+        """test triangle algorithms on square grid"""
+        cell_shape = geometry.SQUARE
+
+        for i in geometry.ANGLES:
+            self.assertCountEqual(geometry.triangle(cell_shape, 0, 0, 0, 0, i), [(0, 0)])
+
+        # TODO: check and validate
+#         # left to right
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # top to bottom
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # right to left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # bottom to top
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # top left to bottom right
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # bottom right to top left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # top right to bottom left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # bottom right to top left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+
+
+
+    def test_fhex2_triangle(self):
+        """test triangle algorithms on hexagonal grid"""
+        cell_shape = geometry.FLAT_HEX
+        for i in geometry.ANGLES:
+            self.assertCountEqual(geometry.triangle(cell_shape, 0, 0, 0, 0, i), [(0, 0)])
+
+        # left to right
+        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [(3, 3), (3, 4), (3, 3), (4, 5), (4, 4), (4, 3), (4, 2), (4, 1), (4, 1), (3, 1), (3, 2), (2, 3)])
+        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [(3, 3), (4, 4), (4, 3), (4, 2), (4, 2), (3, 2), (2, 3)])
+        self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [(3, 3), (4, 4), (4, 3), (4, 2), (4, 2), (3, 2), (2, 3)])
+
+        # TODO: check and validate
+
+#         # top to bottom
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+        # right to left
+        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 1), [(3, 2), (3, 1), (3, 2), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 5), (3, 4), (3, 3), (4, 3)])
+        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 2), [(3, 2), (2, 2), (2, 3), (2, 4), (2, 4), (3, 3), (4, 3)])
+        self.assertCountEqual(geometry.triangle(cell_shape, 4, 3, 2, 3, 3), [(3, 2), (2, 2), (2, 3), (2, 4), (2, 4), (3, 3), (4, 3)])
+
+#         # bottom to top
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # top left to bottom right
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # bottom right to top left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # top right to bottom left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+#
+#         # bottom right to top left
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 1), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 2), [])
+#         self.assertCountEqual(geometry.triangle(cell_shape, 2, 3, 4, 3, 3), [])
+
+
+
+    def test_squ3_triangle(self):
+        """test triangle3d algorithms on square grid"""
+        cell_shape = geometry.SQUARE
+        # TODO: complete
+
+    def test_fhex3_triangle(self):
+        """test triangle3d algorithms on hexagonal grid"""
+        cell_shape = geometry.FLAT_HEX
+        # TODO: complete
+
+    def test_zone(self):
+        """test the errors due to bad parameters"""
+        self.assertRaises(TypeError, geometry.zone, 5, 0, 0, "a")
+        self.assertRaises(TypeError, geometry.zone, 5, "a", 0, 1)
+        self.assertRaises(TypeError, geometry.zone, 5, 0, "a", 1)
+        self.assertRaises(ValueError, geometry.zone, 5, 0, 0, -1)
+        self.assertRaises(ValueError, geometry.zone, -1, 0, 0, 1)
+        self.assertRaises(ValueError, geometry.zone, "a", 0, 0, 1)
+
+    def test_hex_zone(self):
+        """ test the zone algo for hexagonal grid """
+        cell_shape = geometry.FLAT_HEX
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 0), [(3, 3)])
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 1), [(3, 2), (2, 3), (3, 3), (4, 3), (4, 4), (3, 4), (2, 4)])
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 2), [(3, 2), (1, 3), (5, 4), (4, 5), (1, 4), (2, 3), (4, 2), \
+                                                            (2, 5), (5, 3), (1, 2), (3, 5), (3, 3), (4, 4), (3, 1), \
+                                                            (4, 3), (2, 2), (3, 4), (2, 4), (5, 2)])
+
+    def test_squ_zone(self):
+        """ test the zone algo for square grid """
+        cell_shape = geometry.SQUARE
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 0), [(3, 3)])
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 1), [(3, 2), (3, 3), (4, 4), (2, 3), (4, 3), (2, 2), (4, 2), (3, 4), (2, 4)])
+        self.assertCountEqual(geometry.zone(cell_shape, 3, 3, 2), [(2, 4), (3, 2), (5, 4), (1, 3), (4, 5), (2, 1), (1, 4), (2, 3), (4, 2), \
+                                                                    (5, 1), (2, 5), (3, 5), (5, 3), (1, 2), (3, 3), (5, 5), (4, 4), (3, 1), \
+                                                                    (1, 5), (4, 3), (2, 2), (4, 1), (5, 2), (3, 4), (1, 1)])
+
+if __name__ == "__main__":
+    unittest.main()

+ 59 - 60
tests/test_grid.py

@@ -1,101 +1,100 @@
 '''
 '''
-Created on 20 nov. 2016
 
 
-@author: olinox
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 import unittest
 import unittest
 
 
 from pypog import geometry
 from pypog import geometry
-from pypog.Grid import Grid, SquareGrid, HexGrid
+from pypog.grid_objects import Grid, SquareGrid, HexGrid
 
 
 
 
 class Test(unittest.TestCase):
 class Test(unittest.TestCase):
 
 
     def test_init(self):
     def test_init(self):
-        #square grid
-        _ = Grid( geometry.SQUARE, 1, 1 )
-        _ = SquareGrid( 1, 1 )
-        
-        #hex grid
-        _ = Grid( geometry.HEX, 1, 1 )
-        _ = HexGrid( 1, 1 )
+        # square grid
+        _ = Grid(geometry.SQUARE, 1, 1)
+        _ = SquareGrid(1, 1)
+
+        # hex grid
+        _ = Grid(geometry.FLAT_HEX, 1, 1)
+        _ = HexGrid(1, 1)
 
 
     def test_cell_shape(self):
     def test_cell_shape(self):
-        grid = Grid( geometry.SQUARE, 1, 1 )
-        self.assertEqual( grid.cell_shape, geometry.SQUARE )
-        
-        grid.cell_shape = geometry.HEX
-        self.assertEqual( grid.cell_shape, geometry.HEX )
+        grid = Grid(geometry.SQUARE, 1, 1)
+        self.assertEqual(grid.cell_shape, geometry.SQUARE)
+
+        grid.cell_shape = geometry.FLAT_HEX
+        self.assertEqual(grid.cell_shape, geometry.FLAT_HEX)
 
 
         def _set_invalid_cell_shape():
         def _set_invalid_cell_shape():
             grid.cell_shape = -1
             grid.cell_shape = -1
-        self.assertRaises( ValueError, _set_invalid_cell_shape )
+        self.assertRaises(ValueError, _set_invalid_cell_shape)
 
 
     def test_dimensions(self):
     def test_dimensions(self):
-        
+
         for cls in (SquareGrid, HexGrid):
         for cls in (SquareGrid, HexGrid):
-            grid = cls( 1, 1 )
-            self.assertEqual( grid.height, 1 )
-            self.assertEqual( grid.width, 1 )
-    
+            grid = cls(1, 1)
+            self.assertEqual(grid.height, 1)
+            self.assertEqual(grid.width, 1)
+
             grid.height = 1000
             grid.height = 1000
-            self.assertEqual( grid.height, 1000 )
+            self.assertEqual(grid.height, 1000)
             grid.width = 1000
             grid.width = 1000
-            self.assertEqual( grid.width, 1000 )
-    
+            self.assertEqual(grid.width, 1000)
+
             def _set_invalid_height():
             def _set_invalid_height():
                 grid.height = -1
                 grid.height = -1
-            self.assertRaises( ValueError, _set_invalid_height )
-            
+            self.assertRaises(ValueError, _set_invalid_height)
+
             def _set_invalid_width():
             def _set_invalid_width():
                 grid.height = -1
                 grid.height = -1
-            self.assertRaises( ValueError, _set_invalid_width )
-        
+            self.assertRaises(ValueError, _set_invalid_width)
+
     def test_cases_number(self):
     def test_cases_number(self):
         for cls in (SquareGrid, HexGrid):
         for cls in (SquareGrid, HexGrid):
-            grid = cls( 1, 1 )
-            self.assertEqual( grid.cases_number(), 1 )
-            
+            grid = cls(1, 1)
+            self.assertEqual(grid.cases_number(), 1)
+
             grid.width = 100
             grid.width = 100
             grid.height = 100
             grid.height = 100
-            
-            self.assertEqual( grid.cases_number(), 10000 )
-    
+
+            self.assertEqual(grid.cases_number(), 10000)
+
     def test_in_grid(self):
     def test_in_grid(self):
-        
+
         for cls in (SquareGrid, HexGrid):
         for cls in (SquareGrid, HexGrid):
-            grid = cls( 10, 10 )
-            self.assertTrue( grid.in_grid(5, 5) )
-            self.assertFalse( grid.in_grid(11, 5) )
-            self.assertFalse( grid.in_grid(5, 11) )
+            grid = cls(10, 10)
+            self.assertTrue(grid.in_grid(5, 5))
+            self.assertFalse(grid.in_grid(11, 5))
+            self.assertFalse(grid.in_grid(5, 11))
 
 
     def test_line(self):
     def test_line(self):
-         
-        #line algorithm is tested in tests.geometry.test_line
-        
+
+        # line algorithm is tested in tests.geometry.test_line
+
         grid = SquareGrid(10, 10)
         grid = SquareGrid(10, 10)
-         
-        line = grid.line(0,0,0,1)
-        self.assertEqual(line, [(0,0), (0,1)])
-        
+
+        line = grid.line(0, 0, 0, 1)
+        self.assertEqual(line, [(0, 0), (0, 1)])
+
     def test_line_3d(self):
     def test_line_3d(self):
-        
-        #line algorithm is tested in tests.geometry.test_line
-        
+
+        # line algorithm is tested in tests.geometry.test_line
+
         grid = HexGrid(10, 10)
         grid = HexGrid(10, 10)
-    
-        line = grid.line3d(1,1,1,1,1,1)
-        self.assertEqual(line, [(1,1,1)])
-    
+
+        line = grid.line3d(1, 1, 1, 1, 1, 1)
+        self.assertEqual(line, [(1, 1, 1)])
+
 
 
     def test_hex_zone(self):
     def test_hex_zone(self):
-        
-        #zone algorithm is tested in tests.geometry.test_zone
-        
-        grid = HexGrid(10,10)
-        zone = grid.zone( 0, 0, 0 )
-        self.assertCountEqual(zone, [(0,0)])
+
+        # zone algorithm is tested in tests.geometry.test_zone
+
+        grid = HexGrid(10, 10)
+        zone = grid.zone(0, 0, 0)
+        self.assertCountEqual(zone, [(0, 0)])
 
 
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
-    unittest.main()
+    unittest.main()

+ 27 - 28
tests/test_pencils.py

@@ -1,69 +1,68 @@
 '''
 '''
-Created on 12 dec. 2016
 
 
-@author: olinox
+    ** By Cro-Ki l@b, 2017 **
 '''
 '''
 import unittest
 import unittest
 
 
-from pypog import geometry, Grid, pencil
+from pypog import geometry, grid_objects, painting
 
 
 class Test(unittest.TestCase):
 class Test(unittest.TestCase):
 
 
     def test_base_pencil(self):
     def test_base_pencil(self):
-        for cell_shape in (geometry.HEX, geometry.SQUARE):
-        
-            self.assertRaises(TypeError, pencil.BasePencil, "invalid arg")
-            
-            grid = Grid.Grid(cell_shape, 30, 30)
-            my_pencil = pencil.BasePencil(grid)
-            
+        for cell_shape in (geometry.FLAT_HEX, geometry.SQUARE):
+
+            self.assertRaises(TypeError, painting.BasePencil, "invalid arg")
+
+            grid = grid_objects.Grid(cell_shape, 30, 30)
+            my_pencil = painting.BasePencil(grid)
+
             # default origin and position
             # default origin and position
             self.assertEqual(my_pencil.origin, None)
             self.assertEqual(my_pencil.origin, None)
             self.assertEqual(my_pencil.position, None)
             self.assertEqual(my_pencil.position, None)
-            self.assertRaises(AttributeError, my_pencil.origin, (1,1))
-            self.assertRaises(AttributeError, my_pencil.position, (1,1))
-            
+            self.assertRaises(AttributeError, my_pencil.origin, (1, 1))
+            self.assertRaises(AttributeError, my_pencil.position, (1, 1))
+
             # size
             # size
             self.assertRaises(TypeError, setattr, my_pencil, "size", "a")
             self.assertRaises(TypeError, setattr, my_pencil, "size", "a")
             self.assertRaises(ValueError, setattr, my_pencil, "size", -1)
             self.assertRaises(ValueError, setattr, my_pencil, "size", -1)
             self.assertEqual(my_pencil.size, 1)
             self.assertEqual(my_pencil.size, 1)
-            
+
             # selection, added, removed
             # selection, added, removed
             self.assertEqual(my_pencil.selection, [])
             self.assertEqual(my_pencil.selection, [])
             self.assertEqual(my_pencil.added, [])
             self.assertEqual(my_pencil.added, [])
             self.assertEqual(my_pencil.removed, [])
             self.assertEqual(my_pencil.removed, [])
-            
+
             # pencil methods
             # pencil methods
             self.assertRaises(TypeError, my_pencil.start, "a")
             self.assertRaises(TypeError, my_pencil.start, "a")
-            self.assertRaises(pencil.NotStartedException, my_pencil.update, 1,1)
+            self.assertRaises(painting.NotStartedException, my_pencil.update, 1, 1)
             self.assertRaises(NotImplementedError, my_pencil._update)
             self.assertRaises(NotImplementedError, my_pencil._update)
-            
+
             try:
             try:
-                my_pencil.start(0,0)
+                my_pencil.start(0, 0)
             except NotImplementedError:
             except NotImplementedError:
                 pass
                 pass
             self.assertRaises(TypeError, my_pencil.update, "a")
             self.assertRaises(TypeError, my_pencil.update, "a")
-            self.assertEqual(my_pencil.origin, (0,0))
-            
+            self.assertEqual(my_pencil.origin, (0, 0))
+
     def test_line_pencil(self):
     def test_line_pencil(self):
         pass
         pass
-    
+
     def test_free_pencil(self):
     def test_free_pencil(self):
         pass
         pass
-    
+
     def test_pot_pencil(self):
     def test_pot_pencil(self):
         pass
         pass
-    
+
     def test_rect_pencil(self):
     def test_rect_pencil(self):
         pass
         pass
-    
+
     def test_hrect_pencil(self):
     def test_hrect_pencil(self):
         pass
         pass
-    
+
     def test_boundary_pencil(self):
     def test_boundary_pencil(self):
         pass
         pass
-    
-    
+
+
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
-    unittest.main()
+    unittest.main()