class DigitalPlane(object): """Class that represents a digital plane""" def __init__(self, parameters, bound=0): """Construction of a digital plane. The components of the normal vector must be given as a list of integers or as a PointVector. :param parameters: components of the normal vector. :param bound: intercept (default, 0). :raises TypeError if the type of the normal vector is unknown. """ self.bound = bound if isinstance(parameters, list): self.normal = PointVector(parameters) elif isinstance(parameters, PointVector): self.normal = parameters else: raise TypeError def __call__(self, x): """Predicate operator. :param x: any instance of PointVector :return: 'True' if x is in the digital plane, 'False' otherwise. """ r = self.remainder(x) return self.bound <= r and r < self.normal.norm("L1") def remainder(self, x): """Returns the remainder of a given point.""" return self.normal.dot(x) - self.bound def __repr__(self): return str(self.normal) + ", " + str(self.bound)
def drawBasis(self): o = PointVector([0] * 3) op = self.projector(o) e0p = self.projector(self.e0) e1p = self.projector(self.e1) e2p = self.projector(self.e2) opp = self.transform(op) self.canvas.create_line(self.flatten([opp, self.transform(e0p)]), arrow=tk.LAST, fill="purple", width=2, tags="basis") self.canvas.create_line(self.flatten([opp, self.transform(e1p)]), arrow=tk.LAST, fill="purple", width=2, tags="basis") self.canvas.create_line(self.flatten([opp, self.transform(e2p)]), arrow=tk.LAST, fill="purple", width=2, tags="basis") pointKey = self.canvas.create_circle(opp[0], opp[1], self.dotSize, fill="purple", tags="basis") self.canvas.tag_bind(pointKey, "<Button-1>", self.selectStartingPoint) self.grid[pointKey] = o
def __init__(self, parameters, bound=0): """Construction of a digital plane. The components of the normal vector must be given as a list of integers or as a PointVector. :param parameters: components of the normal vector. :param bound: intercept (default, 0). :raises TypeError if the type of the normal vector is unknown. """ self.bound = bound if isinstance(parameters, list): self.normal = PointVector(parameters) elif isinstance(parameters, PointVector): self.normal = parameters else: raise TypeError
class Tile(object): colorByType = { PointVector([-1, 0, 0]): "grey60", PointVector([0, -1, 0]): "grey30", PointVector([0, 0, -1]): "grey80", } colorByGroup = ["grey80", "gray60", "gray30"] def __init__(self, origin, v1, v2, normal): self.o = origin self.v1 = v1 self.v2 = v2 self.n = normal def origin(self): return self.o def shift(self, v): self.o += v
def neighborhood(current): """Returns the 6 neighbors of the given point as a list. :param current: any point :return: list of the 6 neighbors of the given point """ return [ current + PointVector([1, 0, 0]), current + PointVector([-1, 0, 0]), current + PointVector([0, 1, 0]), current + PointVector([0, -1, 0]), current + PointVector([0, 0, 1]), current + PointVector([0, 0, -1]) ]
from NormalComputer.DigitalPlane import DigitalPlane, isReduced, additiveReduction from NormalComputer.TriangleComputer import TriangleComputer #------------------------------------------------------------- #parse command line parser = argparse.ArgumentParser(description="R-algorithm testing for a normal vector whose greatest component is below a threshold") parser.add_argument("-t", "--threshold",help="maximal value for the greatest component of the normal vector",type=int, default=10) #------------------------------------------------------------- args = parser.parse_args() maxTests = args.threshold print(maxTests) o = PointVector([0]*3) e0 = PointVector([1,0,0]) e1 = PointVector([0,1,0]) e2 = PointVector([0,0,1]) s = PointVector([1]*3) q = s counter = 0 for a in range(1,maxTests): for b in range(a,maxTests): for c in range(b,maxTests): d = gcd(a,b) if gcd(d,c) == 1: counter += 1 n = PointVector([a,b,c]) print("#", n)
#non negative if not functools.reduce( lambda x,y: x and y, [x >= 0 for x in param] ): print("Components must be non negative") exit(0) #sum of zeros zeros = 0 for component in param: if component == 0: zeros += 1 if zeros >= 2: print("Only one component over three is allowed to be equal to zero") exit(0) #normal n = PointVector(param) #predicate plane = DigitalPlane(n) #mode mode = "R" if args.algorithmMode == "H": mode = "H" #------------------------------------------------------------- #basis o = PointVector([0]*3) e0 = PointVector([1,0,0]) e1 = PointVector([0,1,0]) e2 = PointVector([0,0,1])
def selectStartingPoint(self, event): report_event(event) pointKey = self.canvas.find_withtag(tk.CURRENT)[0] #current item id self.q = self.grid[pointKey] + PointVector([1] * 3) self.start()
def __init__(self, parent, normal, size, step, projector, algorithmMode, patternMode): """ Initilization of the application :param parent: object of type Tk :param normal: plane normal (provided as a PointVector) :param size: discrete size of the drawing window :param step: grid step of the drawing window :param projector: projection from a 3d PointVector to a 2d PointVector. :param algorithmMode: either 'H' or 'R' :param patternMode: specify the color of the tiles or the starting set of tiles, useful when drawing pattern is enabled """ #dimensions self.discreteSize = size self.gridStep = step self.dotSize = step / 10.0 #origin mid = self.discreteSize / 2 self.origin = PointVector([mid] * 2) #canvas realSize = self.gridStep * self.discreteSize self.canvas = tk.Canvas(parent, width=realSize, height=realSize, borderwidth=0, highlightthickness=0) self.canvas.pack() #projector self.projector = projector #mode self.mode = patternMode self.algo = algorithmMode #digital plane o = PointVector([0] * 3) self.plane = DigitalPlane(normal) pointSet3 = set() edgeSet3 = set() generateBFS(o, lambda x: self.plane(x) and x.norm("Linf") <= size, pointSet3, edgeSet3) #digital plane as dictionnary of 3d points for e3 in edgeSet3: e2 = [self.projector(x) for x in e3] coords = self.flatten([self.transform(x) for x in e2]) self.canvas.create_line(coords, fill="gray", width=2) self.grid = {} for p3 in pointSet3: p2 = self.transform(self.projector(p3)) pointKey = self.canvas.create_circle(p2[0], p2[1], self.dotSize, fill="black") self.canvas.tag_bind(pointKey, "<Button-1>", self.selectStartingPoint) self.grid[pointKey] = p3 #default options self.enableH = False self.enableR = False self.enableT = False self.enableP = False self.enableE = False #key binding self.canvas.bind_all("<Right>", self.updateForwardAndDraw) self.canvas.bind_all("<Left>", self.updateBackwardAndDraw) self.canvas.bind_all("<Return>", self.reSetTriangle) self.canvas.bind_all("<End>", self.exportCanvas) self.canvas.bind_all("<Key>", self.setOption) #data self.q = PointVector([1] * 3) self.s = PointVector([1] * 3) self.e0 = PointVector([1, 0, 0]) self.e1 = PointVector([0, 1, 0]) self.e2 = PointVector([0, 0, 1]) self.drawBasis() self.start()
choices=["upper","lower"],default="upper") parser.add_argument("-m", "--algorithmMode", help="mode of the algorithm (default R)", choices=["H", "R"], default="R") parser.add_argument( "-k", "--showKeybindings", help= "print to the standard output the keys you can hit to modify the display", action="store_true") args = parser.parse_args() param = [args.x, args.y, args.z] n = PointVector(param) projector = standardProjector if args.projection == "hexagonal": projector = hexagonalProjector mode = PatternMode() mode.color = firstArg if args.color == "group": mode.color = secondArg mode.corner = "upper" if args.startingCorner == "lower": mode.corner = args.startingCorner algo = "R" if args.algorithmMode == "H": algo = "H" if args.showKeybindings: print("H:enables/disables hexagon display")