I want to define a function sortbooks(shelf) using insert_animate(blockposition, shelf, high) such that it sorts the shelf according to their size in ascending order.
I have come up with this function:
def sortbooks(shelf):
for i in shelf:
insert_animate(i.size,shelf,max(shelf))
return shelf
However, I got a TypeError as such:
File "<pyshell#275>", line 3, in sortbooks
insert_animate(i.size,shelf,max(shelf))
TypeError: '>' not supported between instances of 'Block' and 'Block'
How should I go about in defining this function? Is my approach completely wrong? I would really appreciate help/some guidance on this! Thank you!
This is the function for insert_animate:
def insert_animate(blockposition, shelf, high):
if blockposition == 0:
return shelf
a = s.pop(blockposition)
for i in range(high):
if a.size <= s[i].size:
s.insert(i, a)
break
else:
s.insert(high, a)
return shelf
Below is shelf.py:
from turtle import *
class Block(Turtle):
def __init__(self, size):
self.size = size
Turtle.__init__(self, shape="square", visible=False)
self.pu()
self.shapesize(size * 1.5, 1.5, 2) # square-->rectangle
self.fillcolor("black")
self.st()
def glow(self):
self.fillcolor("red")
def unglow(self):
self.fillcolor("black")
def __repr__(self):
return "Block size: {0}".format(self.size)
class Shelf(list):
def __init__(self, y):
"create an shelf. y is y-position of first block"
self.y = y
self.x = -150
def push(self, d):
width, _, _ = d.shapesize()
yoffset = width/2 * 20 # to align the blocks by it's bottom edge
d.sety(self.y + yoffset)
d.setx(self.x+34*len(self))
self.append(d)
def _close_gap_from_i(self, i):
for b in self[i:]:
xpos, _ = b.pos()
b.setx(xpos - 34)
def _open_gap_from_i(self, i):
for b in self[i:]:
xpos, _ = b.pos()
b.setx(xpos + 34)
def pop(self, key):
b = list.pop(self, key)
b.glow()
b.sety(200)
self._close_gap_from_i(key)
return b
def insert(self, key, b):
self._open_gap_from_i(key)
list.insert(self, key, b)
b.setx(self.x+34*key)
width, _, _ = b.shapesize()
yoffset = width/2 * 20 # to align the blocks by it's bottom edge
b.sety(self.y + yoffset)
b.unglow()
def show_text(text):
goto(0,-250)
write(text, align="center", font=("Courier", 16, "bold"))
def start_sort():
onkey(None,"space")
clear()
show_text("sort_me")
sort_func(s)
def init_shelf(vals=(4, 8, 2, 9, 3, 1, 10, 7, 5, 6)):
s = Shelf(-200)
for i in vals:
s.push(Block(i))
return s
def clear_window():
getscreen().clearscreen()
def main(func):
global sort_func
sort_func = func
getscreen().clearscreen()
ht(); penup()
init_shelf()
show_text("press spacebar to start sorting")
onkey(start_sort, "space")
onkey(bye, "Escape")
listen()
mainloop()
To solve the problem you have right now, you can use max(shelf, key=lambda b: b.size) instead. An alternative way is to add __gt__ method for block.
I'm just beginning working with object-oriented programming. I have created some classes and am trying to complete the rectangle class. Any and all help is appreciated.
I'm confused about when you need to refer to self and when you can just create variables. For example, in defining the length of the rectangle, I don't know if I should call the variable self.length or just length, and I haven't been able to find any rectangle classes defined in this way.
import math
class Point (object):
# constructor
def __init__ (self, x = 0, y = 0):
self.x = x
self.y = y
# get distance
def dist (self, other):
return math.hypot (self.x - other.x, self.y - other.y)
# get a string representation of a Point object
def __str__ (self):
return '(' + str(self.x) + ", " + str(self.y) + ")"
# test for equality
def __eq__ (self, other):
tol = 1.0e-16
return ((abs (self.x - other.x) < tol) and (abs(self.y - other.y) < tol))
class Circle (object):
# constructor
def __init__ (self, radius = 1, x = 0, y = 0):
self.radius = radius
self.center = Point (x, y)
# compute cirumference
def circumference (self):
return 2.0 * math.pi * self.radius
# compute area
def area (self):
return math.pi * self.radius * self.radius
# determine if point is strictly inside circle
def point_inside (self, p):
return (self.center.dist(p) < self.radius)
# determine if a circle is strictly inside this circle
def circle_inside (self, c):
distance = self.center.dist (c.center)
return (distance + c.radius) < self.radius
# determine if a circle c intersects this circle (non-zero area of overlap)
def does_intersect (self, c):
# string representation of a circle
def __str__ (self):
# test for equality of radius
def __eq__ (self, other):
tol = 1.0e-16
class Rectangle (object):
# constructor
def __init__ (self, ul_x = 0, ul_y = 1, lr_x = 1, lr_y = 0):
if ((ul_x < lr_x) and (ul_y > lr_y)):
self.ul = Point (ul_x, ul_y)
self.lr = Point (lr_x, lr_y)
else:
self.ul = Point (0, 1)
self.lr = Point (1, 0)
# determine length of Rectangle
def length (self):
# determine width of Rectangle
def width (self):
# determine the perimeter
def perimeter (self):
# determine the area
def area (self):
# determine if a point is strictly inside the Rectangle
def point_inside (self, p)
# determine if another Rectangle is inside this Rectangle
def rectangle_inside (self, r):
# determine if two Rectangles overlap
def does_intersect (self, other):
# determine the smallest rectangle that circumscribes a circle
def rect_circumscribe (self, c):
# give string representation of a rectangle
def __str__ (self):
# determine if two rectangles have the same length and width
def __eq__ (self, other):
Basically, setting a value to self.length gives you the ability to access this value from other functions inside the class and from outside of the class. If you set a value to length, you are able to access this variable only in the current function inside the class.
Just a start, try to continue yourself:
class Rectangle (object):
# constructor
def __init__ (self, ul_x = 0, ul_y = 1, lr_x = 1, lr_y = 0):
# Called if you say: my_rectancle = Rectangle (-10, 10, 10, -10)
# Puts parameters in fields of your newly created object of class Rectancle
self.ul_x = ul_x
self.ul_y = ul_y
self.lr_x = lr_x
self.lr_y = lr_y
# compute cirumference
def circumference (self):
return 2 * (self.ur_x - self.lr_x) + 2 * (self.ul_y - self.lr_y)
# compute area
def area (self):
return (self.ur_x - self.lr_x) * (self.ul_y - self.lr_y)
[EDIT]
With regard to the additional code in your comment, it's quite close to what it should be. With some corrections:
# determine length of Rectangle
def length (self):
return self.ul_y - self.lr_y
# determine width of Rectangle
def width (self):
return self.lr_x - self.ul_x
# self. has been added, since e.g. lr_x is not a parameter
# of the width function, but a field of the object you make
# by instantiation: 'rectangle = Rectangle (10, 20, 100, 200)'
# After that, self refers to the object 'rectangle' you created,
# which has class 'Rectangle'.
#
# Note that a class is a type.
# You can have a type 'Dog'.
# Dog 'fluffy' is an instance of that class, so a particular dog.
# In the methods (functions) of 'Dog', 'self' refers to the particular
# dog you're working with.
# determine the perimeter
def perimeter (self):
return 2 * self.width () + 2 * self.length ()
# Note the () after width and length.
# They're needed because width and length are
# function calls (they DO something) rather than fields (data)
# You could also have stored width and length into fields,
# just like the constructor did with ul_x, ul_y, lr_x and lr_y,
# storing them in self.ul_x, self.ul_y etc.
# Then the braces wouldn't have been needed.
# But also out some superfluous braces here
# Multiplication goes before addition anyhow
# And return returns everything after it, no braces needed.
# determine the area
def area (self):
return self.width () * self.length ()
So, how far did you get now?
I use pyqtgraph for data acquisition and I have to represent some thresholds on the graphics view. For example to represent a high voltage limit, etc.
I used the class InfiniteLine from pyqtgraph, but now, I have to take into account some possible changes on the threshold value during the acquisition. It would look as a step between two infinite line (please find an example attached).
example
For this, I would have to draw a half infinite line. Do you know a simple way to do it?
I thought about using some plotCurveItem limited by the viewBox minimum and maximum :
thresholdValue = 60V # just an example
range = self.viewBox.viewRange()
xRange = range[0] # we only want ViewBox horizontal limits
minView = xRange[0]
maxView = xRange[1]
myPlotCurveItem = pyqtgraph.PlotCurveItem([minView, maxView],[thresholdValue, thresholdValue])
In case of changing on threshold value :
newThresholdValue = 70V
the x data for the plotCurveItem would become :
[minView, changingTime] #with changinTime : the moment we change the threshold
and we would add a new plotCurveItem :
myNewPlotCurveItem = pyqtgraph.plotCurveItem([changingTime, maxView],[newThresholdValue, newThresholdValue])
Does this solution looks good or do you see any problem with that?
Your approach looks good and is mostly what pyqtgraph.InfiniteLine is doing. I examined the source of InfiniteLine and extracted those parts which are absolutely necessary and added the change point and two level information, then drawing three lines (left border to change point at left level, change point to right border at right level, connection of both).
Here is the full code:
from pyqtgraph.Qt import QtGui
import numpy as np
import pyqtgraph as pg
class InfiniteLineWithBreak(pg.GraphicsObject):
def __init__(self, changeX, levelsY, pen=None):
pg.GraphicsObject.__init__(self)
self.changeX = changeX
self.levelsY = levelsY
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def setBounds(self, bounds):
self.maxRange = bounds
self.setValue(self.value())
def setPen(self, *args, **kwargs):
self.pen = pg.fn.mkPen(*args, **kwargs)
if not self.mouseHovering:
self.currentPen = self.pen
self.update()
def setHoverPen(self, *args, **kwargs):
self.hoverPen = pg.fn.mkPen(*args, **kwargs)
if self.mouseHovering:
self.currentPen = self.hoverPen
self.update()
def boundingRect(self):
br = self.viewRect()
return br.normalized()
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
# three lines (left border to change point, change point vertical, change point to right)
p.drawLine(pg.Point(br.left(), self.levelsY[0]), pg.Point(self.changeX, self.levelsY[0]))
p.drawLine(pg.Point(self.changeX, self.levelsY[0]), pg.Point(self.changeX, self.levelsY[1]))
p.drawLine(pg.Point(self.changeX, self.levelsY[1]), pg.Point(br.right(), self.levelsY[1]))
def dataBounds(self, axis, frac=1.0, orthoRange=None):
if axis == 0:
return None ## x axis should never be auto-scaled
else:
return (0,0)
def setMouseHover(self, hover):
pass
app = QtGui.QApplication([])
w = pg.GraphicsWindow()
w.resize(1000, 600)
v = w.addPlot(y=np.random.normal(size=100))
v.addItem(InfiniteLineWithBreak(changeX=50, levelsY=(-1, 1)))
app.exec_()
It looks like:
What one could add is reaction to hovering and changing the values with the mouse (change point as well as levels) or even rotate by 90 degree. InfiniteLine is a good example of how to do that.
thanks you for you very complete answer !
Your code works very well.
I made some modifications on your class InfiniteLineWithBreak in order to set multiple threshold transitions.
I modified the init and the paint methods only:
def __init__(self, listOfcouplesOfThresholdAndItsDate, pen=None):
pg.GraphicsObject.__init__(self)
self.listOfcouplesOfThresholdAndItsDate=listOfcouplesOfThresholdAndItsDate
self.maxRange = [None, None]
self.moving = False
self.movable = False
self.mouseHovering = False
pen = (200, 200, 100)
self.setPen(pen)
self.setHoverPen(color=(255,0,0), width=self.pen.width())
self.currentPen = self.pen
def paint(self, p, *args):
br = self.boundingRect()
p.setPen(self.currentPen)
if len(self.listOfcouplesOfThresholdAndItsDate)==0:
pass
elif len(self.listOfcouplesOfThresholdAndItsDate)==1:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
p.drawLine(pg.Point(date, threshold), pg.Point(br.right(), threshold))
else:
threshold = self.listOfcouplesOfThresholdAndItsDate[0][1]
date = self.listOfcouplesOfThresholdAndItsDate[0][0]
i=0
for i in range(0, len(self.listOfcouplesOfThresholdAndItsDate)-2):
threshold = self.listOfcouplesOfThresholdAndItsDate[i][1]
date = self.listOfcouplesOfThresholdAndItsDate[i][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[i+1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[i+1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
threshold = self.listOfcouplesOfThresholdAndItsDate[-2][1]
date = self.listOfcouplesOfThresholdAndItsDate[-2][0]
nexteDate = self.listOfcouplesOfThresholdAndItsDate[-1][0]
nextThreshold = self.listOfcouplesOfThresholdAndItsDate[-1][1]
p.drawLine(pg.Point(date, threshold), pg.Point(nexteDate, threshold))
p.drawLine(pg.Point(nexteDate, threshold), pg.Point(nexteDate, nextThreshold))
p.drawLine(pg.Point(nexteDate, nextThreshold), pg.Point(br.right(), nextThreshold))
Moreover, I added a method to append a new threshold transition point to the listOfcouplesOfThersholdAndItsDate :
def addANewThreshold(self,date, threshold):
self.listOfcouplesOfThresholdAndItsDate.append((date, threshold))
Here is an example of what it looks like :
example of multiple thresholds
Does the code look okay to you ?
Thank you,
I'm new to qgis and in here I want to find a path between two selected points on the map(Roads-vector layer). The points are selected by the user, using mouse clicks.
So here I used the astar algorithm to find path between two points.
*******************************astar.py**********************************
import heapq
class AStar(object):
def __init__(self, graphAstar):
self.graphAstar = graphAstar
def heuristic(self, node, start, end):
raise NotImplementedError
def search(self, start, end):
openset = set()
closedset = set()
current = start
openHeap = []
openset.add(current)
openHeap.append((0,current))
while openset:
temp = heapq.heappop(openHeap)
current = temp[1]
if current == end:
path = []
while current.parent:
path.append(current)
current = current.parent
path.append(current)
return path[::-1]
openset.remove(current)
closedset.add(current)
for node in self.graphAstar[current]:
if node in closedset:
continue
if node in openset:
new_g = current.gg + current.move_cost(node)
if node.gg > new_g:
node.gg = new_g
node.parent = current
else:
node.gg = current.gg + current.move_cost(node)
node.H = self.heuristic(node, start, end)
node.parent = current
openset.add(node)
heapq.heappush(openHeap, (node.H,node))
return None
class AStarNode(object):
def __init__(self):
self.gg = 0
self.H = 0
self.parent = None
def move_cost(self, other):
raise NotImplementedError
*****************************astar_grid.py*******************************
from astar import AStar, AStarNode
from math import sqrt
class AStarGrid(AStar):
def heuristic(self, node, start, end):
return sqrt((end.x - node.x)**2 + (end.y - node.y)**2)
class AStarGridNode(AStarNode):
def __init__(self, x, y):
self.x, self.y = x, y
super(AStarGridNode, self).__init__()
def move_cost(self, other):
diagonal = abs(self.x - other.x) == 1 and abs(self.y - other.y) == 1
return 14 if diagonal else 10
and in the main code, the following method is used to create graph from vector layer.
**************************plugin.py**********************************
def make_graph(self, mapinfo):
nodes = [[AStarGridNode(x, y) for y in range(mapinfo['height'])] for x in range(mapinfo['width'])]
graphAstar = {}
for x, y in product(range(mapinfo['width']), range(mapinfo['height'])):
node = nodes[x][y]
graphAstar[node] = []
for i, j in product([-1, 0, 1], [-1, 0, 1]):
if not (0 <= x + i < mapinfo['width']): continue
if not (0 <= y + j < mapinfo['height']): continue
graphAstar[nodes[x][y]].append(nodes[x+i][y+j])
return graphAstar, nodes
And I called that method in FindRoutes method..
def findRoutes(self):
vl=self.canvas.currentLayer()
director = QgsLineVectorLayerDirector( vl, -1, '', '', '', 3 )
properter = QgsDistanceArcProperter()
director.addProperter( properter )
crs = self.canvas.mapRenderer().destinationCrs()
builder = QgsGraphBuilder( crs )
global x1
global y1
global x2
global y2
pStart = QgsPoint( x1, y1 )
pStop = QgsPoint( x2, y2 )
graphAstar, nodes = self.make_graph({ "width": 8, "height": 8 })
paths = AStarGrid(graphAstar)
start, end = ??
path = paths.search(start, end)
My question is, how to pass the start and end coordinates to the function above? Because passing them just as coordinates (start, end = pStart, pStop) does not work.
How do add them to the graph created as nodes?
Or is there any easy way to do it?
Please help me to to find a solution to this problem.
Thank You
When i do an astar, the node i use are intern of the astar and contain a reference vers the original point object (your tuple of position).
Maybe it's the same with your AStarGridNode ?
In your case :
start = AStarGridNode(x1, y1)
stop = AStarGridNode(x2, y2)
This part could be in the your search function to hide this from the user.
I have spent the last couple of weeks in my off-time looking at openGL. And while I do not have a problem following some of the older NeHe examples, from everything I have read, OpenGL4 is a totally different process. And I have access to the red book and the super bible, but the former is still offering legacy opengl calls where as the latter uses their own library. Neither is especially helpful in understanding how to put together code in a project. For example, my current understanding is that glu and glut are legacy and shouldn't be used for opengl 4.
I can generate vertices very easily for a hypothetical model space. I have an extremely hard time understanding how a model ends up showing up on my screen. About 95% of my attempts end up with a black blank screen.
Thanks in advance.
Here's some code:
# primatives.py
from collections import Iterable
from functools import reduce
import operator
import numpy as np
from exc import UnimplementedMethod
class Primative(object):
SIZE = 1 # number of pixels on a default grid
def __init__(self, point=None, *args, **kwargs):
self.point = point if isinstance(point, Iterable) else [0, 0, 0]
self.point = np.array(self.point, dtype=np.float32)
scaler = [self.SIZE/2]*len(self.point)
self.point = (self.point * scaler).tolist()
#property
def active(self):
attr = "__active__"
if not hasattr(self, attr):
setattr(self, attr, False)
return getattr(self, attr)
#active.setter
def active(self, value):
attr = "__active__"
if value in [True, False]:
setattr(self, attr, value)
return getattr(self, attr)
#property
def vertices(self):
"""Returns a simple list of calculated vertices"""
clsname = self.__class__.__name__
raise UnimplementedMethod(clsname)
#property
def dimension(self):
return len(self.point)
#property
def scaler(self):
attr = "__scaler__"
if not hasattr(self, attr):
size = self.SIZE / 2
setattr(self, attr, [size]*self.dimension)
return getattr(self, attr)
#scaler.setter
def scaler(self, *values):
attr = "__scaler__"
values = values[0] if len(values) == 1 else values
if len(values) == 1 and len(values) != self.point:
if isinstance(values, [int, float]):
setattr(self, attr, [values]*self.dimension)
elif isinstance(values, Iterable):
data = [(v, i)
for v, i in zip(values, xrange(self.dimension))]
value = [v for v, i in data]
if len(value) != self.dimension:
raise ValueError
setattr(self, attr, value)
#property
def translation(self):
attr = "__transalation__"
if not hasattr(self, attr):
size = self.SIZE / 2
setattr(self, attr, [size]*self.dimension)
return getattr(self, attr)
#translation.setter
def transalation(self, *values):
attr = "__transalation__"
values = values[0] if len(values) == 1 else values
if isinstance(values, (int, float)):
setattr(self, attr, [values]*self.dimension)
elif isinstance(values, Iterable):
data = [(v, i)
for v, i in zip(values, xrange(self.dimension))]
value = [v for v, i in data]
if len(value) != self.dimension:
raise ValueError
setattr(self, attr, value)
#property
def rotation(self):
"""
Rotation in radians
"""
attr = "__rotation__"
if not hasattr(self, attr):
setattr(self, attr, [0]*self.dimension)
return getattr(self, attr)
#rotation.setter
def rotation(self, *values):
"""
Rotation in radians
"""
attr = "__rotation__"
values = values[0] if len(values) == 1 else values
if isinstance(values, (int, float)):
setattr(self, attr, [values]*self.dimension)
elif isinstance(values, Iterable):
data = [(v, i)
for v, i in zip(values, xrange(self.dimension))]
value = [v for v, i in data]
if len(value) != self.dimension:
raise ValueError
setattr(self, attr, value)
#property
def volume(self):
clsname = self.__class__.__name__
raise UnimplementedMethod(clsname)
class Cube(Primative):
# G H
# * --------- *
# /| /|
# C / | D / |
# * --------- * |
# | * -------|- *
# | / E | / F
# |/ |/
# * --------- *
# A B
#property
def center_of_mass(self):
"""
Uses density to calculate center of mass
"""
return self.point
#property
def material(self):
clsname = self.__class__.__name__
raise UnimplementedMethod(clsname)
#material.setter
def material(self, value):
clsname = self.__class__.__name__
raise UnimplementedMethod(clsname)
#property
def mass(self):
return self.material.density * self.volume
#property
def volume(self):
func = operator.mul
return reduce(func, self.scaler, 1)
#property
def normals(self):
"""
computes the vertex normals
"""
norm = []
if len(self.point) == 1:
norm = [
# counter clockwise
# x (left hand rule)
(-1), # A
(1) # B
]
elif len(self.point) == 2:
norm = [
# counter clockwise
# x, y (left hand rule)
(-1, -1), # A
(1, -1), # B
(1, 1), # C
(-1, 1) # D
]
elif len(self.point) == 3:
norm = [
# counter clockwise
# x, y, z (left hand rule)
(-1, -1, 1), # A 0
(1, -1, 1), # B 1
(1, 1, 1), # D 2
(-1, 1, 1), # C 3
(-1, -1, -1), # E 4
(1, -1, -1), # F 5
(1, 1, -1), # H 6
(-1, 1, -1), # G 7
]
return norm
#property
def indices(self):
indices = []
if len(self.point) == 2:
indices = [
[[1, 0, 3], [2, 3, 1]], # BAC CDB front
]
elif len(self.point) == 3:
indices = [
[[1, 0, 3], [2, 3, 1]], # BAC CDB front
[[5, 1, 2], [2, 6, 5]], # FBD DHF right
[[4, 5, 6], [6, 7, 4]], # EFH HGE back
[[5, 4, 0], [0, 1, 5]], # FEA ABF bottom
[[0, 4, 7], [7, 3, 0]], # AEG GCA left
[[2, 3, 7], [7, 6, 2]], # DCG GHD top
]
return indices
#property
def nodes(self):
normals = np.array(self.normals, dtype=np.float32)
scaler = np.array(self.scaler, dtype=np.float32)
nodes = normals * scaler
return nodes.tolist()
#property
def vertices(self):
verts = (n for node in self.nodes for n in node)
return verts
And one more:
# Voxel.py
from collections import Iterable
from time import time
import numpy as np
import pyglet
from pyglet.gl import *
from primatives import Cube
import materials
class Voxel(Cube):
"""
Standard Voxel
"""
def __init__(self, point=None, material=None):
super(Voxel, self).__init__(point=point)
if isinstance(material, materials.Material):
self.material = material
else:
self.material = materials.stone
def __str__(self):
point = ", ".join(str(p) for p in self.point)
material = self.material.name
desc = "<Voxel [%s] (%s)>" % (material, point)
return desc
def __repr__(self):
point = ", ".join(str(p) for p in self.point)
material = self.material.name
desc = "<Voxel %s(%s)>" % (material, point)
return desc
#property
def material(self):
attr = "__material__"
if not hasattr(self, attr):
setattr(self, attr, materials.ether)
return getattr(self, attr)
#material.setter
def material(self, value):
attr = "__material__"
if value in materials.valid_materials:
setattr(self, attr, value)
return getattr(self, attr)
class Chunk(Cube):
"""
A Chunk contains a specified number of Voxels. Chunks are an
optimization to manage voxels which do not change often.
"""
NUMBER = 16
NUMBER_OF_VOXELS_X = NUMBER
NUMBER_OF_VOXELS_Y = NUMBER
NUMBER_OF_VOXELS_Z = NUMBER
def __init__(self, point=None):
point = (0, 0, 0) if point is None else point
super(Chunk, self).__init__(point=point)
self.batch = pyglet.graphics.Batch()
points = []
x_scale = self.NUMBER_OF_VOXELS_X / 2
y_scale = self.NUMBER_OF_VOXELS_Y / 2
z_scale = self.NUMBER_OF_VOXELS_Z / 2
self.rebuild_mesh = True
if len(point) == 1:
points = ((x,) for x in xrange(-x_scale, x_scale))
elif len(point) == 2:
points = ((x, y)
for x in xrange(-x_scale, x_scale)
for y in xrange(-y_scale, y_scale))
elif len(point) == 3:
points = ((x, y, z)
for x in xrange(-x_scale, x_scale)
for y in xrange(-y_scale, y_scale)
for z in xrange(-z_scale, z_scale))
t = time()
self.voxels = dict((point, Voxel(point)) for point in points)
self.active_voxels = dict((p, v)
for p, v in self.voxels.iteritems()
if v.active)
self.inactive_voxels = dict((p, v)
for p, v in self.voxels.iteritems()
if not v.active)
print 'Setup Time: %s' % (time() - t)
#property
def material(self):
return ether
#material.setter
def material(self, value):
if value in materials.valid_materials:
for voxel in self.voxels:
if voxel.material != value:
voxel.material = value
self.rebuild_mesh = True
#property
def mesh(self):
"""
Returns the verticies as defined by the Chunk's Voxels
"""
attr = "__mesh__"
if self.rebuild_mesh == True:
self.mesh_vert_count = 0
vertices = []
t = time()
for point, voxel in self.active_voxels.iteritems():
if voxel.active is True:
vertices.extend(voxel.vertices)
num_verts_in_voxel = len(voxel.normals)
self.mesh_vert_count += num_verts_in_voxel
print "Mesh Generation Time: %s" % time() - t
vertices = tuple(vertices)
setattr(self, attr, vertices)
voxel_count = len(self.active_voxels)
voxel_mesh = self.mesh
count = self.mesh_vert_count
group = None
data = ('v3f/static', vertices)
self.batch.add(count, self.mode, group, data)
return getattr(self, attr)
#property
def center_of_mass(self):
"""
Uses density to calculate center of mass. This is probably only
useful if the chunk represents an object.
"""
center = self.point
points = []
for point, voxel in self.active_voxels.iteritems():
mass = voxel.mass
if mass > 0:
point = [p*mass for p in point]
points.append(point)
points = np.array(points)
means = []
if points.any():
for idx, val in enumerate(self.point):
means.append(np.mean(points[:, idx]))
if means:
center = means
return center
def add(self, voxel):
added = False
point = None
if isinstance(voxel, Voxel):
point = voxel.point
elif isinstance(voxel, Iterable):
point = voxel
if point in self.inactive_voxels.iterkeys():
last = self.voxels[point]
self.voxels[point] = voxel if isinstance(voxel, Voxel) else last
self.voxels[point].active = True
self.active_voxels[point] = self.voxels[point]
self.inactive_voxels.pop(point)
added = True
self.rebuild_mesh = True
return added
def remove(self, voxel):
removed = False
point = None
if isinstance(voxel, Voxel):
point = voxel.point
elif isinstance(voxel, Iterable):
point = voxel
if point in self.active_voxels.iterkeys():
last = self.voxels[point]
self.voxels[point] = voxel if isinstance(voxel, Voxel) else last
self.voxels[point].active = False
self.inactive_voxels[point] = self.voxels[point]
self.active_voxels.pop(point)
removed = True
self.rebuild_mesh = True
return removed
def render(self):
voxels = len(self.active_voxels)
self.batch.draw()
return voxels
if __name__ == "__main__":
import pyglet
from pyglet.gl import *
class Window(pyglet.window.Window):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
vox_cnt = self.setup_scene()
print 'Added: %s voxels' % (vox_cnt)
def run(self):
"""wrapper to start the gui loop"""
pyglet.app.run()
def setup_scene(self):
self.chunk = Chunk()
cnt = 0
t = time()
for x in xrange(self.chunk.NUMBER_OF_VOXELS_X):
for y in xrange(self.chunk.NUMBER_OF_VOXELS_Y):
self.chunk.add((x, y))
cnt += 1
print "Setup Scene Time: %s" % (time() - t)
return cnt
def render_scene(self):
y = h = self.height
x = w = self.width
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
# glEnable(GL_DEPTH_TEST)
# glDepthFunc(GL_LESS)
t = time()
voxels_drawn = self.chunk.render()
print 'Render Time: %s' % (time() - t)
print 'Points Rendered %s' % voxels_drawn
# array_len = len(self.vertex_data)
# glDrawArrays(GL_TRIANGLES, 0, array_len)
def on_draw(self, *args, **kwargs):
self.render_scene()
w = Window()
w.run()
There are examples in the source distributions, if you download them (link to page).
The one you want to see is in <top-dir>/examples/opengl.py -- for a torus. If you make the following modifications you will have a cube.
# line 91:
cube.draw() # previously torus.draw()
# line 178: replace the line with the below (GL_TRIANGLES for GL_QUADS)
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, indices)
# line 187:
cube = Cube(0.8) # previously torus = Torus(1, 0.3, 50, 30)
# replace lines 125 through 166 with:
class Cube(object):
Vertices =(0.,0.,0., 1.,0.,0., 0.,0.,1., 1.,0.,1.,
0.,1.,0., 1.,1.,0., 0.,1.,1., 1.,1.,1.)
def __init__(self, scale):
# Create the vertex and normal arrays.
indices = [0,1,3,2, 1,5,7,3, 5,4,6,7,
0,2,6,4, 0,4,5,1, 2,3,7,6]
normals = [ 0.0, -1.0, 0.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
-1.0, 0.0, 0.0,
0.0, 0.0, -1.0,
0.0, 0.0, 1.0]
vertices = [scale * v for v in Cube.Vertices]
vertices = (GLfloat * len(vertices))(*vertices)
normals = (GLfloat * len(normals))(*normals)
I don't know about python's class wrappers and I did not do any graphics programming for quite some time. But I know that you should search for qualified answers about real workings and internals in the community of hardware guys who either create the VHDL GPU code or write low level drivers or so. They KNOW for sure how it works and some FAQ explanation should be available already in their community.
Based on that assumption this is what some Googling gave me to start with:
OpenGL 4.4 API Reference Card - page 7 - (available among top level resources on http://www.opengl.org) shows some simple picture (for 5 years old?) with the rendering pipeline split into
Blue blocks indicate various buffers that feed or get fed by the OpenGL pipeline
Green blocks indicate fixed function stages
Yellow blocks indicate programmable stages
Jarrred Walton's - Return of the DirectX vs. OpenGL Debates points to a 130-page slideshow How OpenGL Can Unlock 15x Performance Gains | NVIDIA Blog. Both articles fall into categories AMD,Intel,NVIDIA,Game Developer Converence
I have dome some simple OpenGL using C, C++, Delphi long ago and my recommendation is to get rid of the python mapping at first altogether. Look for suitable class library with good community with some good support only afterwards you know what you are looking for.
The above are IMHO the waters to start fishing in