diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..68859ad
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[pep8]
+max-line-length = 120
diff --git a/src/dialog_about.py b/src/dialog_about.py
index 303d64d..157527c 100644
--- a/src/dialog_about.py
+++ b/src/dialog_about.py
@@ -18,7 +18,9 @@
from ui_dialog_about import Ui_AboutDialog
from constants import ZOXEL_VERSION
+
class AboutDialog(QtGui.QDialog):
+
def __init__(self, parent=None):
# Initialise the UI
super(AboutDialog, self).__init__(parent)
diff --git a/src/dialog_resize.py b/src/dialog_resize.py
index 4c421ff..9e8795a 100644
--- a/src/dialog_resize.py
+++ b/src/dialog_resize.py
@@ -17,7 +17,9 @@
from PySide import QtGui
from ui_dialog_resize import Ui_ResizeDialog
+
class ResizeDialog(QtGui.QDialog):
+
def __init__(self, parent=None):
# Initialise the UI
super(ResizeDialog, self).__init__(parent)
@@ -26,7 +28,7 @@ def __init__(self, parent=None):
self.ui.button_auto.clicked.connect(self.on_button_auto_clicked)
def on_button_auto_clicked(self):
- _,_,_,x,y,z = self.parent().display.voxels.get_bounding_box()
+ _, _, _, x, y, z = self.parent().display.voxels.get_bounding_box()
self.ui.width.setValue(x)
self.ui.height.setValue(y)
self.ui.depth.setValue(z)
diff --git a/src/euclid.py b/src/euclid.py
index 74b4ddc..ecf3349 100644
--- a/src/euclid.py
+++ b/src/euclid.py
@@ -54,7 +54,10 @@
_use_slots = True
# Implement _use_slots magic.
+
+
class _EuclidMetaclass(type):
+
def __new__(cls, name, bases, dct):
if '__slots__' in dct:
dct['__getstate__'] = cls._create_getstate(dct['__slots__'])
@@ -84,6 +87,7 @@ def __setstate__(self, state):
__metaclass__ = _EuclidMetaclass
+
class Vector2:
__slots__ = ['x', 'y']
__hash__ = None
@@ -103,11 +107,11 @@ def __repr__(self):
def __eq__(self, other):
if isinstance(other, Vector2):
return self.x == other.x and \
- self.y == other.y
+ self.y == other.y
else:
assert hasattr(other, '__len__') and len(other) == 2
return self.x == other[0] and \
- self.y == other[1]
+ self.y == other[1]
def __ne__(self, other):
return not self.__eq__(other)
@@ -131,10 +135,10 @@ def __iter__(self):
def __getattr__(self, name):
try:
- return tuple([(self.x, self.y)['xy'.index(c)] \
+ return tuple([(self.x, self.y)['xy'.index(c)]
for c in name])
except ValueError:
- raise AttributeError, name
+ raise AttributeError(name)
if _enable_swizzle_set:
# This has detrimental performance on ordinary setattr as well
@@ -149,7 +153,7 @@ def __setattr__(self, name, value):
l['xy'.index(c)] = v
self.x, self.y = l
except ValueError:
- raise AttributeError, name
+ raise AttributeError(name)
def __add__(self, other):
if isinstance(other, Vector2):
@@ -193,7 +197,6 @@ def __sub__(self, other):
return Vector2(self.x - other[0],
self.y - other[1])
-
def __rsub__(self, other):
if isinstance(other, Vector2):
return Vector2(other.x - self.x,
@@ -221,7 +224,6 @@ def __div__(self, other):
return Vector2(operator.div(self.x, other),
operator.div(self.y, other))
-
def __rdiv__(self, other):
assert type(other) in (int, long, float)
return Vector2(operator.div(other, self.x),
@@ -232,7 +234,6 @@ def __floordiv__(self, other):
return Vector2(operator.floordiv(self.x, other),
operator.floordiv(self.y, other))
-
def __rfloordiv__(self, other):
assert type(other) in (int, long, float)
return Vector2(operator.floordiv(other, self.x),
@@ -243,7 +244,6 @@ def __truediv__(self, other):
return Vector2(operator.truediv(self.x, other),
operator.truediv(self.y, other))
-
def __rtruediv__(self, other):
assert type(other) in (int, long, float)
return Vector2(operator.truediv(other, self.x),
@@ -251,19 +251,19 @@ def __rtruediv__(self, other):
def __neg__(self):
return Vector2(-self.x,
- -self.y)
+ -self.y)
__pos__ = __copy__
def __abs__(self):
- return math.sqrt(self.x ** 2 + \
+ return math.sqrt(self.x ** 2 +
self.y ** 2)
magnitude = __abs__
def magnitude_squared(self):
return self.x ** 2 + \
- self.y ** 2
+ self.y ** 2
def normalize(self):
d = self.magnitude()
@@ -282,7 +282,7 @@ def normalized(self):
def dot(self, other):
assert isinstance(other, Vector2)
return self.x * other.x + \
- self.y * other.y
+ self.y * other.y
def cross(self):
return Vector2(self.y, -self.x)
@@ -296,12 +296,13 @@ def reflect(self, normal):
def angle(self, other):
"""Return the angle to the vector other"""
- return math.acos(self.dot(other) / (self.magnitude()*other.magnitude()))
+ return math.acos(self.dot(other) / (self.magnitude() * other.magnitude()))
def project(self, other):
"""Return one vector projected on the vector other"""
n = other.normalized()
- return self.dot(n)*n
+ return self.dot(n) * n
+
class Vector3:
__slots__ = ['x', 'y', 'z']
@@ -325,13 +326,13 @@ def __repr__(self):
def __eq__(self, other):
if isinstance(other, Vector3):
return self.x == other.x and \
- self.y == other.y and \
- self.z == other.z
+ self.y == other.y and \
+ self.z == other.z
else:
assert hasattr(other, '__len__') and len(other) == 3
return self.x == other[0] and \
- self.y == other[1] and \
- self.z == other[2]
+ self.y == other[1] and \
+ self.z == other[2]
def __ne__(self, other):
return not self.__eq__(other)
@@ -355,10 +356,10 @@ def __iter__(self):
def __getattr__(self, name):
try:
- return tuple([(self.x, self.y, self.z)['xyz'.index(c)] \
+ return tuple([(self.x, self.y, self.z)['xyz'.index(c)]
for c in name])
except ValueError:
- raise AttributeError, name
+ raise AttributeError(name)
if _enable_swizzle_set:
# This has detrimental performance on ordinary setattr as well
@@ -373,8 +374,7 @@ def __setattr__(self, name, value):
l['xyz'.index(c)] = v
self.x, self.y, self.z = l
except ValueError:
- raise AttributeError, name
-
+ raise AttributeError(name)
def __add__(self, other):
if isinstance(other, Vector3):
@@ -424,7 +424,6 @@ def __sub__(self, other):
self.y - other[1],
self.z - other[2])
-
def __rsub__(self, other):
if isinstance(other, Vector3):
return Vector3(other.x - self.x,
@@ -467,7 +466,6 @@ def __div__(self, other):
operator.div(self.y, other),
operator.div(self.z, other))
-
def __rdiv__(self, other):
assert type(other) in (int, long, float)
return Vector3(operator.div(other, self.x),
@@ -480,7 +478,6 @@ def __floordiv__(self, other):
operator.floordiv(self.y, other),
operator.floordiv(self.z, other))
-
def __rfloordiv__(self, other):
assert type(other) in (int, long, float)
return Vector3(operator.floordiv(other, self.x),
@@ -493,7 +490,6 @@ def __truediv__(self, other):
operator.truediv(self.y, other),
operator.truediv(self.z, other))
-
def __rtruediv__(self, other):
assert type(other) in (int, long, float)
return Vector3(operator.truediv(other, self.x),
@@ -502,22 +498,22 @@ def __rtruediv__(self, other):
def __neg__(self):
return Vector3(-self.x,
- -self.y,
- -self.z)
+ -self.y,
+ -self.z)
__pos__ = __copy__
def __abs__(self):
- return math.sqrt(self.x ** 2 + \
- self.y ** 2 + \
+ return math.sqrt(self.x ** 2 +
+ self.y ** 2 +
self.z ** 2)
magnitude = __abs__
def magnitude_squared(self):
return self.x ** 2 + \
- self.y ** 2 + \
- self.z ** 2
+ self.y ** 2 + \
+ self.z ** 2
def normalize(self):
d = self.magnitude()
@@ -538,8 +534,8 @@ def normalized(self):
def dot(self, other):
assert isinstance(other, Vector3)
return self.x * other.x + \
- self.y * other.y + \
- self.z * other.z
+ self.y * other.y + \
+ self.z * other.z
def cross(self, other):
assert isinstance(other, Vector3)
@@ -560,7 +556,7 @@ def rotate_around(self, axis, theta):
# Adapted from equations published by Glenn Murray.
# http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.html
- x, y, z = self.x, self.y,self.z
+ x, y, z = self.x, self.y, self.z
u, v, w = axis.x, axis.y, axis.z
# Extracted common factors for simplicity and efficiency
@@ -568,24 +564,25 @@ def rotate_around(self, axis, theta):
r = math.sqrt(r2)
ct = math.cos(theta)
st = math.sin(theta) / r
- dt = (u*x + v*y + w*z) * (1 - ct) / r2
+ dt = (u * x + v * y + w * z) * (1 - ct) / r2
return Vector3((u * dt + x * ct + (-w * y + v * z) * st),
- (v * dt + y * ct + ( w * x - u * z) * st),
+ (v * dt + y * ct + (w * x - u * z) * st),
(w * dt + z * ct + (-v * x + u * y) * st))
def angle(self, other):
"""Return the angle to the vector other"""
- return math.acos(self.dot(other) / (self.magnitude()*other.magnitude()))
+ return math.acos(self.dot(other) / (self.magnitude() * other.magnitude()))
def project(self, other):
"""Return one vector projected on the vector other"""
n = other.normalized()
- return self.dot(n)*n
+ return self.dot(n) * n
# a b c
# e f g
# i j k
+
class Matrix3:
__slots__ = list('abcefgijk')
@@ -606,13 +603,14 @@ def __copy__(self):
return M
copy = __copy__
+
def __repr__(self):
- return ('Matrix3([% 8.2f % 8.2f % 8.2f\n' \
- ' % 8.2f % 8.2f % 8.2f\n' \
+ return ('Matrix3([% 8.2f % 8.2f % 8.2f\n'
+ ' % 8.2f % 8.2f % 8.2f\n'
' % 8.2f % 8.2f % 8.2f])') \
- % (self.a, self.b, self.c,
- self.e, self.f, self.g,
- self.i, self.j, self.k)
+ % (self.a, self.b, self.c,
+ self.e, self.f, self.g,
+ self.i, self.j, self.k)
def __getitem__(self, key):
return [self.a, self.e, self.i,
@@ -758,12 +756,12 @@ def new_rotate(cls, angle):
new_rotate = classmethod(new_rotate)
def determinant(self):
- return (self.a*self.f*self.k
- + self.b*self.g*self.i
- + self.c*self.e*self.j
- - self.a*self.g*self.j
- - self.b*self.e*self.k
- - self.c*self.f*self.i)
+ return (self.a * self.f * self.k
+ + self.b * self.g * self.i
+ + self.c * self.e * self.j
+ - self.a * self.g * self.j
+ - self.b * self.e * self.k
+ - self.c * self.f * self.i)
def inverse(self):
tmp = Matrix3()
@@ -775,15 +773,15 @@ def inverse(self):
else:
d = 1.0 / d
- tmp.a = d * (self.f*self.k - self.g*self.j)
- tmp.b = d * (self.c*self.j - self.b*self.k)
- tmp.c = d * (self.b*self.g - self.c*self.f)
- tmp.e = d * (self.g*self.i - self.e*self.k)
- tmp.f = d * (self.a*self.k - self.c*self.i)
- tmp.g = d * (self.c*self.e - self.a*self.g)
- tmp.i = d * (self.e*self.j - self.f*self.i)
- tmp.j = d * (self.b*self.i - self.a*self.j)
- tmp.k = d * (self.a*self.f - self.b*self.e)
+ tmp.a = d * (self.f * self.k - self.g * self.j)
+ tmp.b = d * (self.c * self.j - self.b * self.k)
+ tmp.c = d * (self.b * self.g - self.c * self.f)
+ tmp.e = d * (self.g * self.i - self.e * self.k)
+ tmp.f = d * (self.a * self.k - self.c * self.i)
+ tmp.g = d * (self.c * self.e - self.a * self.g)
+ tmp.i = d * (self.e * self.j - self.f * self.i)
+ tmp.j = d * (self.b * self.i - self.a * self.j)
+ tmp.k = d * (self.a * self.f - self.b * self.e)
return tmp
@@ -792,6 +790,7 @@ def inverse(self):
# i j k l
# m n o p
+
class Matrix4:
__slots__ = list('abcdefghijklmnop')
@@ -820,16 +819,15 @@ def __copy__(self):
copy = __copy__
-
def __repr__(self):
- return ('Matrix4([% 8.2f % 8.2f % 8.2f % 8.2f\n' \
- ' % 8.2f % 8.2f % 8.2f % 8.2f\n' \
- ' % 8.2f % 8.2f % 8.2f % 8.2f\n' \
+ return ('Matrix4([% 8.2f % 8.2f % 8.2f % 8.2f\n'
+ ' % 8.2f % 8.2f % 8.2f % 8.2f\n'
+ ' % 8.2f % 8.2f % 8.2f % 8.2f\n'
' % 8.2f % 8.2f % 8.2f % 8.2f])') \
- % (self.a, self.b, self.c, self.d,
- self.e, self.f, self.g, self.h,
- self.i, self.j, self.k, self.l,
- self.m, self.n, self.o, self.p)
+ % (self.a, self.b, self.c, self.d,
+ self.e, self.f, self.g, self.h,
+ self.i, self.j, self.k, self.l,
+ self.m, self.n, self.o, self.p)
def __getitem__(self, key):
return [self.a, self.e, self.i, self.m,
@@ -979,7 +977,7 @@ def transform(self, other):
P.x = A.a * B.x + A.b * B.y + A.c * B.z + A.d
P.y = A.e * B.x + A.f * B.y + A.g * B.z + A.h
P.z = A.i * B.x + A.j * B.y + A.k * B.z + A.l
- w = A.m * B.x + A.n * B.y + A.o * B.z + A.p
+ w = A.m * B.x + A.n * B.y + A.o * B.z + A.p
if w != 0:
P.x /= w
P.y /= w
@@ -989,7 +987,7 @@ def transform(self, other):
def identity(self):
self.a = self.f = self.k = self.p = 1.
self.b = self.c = self.d = self.e = self.g = self.h = \
- self.i = self.j = self.l = self.m = self.n = self.o = 0
+ self.i = self.j = self.l = self.m = self.n = self.o = 0
return self
def scale(self, x, y, z):
@@ -1029,10 +1027,10 @@ def transpose(self):
self.b, self.f, self.j, self.n,
self.c, self.g, self.k, self.o,
self.d, self.h, self.l, self.p) = \
- (self.a, self.b, self.c, self.d,
- self.e, self.f, self.g, self.h,
- self.i, self.j, self.k, self.l,
- self.m, self.n, self.o, self.p)
+ (self.a, self.b, self.c, self.d,
+ self.e, self.f, self.g, self.h,
+ self.i, self.j, self.k, self.l,
+ self.m, self.n, self.o, self.p)
def transposed(self):
M = self.copy()
@@ -1145,23 +1143,23 @@ def new_rotate_euler(cls, heading, attitude, bank):
new_rotate_euler = classmethod(new_rotate_euler)
def new_rotate_triple_axis(cls, x, y, z):
- m = cls()
+ m = cls()
- m.a, m.b, m.c = x.x, y.x, z.x
- m.e, m.f, m.g = x.y, y.y, z.y
- m.i, m.j, m.k = x.z, y.z, z.z
+ m.a, m.b, m.c = x.x, y.x, z.x
+ m.e, m.f, m.g = x.y, y.y, z.y
+ m.i, m.j, m.k = x.z, y.z, z.z
- return m
+ return m
new_rotate_triple_axis = classmethod(new_rotate_triple_axis)
def new_look_at(cls, eye, at, up):
- z = (eye - at).normalized()
- x = up.cross(z).normalized()
- y = z.cross(x)
+ z = (eye - at).normalized()
+ x = up.cross(z).normalized()
+ y = z.cross(x)
- m = cls.new_rotate_triple_axis(x, y, z)
- m.d, m.h, m.l = eye.x, eye.y, eye.z
- return m
+ m = cls.new_rotate_triple_axis(x, y, z)
+ m.d, m.h, m.l = eye.x, eye.y, eye.z
+ return m
new_look_at = classmethod(new_look_at)
def new_perspective(cls, fov_y, aspect, near, far):
@@ -1180,49 +1178,65 @@ def new_perspective(cls, fov_y, aspect, near, far):
def determinant(self):
return ((self.a * self.f - self.e * self.b)
- * (self.k * self.p - self.o * self.l)
- - (self.a * self.j - self.i * self.b)
- * (self.g * self.p - self.o * self.h)
- + (self.a * self.n - self.m * self.b)
- * (self.g * self.l - self.k * self.h)
- + (self.e * self.j - self.i * self.f)
- * (self.c * self.p - self.o * self.d)
- - (self.e * self.n - self.m * self.f)
- * (self.c * self.l - self.k * self.d)
- + (self.i * self.n - self.m * self.j)
- * (self.c * self.h - self.g * self.d))
+ * (self.k * self.p - self.o * self.l)
+ - (self.a * self.j - self.i * self.b)
+ * (self.g * self.p - self.o * self.h)
+ + (self.a * self.n - self.m * self.b)
+ * (self.g * self.l - self.k * self.h)
+ + (self.e * self.j - self.i * self.f)
+ * (self.c * self.p - self.o * self.d)
+ - (self.e * self.n - self.m * self.f)
+ * (self.c * self.l - self.k * self.d)
+ + (self.i * self.n - self.m * self.j)
+ * (self.c * self.h - self.g * self.d))
def inverse(self):
tmp = Matrix4()
- d = self.determinant();
+ d = self.determinant()
if abs(d) < 0.001:
# No inverse, return identity
return tmp
else:
- d = 1.0 / d;
-
- tmp.a = d * (self.f * (self.k * self.p - self.o * self.l) + self.j * (self.o * self.h - self.g * self.p) + self.n * (self.g * self.l - self.k * self.h));
- tmp.e = d * (self.g * (self.i * self.p - self.m * self.l) + self.k * (self.m * self.h - self.e * self.p) + self.o * (self.e * self.l - self.i * self.h));
- tmp.i = d * (self.h * (self.i * self.n - self.m * self.j) + self.l * (self.m * self.f - self.e * self.n) + self.p * (self.e * self.j - self.i * self.f));
- tmp.m = d * (self.e * (self.n * self.k - self.j * self.o) + self.i * (self.f * self.o - self.n * self.g) + self.m * (self.j * self.g - self.f * self.k));
-
- tmp.b = d * (self.j * (self.c * self.p - self.o * self.d) + self.n * (self.k * self.d - self.c * self.l) + self.b * (self.o * self.l - self.k * self.p));
- tmp.f = d * (self.k * (self.a * self.p - self.m * self.d) + self.o * (self.i * self.d - self.a * self.l) + self.c * (self.m * self.l - self.i * self.p));
- tmp.j = d * (self.l * (self.a * self.n - self.m * self.b) + self.p * (self.i * self.b - self.a * self.j) + self.d * (self.m * self.j - self.i * self.n));
- tmp.n = d * (self.i * (self.n * self.c - self.b * self.o) + self.m * (self.b * self.k - self.j * self.c) + self.a * (self.j * self.o - self.n * self.k));
-
- tmp.c = d * (self.n * (self.c * self.h - self.g * self.d) + self.b * (self.g * self.p - self.o * self.h) + self.f * (self.o * self.d - self.c * self.p));
- tmp.g = d * (self.o * (self.a * self.h - self.e * self.d) + self.c * (self.e * self.p - self.m * self.h) + self.g * (self.m * self.d - self.a * self.p));
- tmp.k = d * (self.p * (self.a * self.f - self.e * self.b) + self.d * (self.e * self.n - self.m * self.f) + self.h * (self.m * self.b - self.a * self.n));
- tmp.o = d * (self.m * (self.f * self.c - self.b * self.g) + self.a * (self.n * self.g - self.f * self.o) + self.e * (self.b * self.o - self.n * self.c));
-
- tmp.d = d * (self.b * (self.k * self.h - self.g * self.l) + self.f * (self.c * self.l - self.k * self.d) + self.j * (self.g * self.d - self.c * self.h));
- tmp.h = d * (self.c * (self.i * self.h - self.e * self.l) + self.g * (self.a * self.l - self.i * self.d) + self.k * (self.e * self.d - self.a * self.h));
- tmp.l = d * (self.d * (self.i * self.f - self.e * self.j) + self.h * (self.a * self.j - self.i * self.b) + self.l * (self.e * self.b - self.a * self.f));
- tmp.p = d * (self.a * (self.f * self.k - self.j * self.g) + self.e * (self.j * self.c - self.b * self.k) + self.i * (self.b * self.g - self.f * self.c));
+ d = 1.0 / d
- return tmp;
+ tmp.a = d * (self.f * (self.k * self.p - self.o * self.l) + self.j * (self.o *
+ self.h - self.g * self.p) + self.n * (self.g * self.l - self.k * self.h))
+ tmp.e = d * (self.g * (self.i * self.p - self.m * self.l) + self.k * (self.m *
+ self.h - self.e * self.p) + self.o * (self.e * self.l - self.i * self.h))
+ tmp.i = d * (self.h * (self.i * self.n - self.m * self.j) + self.l * (self.m *
+ self.f - self.e * self.n) + self.p * (self.e * self.j - self.i * self.f))
+ tmp.m = d * (self.e * (self.n * self.k - self.j * self.o) + self.i * (self.f *
+ self.o - self.n * self.g) + self.m * (self.j * self.g - self.f * self.k))
+
+ tmp.b = d * (self.j * (self.c * self.p - self.o * self.d) + self.n * (self.k *
+ self.d - self.c * self.l) + self.b * (self.o * self.l - self.k * self.p))
+ tmp.f = d * (self.k * (self.a * self.p - self.m * self.d) + self.o * (self.i *
+ self.d - self.a * self.l) + self.c * (self.m * self.l - self.i * self.p))
+ tmp.j = d * (self.l * (self.a * self.n - self.m * self.b) + self.p * (self.i *
+ self.b - self.a * self.j) + self.d * (self.m * self.j - self.i * self.n))
+ tmp.n = d * (self.i * (self.n * self.c - self.b * self.o) + self.m * (self.b *
+ self.k - self.j * self.c) + self.a * (self.j * self.o - self.n * self.k))
+
+ tmp.c = d * (self.n * (self.c * self.h - self.g * self.d) + self.b * (self.g *
+ self.p - self.o * self.h) + self.f * (self.o * self.d - self.c * self.p))
+ tmp.g = d * (self.o * (self.a * self.h - self.e * self.d) + self.c * (self.e *
+ self.p - self.m * self.h) + self.g * (self.m * self.d - self.a * self.p))
+ tmp.k = d * (self.p * (self.a * self.f - self.e * self.b) + self.d * (self.e *
+ self.n - self.m * self.f) + self.h * (self.m * self.b - self.a * self.n))
+ tmp.o = d * (self.m * (self.f * self.c - self.b * self.g) + self.a * (self.n *
+ self.g - self.f * self.o) + self.e * (self.b * self.o - self.n * self.c))
+
+ tmp.d = d * (self.b * (self.k * self.h - self.g * self.l) + self.f * (self.c *
+ self.l - self.k * self.d) + self.j * (self.g * self.d - self.c * self.h))
+ tmp.h = d * (self.c * (self.i * self.h - self.e * self.l) + self.g * (self.a *
+ self.l - self.i * self.d) + self.k * (self.e * self.d - self.a * self.h))
+ tmp.l = d * (self.d * (self.i * self.f - self.e * self.j) + self.h * (self.a *
+ self.j - self.i * self.b) + self.l * (self.e * self.b - self.a * self.f))
+ tmp.p = d * (self.a * (self.f * self.k - self.j * self.g) + self.e * (self.j *
+ self.c - self.b * self.k) + self.i * (self.b * self.g - self.f * self.c))
+
+ return tmp
class Quaternion:
@@ -1263,9 +1277,9 @@ def __mul__(self, other):
Bz = other.z
Bw = other.w
Q = Quaternion()
- Q.x = Ax * Bw + Ay * Bz - Az * By + Aw * Bx
+ Q.x = Ax * Bw + Ay * Bz - Az * By + Aw * Bx
Q.y = -Ax * Bz + Ay * Bw + Az * Bx + Aw * By
- Q.z = Ax * By - Ay * Bx + Az * Bw + Aw * Bz
+ Q.z = Ax * By - Ay * Bx + Az * Bw + Aw * Bz
Q.w = -Ax * Bx - Ay * By - Az * Bz + Aw * Bw
return Q
elif isinstance(other, Vector3):
@@ -1288,16 +1302,16 @@ def __mul__(self, other):
yy = y * y
yz2 = 2 * y * z
zz = z * z
- return other.__class__(\
- ww * Vx + wy2 * Vz - wz2 * Vy + \
- xx * Vx + xy2 * Vy + xz2 * Vz - \
- zz * Vx - yy * Vx,
- xy2 * Vx + yy * Vy + yz2 * Vz + \
- wz2 * Vx - zz * Vy + ww * Vy - \
- wx2 * Vz - xx * Vy,
- xz2 * Vx + yz2 * Vy + \
- zz * Vz - wy2 * Vx - yy * Vz + \
- wx2 * Vy - xx * Vz + ww * Vz)
+ return other.__class__(
+ ww * Vx + wy2 * Vz - wz2 * Vy +
+ xx * Vx + xy2 * Vy + xz2 * Vz -
+ zz * Vx - yy * Vx,
+ xy2 * Vx + yy * Vy + yz2 * Vz +
+ wz2 * Vx - zz * Vy + ww * Vy -
+ wx2 * Vz - xx * Vy,
+ xz2 * Vx + yz2 * Vy +
+ zz * Vz - wy2 * Vx - yy * Vz +
+ wx2 * Vy - xx * Vz + ww * Vz)
else:
other = other.copy()
other._apply_transform(self)
@@ -1313,25 +1327,25 @@ def __imul__(self, other):
By = other.y
Bz = other.z
Bw = other.w
- self.x = Ax * Bw + Ay * Bz - Az * By + Aw * Bx
+ self.x = Ax * Bw + Ay * Bz - Az * By + Aw * Bx
self.y = -Ax * Bz + Ay * Bw + Az * Bx + Aw * By
- self.z = Ax * By - Ay * Bx + Az * Bw + Aw * Bz
+ self.z = Ax * By - Ay * Bx + Az * Bw + Aw * Bz
self.w = -Ax * Bx - Ay * By - Az * Bz + Aw * Bw
return self
def __abs__(self):
- return math.sqrt(self.w ** 2 + \
- self.x ** 2 + \
- self.y ** 2 + \
+ return math.sqrt(self.w ** 2 +
+ self.x ** 2 +
+ self.y ** 2 +
self.z ** 2)
magnitude = __abs__
def magnitude_squared(self):
return self.w ** 2 + \
- self.x ** 2 + \
- self.y ** 2 + \
- self.z ** 2
+ self.x ** 2 + \
+ self.y ** 2 + \
+ self.z ** 2
def identity(self):
self.w = 1
@@ -1468,49 +1482,49 @@ def new_rotate_euler(cls, heading, attitude, bank):
new_rotate_euler = classmethod(new_rotate_euler)
def new_rotate_matrix(cls, m):
- if m[0*4 + 0] + m[1*4 + 1] + m[2*4 + 2] > 0.00000001:
- t = m[0*4 + 0] + m[1*4 + 1] + m[2*4 + 2] + 1.0
- s = 0.5/math.sqrt(t)
-
- return cls(
- s*t,
- (m[1*4 + 2] - m[2*4 + 1])*s,
- (m[2*4 + 0] - m[0*4 + 2])*s,
- (m[0*4 + 1] - m[1*4 + 0])*s
- )
-
- elif m[0*4 + 0] > m[1*4 + 1] and m[0*4 + 0] > m[2*4 + 2]:
- t = m[0*4 + 0] - m[1*4 + 1] - m[2*4 + 2] + 1.0
- s = 0.5/math.sqrt(t)
-
- return cls(
- (m[1*4 + 2] - m[2*4 + 1])*s,
- s*t,
- (m[0*4 + 1] + m[1*4 + 0])*s,
- (m[2*4 + 0] + m[0*4 + 2])*s
- )
-
- elif m[1*4 + 1] > m[2*4 + 2]:
- t = -m[0*4 + 0] + m[1*4 + 1] - m[2*4 + 2] + 1.0
- s = 0.5/math.sqrt(t)
-
- return cls(
- (m[2*4 + 0] - m[0*4 + 2])*s,
- (m[0*4 + 1] + m[1*4 + 0])*s,
- s*t,
- (m[1*4 + 2] + m[2*4 + 1])*s
- )
-
- else:
- t = -m[0*4 + 0] - m[1*4 + 1] + m[2*4 + 2] + 1.0
- s = 0.5/math.sqrt(t)
-
- return cls(
- (m[0*4 + 1] - m[1*4 + 0])*s,
- (m[2*4 + 0] + m[0*4 + 2])*s,
- (m[1*4 + 2] + m[2*4 + 1])*s,
- s*t
- )
+ if m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] > 0.00000001:
+ t = m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0
+ s = 0.5 / math.sqrt(t)
+
+ return cls(
+ s * t,
+ (m[1 * 4 + 2] - m[2 * 4 + 1]) * s,
+ (m[2 * 4 + 0] - m[0 * 4 + 2]) * s,
+ (m[0 * 4 + 1] - m[1 * 4 + 0]) * s
+ )
+
+ elif m[0 * 4 + 0] > m[1 * 4 + 1] and m[0 * 4 + 0] > m[2 * 4 + 2]:
+ t = m[0 * 4 + 0] - m[1 * 4 + 1] - m[2 * 4 + 2] + 1.0
+ s = 0.5 / math.sqrt(t)
+
+ return cls(
+ (m[1 * 4 + 2] - m[2 * 4 + 1]) * s,
+ s * t,
+ (m[0 * 4 + 1] + m[1 * 4 + 0]) * s,
+ (m[2 * 4 + 0] + m[0 * 4 + 2]) * s
+ )
+
+ elif m[1 * 4 + 1] > m[2 * 4 + 2]:
+ t = -m[0 * 4 + 0] + m[1 * 4 + 1] - m[2 * 4 + 2] + 1.0
+ s = 0.5 / math.sqrt(t)
+
+ return cls(
+ (m[2 * 4 + 0] - m[0 * 4 + 2]) * s,
+ (m[0 * 4 + 1] + m[1 * 4 + 0]) * s,
+ s * t,
+ (m[1 * 4 + 2] + m[2 * 4 + 1]) * s
+ )
+
+ else:
+ t = -m[0 * 4 + 0] - m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0
+ s = 0.5 / math.sqrt(t)
+
+ return cls(
+ (m[0 * 4 + 1] - m[1 * 4 + 0]) * s,
+ (m[2 * 4 + 0] + m[0 * 4 + 2]) * s,
+ (m[1 * 4 + 2] + m[2 * 4 + 1]) * s,
+ s * t
+ )
new_rotate_matrix = classmethod(new_rotate_matrix)
def new_interpolate(cls, q1, q2, t):
@@ -1554,14 +1568,16 @@ def new_interpolate(cls, q1, q2, t):
# Much maths thanks to Paul Bourke, http://astronomy.swin.edu.au/~pbourke
# ---------------------------------------------------------------------------
+
class Geometry:
+
def _connect_unimplemented(self, other):
- raise AttributeError, 'Cannot connect %s to %s' % \
- (self.__class__, other.__class__)
+ raise AttributeError('Cannot connect %s to %s' %
+ (self.__class__, other.__class__))
def _intersect_unimplemented(self, other):
- raise AttributeError, 'Cannot intersect %s and %s' % \
- (self.__class__, other.__class__)
+ raise AttributeError('Cannot intersect %s and %s' %
+ (self.__class__, other.__class__))
_intersect_point2 = _intersect_unimplemented
_intersect_line2 = _intersect_unimplemented
@@ -1591,9 +1607,11 @@ def distance(self, other):
return c.length
return 0.0
+
def _intersect_point2_circle(P, C):
return abs(P - C.c) <= C.r
+
def _intersect_line2_line2(A, B):
d = B.v.y * A.v.x - B.v.x * A.v.y
if d == 0:
@@ -1611,9 +1629,10 @@ def _intersect_line2_line2(A, B):
return Point2(A.p.x + ua * A.v.x,
A.p.y + ua * A.v.y)
+
def _intersect_line2_circle(L, C):
a = L.v.magnitude_squared()
- b = 2 * (L.v.x * (L.p.x - C.c.x) + \
+ b = 2 * (L.v.x * (L.p.x - C.c.x) +
L.v.y * (L.p.y - C.c.y))
c = C.c.magnitude_squared() + \
L.p.magnitude_squared() - \
@@ -1640,10 +1659,11 @@ def _intersect_line2_circle(L, C):
Point2(L.p.x + u2 * L.v.x,
L.p.y + u2 * L.v.y))
+
def _connect_point2_line2(P, L):
d = L.v.magnitude_squared()
assert d != 0
- u = ((P.x - L.p.x) * L.v.x + \
+ u = ((P.x - L.p.x) * L.v.x +
(P.y - L.p.y) * L.v.y) / d
if not L._u_in(u):
u = max(min(u, 1.0), 0.0)
@@ -1651,12 +1671,14 @@ def _connect_point2_line2(P, L):
Point2(L.p.x + u * L.v.x,
L.p.y + u * L.v.y))
+
def _connect_point2_circle(P, C):
v = P - C.c
v.normalize()
v *= C.r
return LineSegment2(P, Point2(C.c.x + v.x, C.c.y + v.y))
+
def _connect_line2_line2(A, B):
d = B.v.y * A.v.x - B.v.x * A.v.y
if d == 0:
@@ -1680,6 +1702,7 @@ def _connect_line2_line2(A, B):
return LineSegment2(Point2(A.p.x + ua * A.v.x, A.p.y + ua * A.v.y),
Point2(B.p.x + ub * B.v.x, B.p.y + ub * B.v.y))
+
def _connect_circle_line2(C, L):
d = L.v.magnitude_squared()
assert d != 0
@@ -1692,23 +1715,25 @@ def _connect_circle_line2(C, L):
v *= C.r
return LineSegment2(Point2(C.c.x + v.x, C.c.y + v.y), point)
+
def _connect_circle_circle(A, B):
v = B.c - A.c
d = v.magnitude()
if A.r >= B.r and d < A.r:
- #centre B inside A
- s1,s2 = +1, +1
+ # centre B inside A
+ s1, s2 = +1, +1
elif B.r > A.r and d < B.r:
- #centre A inside B
- s1,s2 = -1, -1
+ # centre A inside B
+ s1, s2 = -1, -1
elif d >= A.r and d >= B.r:
- s1,s2 = +1, -1
+ s1, s2 = +1, -1
v.normalize()
return LineSegment2(Point2(A.c.x + s1 * v.x * A.r, A.c.y + s1 * v.y * A.r),
Point2(B.c.x + s2 * v.x * B.r, B.c.y + s2 * v.y * B.r))
class Point2(Vector2, Geometry):
+
def __repr__(self):
return 'Point2(%.2f, %.2f)' % (self.x, self.y)
@@ -1734,14 +1759,15 @@ def _connect_circle(self, other):
if c:
return c._swap()
+
class Line2(Geometry):
__slots__ = ['p', 'v']
def __init__(self, *args):
if len(args) == 3:
assert isinstance(args[0], Point2) and \
- isinstance(args[1], Vector2) and \
- type(args[2]) == float
+ isinstance(args[1], Vector2) and \
+ type(args[2]) == float
self.p = args[0].copy()
self.v = args[1] * args[2] / abs(args[1])
elif len(args) == 2:
@@ -1752,18 +1778,18 @@ def __init__(self, *args):
self.p = args[0].copy()
self.v = args[1].copy()
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
elif len(args) == 1:
if isinstance(args[0], Line2):
self.p = args[0].p.copy()
self.v = args[0].v.copy()
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
if not self.v:
- raise AttributeError, 'Line has zero-length vector'
+ raise AttributeError('Line has zero-length vector')
def __copy__(self):
return self.__class__(self.p, self.v)
@@ -1806,7 +1832,9 @@ def _connect_line2(self, other):
def _connect_circle(self, other):
return _connect_circle_line2(other, self)
+
class Ray2(Line2):
+
def __repr__(self):
return 'Ray2(<%.2f, %.2f> + u<%.2f, %.2f>)' % \
(self.p.x, self.p.y, self.v.x, self.v.y)
@@ -1814,7 +1842,9 @@ def __repr__(self):
def _u_in(self, u):
return u >= 0.0
+
class LineSegment2(Line2):
+
def __repr__(self):
return 'LineSegment2(<%.2f, %.2f> to <%.2f, %.2f>)' % \
(self.p.x, self.p.y, self.p.x + self.v.x, self.p.y + self.v.y)
@@ -1836,6 +1866,7 @@ def _swap(self):
length = property(lambda self: abs(self.v))
+
class Circle(Geometry):
__slots__ = ['c', 'r']
@@ -1882,11 +1913,12 @@ def _connect_circle(self, other):
# 3D Geometry
# -------------------------------------------------------------------------
+
def _connect_point3_line3(P, L):
d = L.v.magnitude_squared()
assert d != 0
- u = ((P.x - L.p.x) * L.v.x + \
- (P.y - L.p.y) * L.v.y + \
+ u = ((P.x - L.p.x) * L.v.x +
+ (P.y - L.p.y) * L.v.y +
(P.z - L.p.z) * L.v.z) / d
if not L._u_in(u):
u = max(min(u, 1.0), 0.0)
@@ -1894,17 +1926,20 @@ def _connect_point3_line3(P, L):
L.p.y + u * L.v.y,
L.p.z + u * L.v.z))
+
def _connect_point3_sphere(P, S):
v = P - S.c
v.normalize()
v *= S.r
return LineSegment3(P, Point3(S.c.x + v.x, S.c.y + v.y, S.c.z + v.z))
+
def _connect_point3_plane(p, plane):
n = plane.n.normalized()
d = p.dot(plane.n) - plane.k
return LineSegment3(p, Point3(p.x - n.x * d, p.y - n.y * d, p.z - n.z * d))
+
def _connect_line3_line3(A, B):
assert A.v and B.v
p13 = A.p - B.p
@@ -1934,6 +1969,7 @@ def _connect_line3_line3(A, B):
B.p.y + ub * B.v.y,
B.p.z + ub * B.v.z))
+
def _connect_line3_plane(L, P):
d = P.n.dot(L.v)
if not d:
@@ -1949,11 +1985,12 @@ def _connect_line3_plane(L, P):
# Intersection
return None
+
def _connect_sphere_line3(S, L):
d = L.v.magnitude_squared()
assert d != 0
- u = ((S.c.x - L.p.x) * L.v.x + \
- (S.c.y - L.p.y) * L.v.y + \
+ u = ((S.c.x - L.p.x) * L.v.x +
+ (S.c.y - L.p.y) * L.v.y +
(S.c.z - L.p.z) * L.v.z) / d
if not L._u_in(u):
u = max(min(u, 1.0), 0.0)
@@ -1964,25 +2001,27 @@ def _connect_sphere_line3(S, L):
return LineSegment3(Point3(S.c.x + v.x, S.c.y + v.y, S.c.z + v.z),
point)
+
def _connect_sphere_sphere(A, B):
v = B.c - A.c
d = v.magnitude()
if A.r >= B.r and d < A.r:
- #centre B inside A
- s1,s2 = +1, +1
+ # centre B inside A
+ s1, s2 = +1, +1
elif B.r > A.r and d < B.r:
- #centre A inside B
- s1,s2 = -1, -1
+ # centre A inside B
+ s1, s2 = -1, -1
elif d >= A.r and d >= B.r:
- s1,s2 = +1, -1
+ s1, s2 = +1, -1
v.normalize()
- return LineSegment3(Point3(A.c.x + s1* v.x * A.r,
- A.c.y + s1* v.y * A.r,
- A.c.z + s1* v.z * A.r),
- Point3(B.c.x + s2* v.x * B.r,
- B.c.y + s2* v.y * B.r,
- B.c.z + s2* v.z * B.r))
+ return LineSegment3(Point3(A.c.x + s1 * v.x * A.r,
+ A.c.y + s1 * v.y * A.r,
+ A.c.z + s1 * v.z * A.r),
+ Point3(B.c.x + s2 * v.x * B.r,
+ B.c.y + s2 * v.y * B.r,
+ B.c.z + s2 * v.z * B.r))
+
def _connect_sphere_plane(S, P):
c = _connect_point3_plane(S.c, P)
@@ -1995,6 +2034,7 @@ def _connect_sphere_plane(S, P):
return LineSegment3(Point3(S.c.x + v.x, S.c.y + v.y, S.c.z + v.z),
p2)
+
def _connect_plane_plane(A, B):
if A.n.cross(B.n):
# Planes intersect
@@ -2003,13 +2043,15 @@ def _connect_plane_plane(A, B):
# Planes are parallel, connect to arbitrary point
return _connect_point3_plane(A._get_point(), B)
+
def _intersect_point3_sphere(P, S):
return abs(P - S.c) <= S.r
+
def _intersect_line3_sphere(L, S):
a = L.v.magnitude_squared()
- b = 2 * (L.v.x * (L.p.x - S.c.x) + \
- L.v.y * (L.p.y - S.c.y) + \
+ b = 2 * (L.v.x * (L.p.x - S.c.x) +
+ L.v.y * (L.p.y - S.c.y) +
L.v.z * (L.p.z - S.c.z))
c = S.c.magnitude_squared() + \
L.p.magnitude_squared() - \
@@ -2032,6 +2074,7 @@ def _intersect_line3_sphere(L, S):
L.p.y + u2 * L.v.y,
L.p.z + u2 * L.v.z))
+
def _intersect_line3_plane(L, P):
d = P.n.dot(L.v)
if not d:
@@ -2044,6 +2087,7 @@ def _intersect_line3_plane(L, P):
L.p.y + u * L.v.y,
L.p.z + u * L.v.z)
+
def _intersect_plane_plane(A, B):
n1_m = A.n.magnitude_squared()
n2_m = B.n.magnitude_squared()
@@ -2059,7 +2103,9 @@ def _intersect_plane_plane(A, B):
c1 * A.n.z + c2 * B.n.z),
A.n.cross(B.n))
+
class Point3(Vector3, Geometry):
+
def __repr__(self):
return 'Point3(%.2f, %.2f, %.2f)' % (self.x, self.y, self.z)
@@ -2092,14 +2138,15 @@ def _connect_plane(self, other):
if c:
return c._swap()
+
class Line3:
__slots__ = ['p', 'v']
def __init__(self, *args):
if len(args) == 3:
assert isinstance(args[0], Point3) and \
- isinstance(args[1], Vector3) and \
- type(args[2]) == float
+ isinstance(args[1], Vector3) and \
+ type(args[2]) == float
self.p = args[0].copy()
self.v = args[1] * args[2] / abs(args[1])
elif len(args) == 2:
@@ -2110,18 +2157,18 @@ def __init__(self, *args):
self.p = args[0].copy()
self.v = args[1].copy()
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
elif len(args) == 1:
if isinstance(args[0], Line3):
self.p = args[0].p.copy()
self.v = args[0].v.copy()
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
# XXX This is annoying.
- #if not self.v:
+ # if not self.v:
# raise AttributeError, 'Line has zero-length vector'
def __copy__(self):
@@ -2171,7 +2218,9 @@ def _connect_plane(self, other):
if c:
return c
+
class Ray3(Line3):
+
def __repr__(self):
return 'Ray3(<%.2f, %.2f, %.2f> + u<%.2f, %.2f, %.2f>)' % \
(self.p.x, self.p.y, self.p.z, self.v.x, self.v.y, self.v.z)
@@ -2179,7 +2228,9 @@ def __repr__(self):
def _u_in(self, u):
return u >= 0.0
+
class LineSegment3(Line3):
+
def __repr__(self):
return 'LineSegment3(<%.2f, %.2f, %.2f> to <%.2f, %.2f, %.2f>)' % \
(self.p.x, self.p.y, self.p.z,
@@ -2202,6 +2253,7 @@ def _swap(self):
length = property(lambda self: abs(self.v))
+
class Sphere:
__slots__ = ['c', 'r']
@@ -2250,6 +2302,7 @@ def _connect_plane(self, other):
if c:
return c
+
class Plane:
# n.p = k, where n is normal, p is point on plane, k is constant scalar
__slots__ = ['n', 'k']
@@ -2257,8 +2310,8 @@ class Plane:
def __init__(self, *args):
if len(args) == 3:
assert isinstance(args[0], Point3) and \
- isinstance(args[1], Point3) and \
- isinstance(args[2], Point3)
+ isinstance(args[1], Point3) and \
+ isinstance(args[2], Point3)
self.n = (args[1] - args[0]).cross(args[2] - args[0])
self.n.normalize()
self.k = self.n.dot(args[0])
@@ -2270,13 +2323,13 @@ def __init__(self, *args):
self.n = args[0].normalized()
self.k = args[1]
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
else:
- raise AttributeError, '%r' % (args,)
+ raise AttributeError('%r' % (args,))
if not self.n:
- raise AttributeError, 'Points on plane are colinear'
+ raise AttributeError('Points on plane are colinear')
def __copy__(self):
return self.__class__(self.n, self.k)
diff --git a/src/mainwindow.py b/src/mainwindow.py
index 342dacf..fa835a3 100644
--- a/src/mainwindow.py
+++ b/src/mainwindow.py
@@ -29,6 +29,7 @@
import sys
from constants import ZOXEL_TAG
+
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
@@ -50,7 +51,7 @@ def __init__(self, parent=None):
# Our animation timer
self._timer = QtCore.QTimer(self)
self.connect(self._timer, QtCore.SIGNAL("timeout()"),
- self.on_animation_tick)
+ self.on_animation_tick)
self._anim_speed = 200
# Load our state if possible
self.load_state()
@@ -61,7 +62,7 @@ def __init__(self, parent=None):
self.display = voxels
except Exception as E:
QtGui.QMessageBox.warning(self, "Initialisation Failed",
- str(E))
+ str(E))
exit(1)
# Load default model dimensions
width = self.get_setting("default_model_width")
@@ -114,9 +115,9 @@ def __init__(self, parent=None):
latest_tag = urllib.urlopen("https://github.com/chrmoritz/zoxel/releases/latest").geturl()
if not latest_tag.endswith(ZOXEL_TAG):
responce = QtGui.QMessageBox.question(self, "Outdated Zoxel version",
- "A new version of Zoxel is available! Do you want to update now?",
- buttons = (QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
- defaultButton = QtGui.QMessageBox.Yes)
+ "A new version of Zoxel is available! Do you want to update now?",
+ buttons=(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No),
+ defaultButton=QtGui.QMessageBox.Yes)
if responce == QtGui.QMessageBox.Yes:
webbrowser.open(latest_tag, 2)
sys.exit(0)
@@ -212,7 +213,7 @@ def resize_voxels(self, width, height, depth):
new_height_scale = float(height) / self.display.voxels.height
new_depth_scale = float(depth) / self.display.voxels.depth
self.display.voxels.resize(width, height, depth)
- self.display.grids.scale_offsets( new_width_scale, new_height_scale, new_depth_scale )
+ self.display.grids.scale_offsets(new_width_scale, new_height_scale, new_depth_scale)
self.display.refresh()
# Remember these dimensions
self.set_setting("default_model_width", width)
@@ -240,7 +241,8 @@ def on_action_background_triggered(self):
@QtCore.Slot()
def on_action_anim_add_triggered(self):
- value, res = QtGui.QInputDialog.getInt(self, "Add frame", "Add new frame after:", self.display.voxels.get_frame_number()+1, 1, self.display.voxels.get_frame_count())
+ value, res = QtGui.QInputDialog.getInt(self, "Add frame", "Add new frame after:", self.display.voxels.get_frame_number(
+ ) + 1, 1, self.display.voxels.get_frame_count())
if res:
self.display.voxels.add_frame(value, True)
self.display.refresh()
@@ -248,7 +250,8 @@ def on_action_anim_add_triggered(self):
@QtCore.Slot()
def on_action_anim_add_empty_triggered(self):
- value, res = QtGui.QInputDialog.getInt(self, "Add frame", "Add new frame after:", self.display.voxels.get_frame_number()+1, 1, self.display.voxels.get_frame_count())
+ value, res = QtGui.QInputDialog.getInt(self, "Add frame", "Add new frame after:", self.display.voxels.get_frame_number(
+ ) + 1, 1, self.display.voxels.get_frame_count())
if res:
self.display.voxels.add_frame(value, False)
self.display.refresh()
@@ -256,7 +259,8 @@ def on_action_anim_add_empty_triggered(self):
@QtCore.Slot()
def on_action_anim_copy_triggered(self):
- value, res = QtGui.QInputDialog.getInt(self, "Copy frame", "Replace current frame with:", 1, 1, self.display.voxels.get_frame_count())
+ value, res = QtGui.QInputDialog.getInt(
+ self, "Copy frame", "Replace current frame with:", 1, 1, self.display.voxels.get_frame_count())
if res:
self.display.voxels.copy_to_current(value)
self.display.refresh()
@@ -264,7 +268,8 @@ def on_action_anim_copy_triggered(self):
@QtCore.Slot()
def on_action_anim_delete_triggered(self):
- ret = QtGui.QMessageBox.question(self, "Zoxel", "Do you really want to delete this frame?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
+ ret = QtGui.QMessageBox.question(
+ self, "Zoxel", "Do you really want to delete this frame?", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
if (ret == QtGui.QMessageBox.Yes):
self.display.voxels.delete_frame()
self.display.refresh()
@@ -349,9 +354,9 @@ def on_action_export_image_triggered(self):
directory = self.get_setting("default_directory")
# grab a filename
filename, filetype = QtGui.QFileDialog.getSaveFileName(self,
- caption = "Export Image As",
- filter = choices,
- dir = directory)
+ caption="Export Image As",
+ filter=choices,
+ dir=directory)
if not filename:
return
@@ -360,7 +365,7 @@ def on_action_export_image_triggered(self):
self.set_setting("default_directory", directory)
# Save the PNG
- png.save(filename,filetype.split()[0])
+ png.save(filename, filetype.split()[0])
@QtCore.Slot()
def on_action_export_troxel_triggered(self):
@@ -399,10 +404,10 @@ def on_tool_drag_end(self):
# Confirm if user wants to save before doing something drastic.
# returns True if we should continue
def confirm_save(self):
- responce = QtGui.QMessageBox.question(self,"Save changes?",
- "Save changes before discarding?",
- buttons = (QtGui.QMessageBox.Save | QtGui.QMessageBox.Cancel
- | QtGui.QMessageBox.No))
+ responce = QtGui.QMessageBox.question(self, "Save changes?",
+ "Save changes before discarding?",
+ buttons=(QtGui.QMessageBox.Save | QtGui.QMessageBox.Cancel
+ | QtGui.QMessageBox.No))
if responce == QtGui.QMessageBox.StandardButton.Save:
if not self.save():
return False
@@ -469,7 +474,7 @@ def update_caption(self):
if self.display and self.display.voxels.changed:
caption += " *"
numframes = self.display.voxels.get_frame_count()
- frame = self.display.voxels.get_frame_number()+1
+ frame = self.display.voxels.get_frame_number() + 1
if numframes > 1:
caption += " - Frame {0} of {1}".format(frame, numframes)
if caption != self._caption:
@@ -477,7 +482,7 @@ def update_caption(self):
self._caption = caption
# Save the current data
- def save(self, newfile = False):
+ def save(self, newfile=False):
# Find the handlers that support saving
handlers = [x for x in self._file_handlers if hasattr(x, 'save')]
@@ -491,7 +496,7 @@ def save(self, newfile = False):
# Build list of available types
choices = []
for exporter in handlers:
- choices.append( "%s (%s)" % (exporter.description, exporter.filetype))
+ choices.append("%s (%s)" % (exporter.description, exporter.filetype))
choices = ";;".join(choices)
# Grab our default location
@@ -500,10 +505,10 @@ def save(self, newfile = False):
# Get a filename if we need one
if newfile or not filename:
filename, filetype = QtGui.QFileDialog.getSaveFileName(self,
- caption = "Save As",
- filter = choices,
- dir = directory,
- selectedFilter="Zoxel Files (*.zox)")
+ caption="Save As",
+ filter=choices,
+ dir=directory,
+ selectedFilter="Zoxel Files (*.zox)")
if not filename:
return
handler = None
@@ -517,7 +522,7 @@ def save(self, newfile = False):
for exporter in handlers:
ourtype = "%s (%s)" % (exporter.description, exporter.filetype)
if filetype == ourtype:
- handler = exporter
+ handler = exporter
# Call the save handler
try:
@@ -525,7 +530,7 @@ def save(self, newfile = False):
saved = True
except Exception as Ex:
QtGui.QMessageBox.warning(self, "Save Failed",
- str(Ex))
+ str(Ex))
# If we saved, clear edited state
if saved:
@@ -554,7 +559,7 @@ def load(self):
# Build list of types we can load
choices = ["All Files (*)"]
for importer in handlers:
- choices.append( "%s (%s)" % (importer.description, importer.filetype))
+ choices.append("%s (%s)" % (importer.description, importer.filetype))
choices = ";;".join(choices)
# Grab our default location
@@ -562,10 +567,10 @@ def load(self):
# Get a filename
filename, filetype = QtGui.QFileDialog.getOpenFileName(self,
- caption="Open file",
- filter=choices,
- dir = directory,
- selectedFilter="All Files (*)")
+ caption="Open file",
+ filter=choices,
+ dir=directory,
+ selectedFilter="All Files (*)")
if not filename:
return
if filetype == "All Files (*)":
@@ -574,7 +579,7 @@ def load(self):
if filename.endswith(importer.filetype[1:]):
filetype = "%s (%s)" % (importer.description, importer.filetype)
break
- if filetype == None:
+ if filetype is None:
return
# Remember the location
@@ -585,7 +590,7 @@ def load(self):
for importer in handlers:
ourtype = "%s (%s)" % (importer.description, importer.filetype)
if filetype == ourtype:
- handler = importer
+ handler = importer
self._last_file_handler = handler
# Load the file
@@ -598,10 +603,10 @@ def load(self):
except Exception as Ex:
self.display.voxels.enable_undo()
QtGui.QMessageBox.warning(self, "Could not load file",
- str(Ex))
+ str(Ex))
self.display.build_grids()
- #self.display.voxels.resize()
+ # self.display.voxels.resize()
self.display.voxels.saved()
self.display.reset_camera()
self.update_caption()
@@ -610,7 +615,7 @@ def load(self):
self.display.refresh()
# Registers a tool in the drawing toolbar
- def register_tool(self, tool, activate = False):
+ def register_tool(self, tool, activate=False):
self._tools.append(tool)
self._tool_group.addAction(tool.get_action())
self.ui.toolbar_drawing.addAction(tool.get_action())
@@ -639,6 +644,6 @@ def refresh_actions(self):
self.ui.action_anim_previous.setEnabled(num_frames > 1)
self.ui.action_anim_next.setEnabled(num_frames > 1)
self.ui.action_anim_play.setEnabled(num_frames > 1
- and not self._timer.isActive())
+ and not self._timer.isActive())
self.ui.action_anim_stop.setEnabled(self._timer.isActive())
self.update_caption()
diff --git a/src/palette_widget.py b/src/palette_widget.py
index d3f94b6..e2206a8 100644
--- a/src/palette_widget.py
+++ b/src/palette_widget.py
@@ -17,6 +17,7 @@
from PySide import QtCore, QtGui
from PySide.QtCore import QRect, QPoint
+
class PaletteWidget(QtGui.QWidget):
# Colour changed signal
@@ -25,6 +26,7 @@ class PaletteWidget(QtGui.QWidget):
@property
def colour(self):
return QtGui.QColor.fromHsvF(self._hue, self._saturation, self._value)
+
@colour.setter
def colour(self, value):
# If this is an integer, assume is RGBA
@@ -32,11 +34,11 @@ def colour(self, value):
r = (value & 0xff000000) >> 24
g = (value & 0xff0000) >> 16
b = (value & 0xff00) >> 8
- value = QtGui.QColor.fromRgb(r,g,b)
+ value = QtGui.QColor.fromRgb(r, g, b)
self._set_colour(value)
self.RGBvalue.setText(value.name())
- def __init__(self, parent = None, RGBvalue = None):
+ def __init__(self, parent=None, RGBvalue=None):
super(PaletteWidget, self).__init__(parent)
self._hue = 1.0
self._saturation = 1.0
@@ -54,17 +56,17 @@ def _calculate_bounds(self):
height = self.height()
# Hue palette
self._hue_rect = QRect(
- width-self._hue_width, 0, self._hue_width, height)
+ width - self._hue_width, 0, self._hue_width, height)
# Shades palette
self._shades_rect = QRect(
- 0, 0, width-(self._hue_width+self._gap), height)
+ 0, 0, width - (self._hue_width + self._gap), height)
# Render our palette to an image
def _draw_palette(self):
# Create an image with a white background
self._image = QtGui.QImage(QtCore.QSize(self.width(), self.height()),
- QtGui.QImage.Format.Format_RGB32)
+ QtGui.QImage.Format.Format_RGB32)
self._image.fill(QtGui.QColor.fromRgb(0xff, 0xff, 0xff))
# Draw on our image with no pen
@@ -74,9 +76,9 @@ def _draw_palette(self):
# Render hues
rect = self._hue_rect
- for x in xrange(rect.x(), rect.x()+rect.width()):
- for y in xrange(rect.y(), rect.y()+rect.height(), 8):
- h = float(y)/rect.height()
+ for x in xrange(rect.x(), rect.x() + rect.width()):
+ for y in xrange(rect.y(), rect.y() + rect.height(), 8):
+ h = float(y) / rect.height()
s = 1.0
v = 1.0
c = QtGui.QColor.fromHsvF(h, s, v)
@@ -86,7 +88,7 @@ def _draw_palette(self):
# Render hue selection marker
qp.setBrush(QtGui.QColor.fromRgb(0xff, 0xff, 0xff))
qp.drawRect(rect.x(), self._hue * rect.height(),
- rect.width(), 2)
+ rect.width(), 2)
# Render shades
rect = self._shades_rect
@@ -94,12 +96,12 @@ def _draw_palette(self):
steps = int(round(width / 8.0))
step_size = width / steps
x = rect.x()
- while x < rect.width()+rect.x():
+ while x < rect.width() + rect.x():
w = int(round(step_size))
- for y in xrange(rect.y(), rect.y()+rect.height(), 8):
+ for y in xrange(rect.y(), rect.y() + rect.height(), 8):
h = self._hue
- s = 1-float(y)/rect.height()
- v = float(x)/rect.width()
+ s = 1 - float(y) / rect.height()
+ v = float(x) / rect.width()
c = QtGui.QColor.fromHsvF(h, s, v)
qp.setBrush(c)
qp.drawRect(x, y, w, 8)
@@ -111,8 +113,8 @@ def _draw_palette(self):
# Render colour selection marker
qp.setBrush(QtGui.QColor.fromRgb(0xff, 0xff, 0xff))
- qp.drawRect(rect.x(), (1-self._saturation)*rect.height(), rect.width(), 1)
- qp.drawRect(self._value*rect.width(), rect.y(), 1, rect.height())
+ qp.drawRect(rect.x(), (1 - self._saturation) * rect.height(), rect.width(), 1)
+ qp.drawRect(self._value * rect.width(), rect.y(), 1, rect.height())
qp.end()
@@ -120,7 +122,7 @@ def paintEvent(self, event):
# Render our palette image to the screen
qp = QtGui.QPainter()
qp.begin(self)
- qp.drawImage(QPoint(0,0), self._image)
+ qp.drawImage(QPoint(0, 0), self._image)
qp.end()
def mousePressEvent(self, event):
@@ -130,7 +132,7 @@ def mousePressEvent(self, event):
if self._hue_rect.contains(mouse.x(), mouse.y()):
y = mouse.y()
c = QtGui.QColor.fromHsvF(
- float(y)/self.height(), self._saturation, self._value)
+ float(y) / self.height(), self._saturation, self._value)
self.colour = c
# Click on colours?
elif self._shades_rect.contains(mouse.x(), mouse.y()):
@@ -138,8 +140,8 @@ def mousePressEvent(self, event):
x = mouse.x()
y = mouse.y()
c = QtGui.QColor.fromHsvF(
- self._hue, 1-float(y)/self._shades_rect.height(),
- float(x)/self._shades_rect.width())
+ self._hue, 1 - float(y) / self._shades_rect.height(),
+ float(x) / self._shades_rect.width())
self.colour = c
def mouseMoveEvent(self, event):
diff --git a/src/plugin_api.py b/src/plugin_api.py
index a0753c6..258d34f 100644
--- a/src/plugin_api.py
+++ b/src/plugin_api.py
@@ -16,9 +16,11 @@
# along with this program. If not, see .
from PySide import QtGui
+
class PluginManager(object):
plugins = []
+
class PluginAPI(object):
def __init__(self):
@@ -28,7 +30,7 @@ def __init__(self):
self.mainwindow = self.application.mainwindow
# Register a drawing tool with the system
- def register_tool(self, tool, activate = False):
+ def register_tool(self, tool, activate=False):
# Create an instance
self.mainwindow.register_tool(tool, activate)
@@ -59,6 +61,7 @@ def get_voxel_mesh(self):
# name should be a hashable type, like a simple string.
def set_config(self, name, value):
self.api.mainwindow.set_setting(name, value)
+
def get_config(self, name):
return self.api.mainwindow.get_setting(name)
@@ -70,6 +73,8 @@ def warning(self, message):
# Plugins call this function to register with the system. A plugin
# should pass the class which will be instaniated by the application,
# this constructor is passed an instance of the system plugin API.
+
+
def register_plugin(plugin_class, name, version):
# Create an instance of the API to send to the plugin
# Plugins access the main app via this API instance
diff --git a/src/plugins/io_magica.py b/src/plugins/io_magica.py
index f80d74a..7ee22dd 100644
--- a/src/plugins/io_magica.py
+++ b/src/plugins/io_magica.py
@@ -16,6 +16,8 @@
from plugin_api import register_plugin
# http://voxel.codeplex.com/wikipage?title=VOX%20Format&referringTitle=MagicaVoxel%20Editor
+
+
class MagicaFile(object):
# Description of file type
@@ -28,38 +30,59 @@ def __init__(self, api):
self.api = api
# Register our exporter
self.api.register_file_handler(self)
- self.default_palette = [0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff, 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff, 0xff9999ff,
- 0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff, 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff, 0xff3333ff, 0xff0033ff, 0xffff00ff,
- 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff, 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc, 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc,
- 0xff00cccc, 0xffff99cc, 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc, 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,
- 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc, 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99, 0xff00ff99, 0xffffcc99,
- 0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99, 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699, 0xffcc6699, 0xff996699, 0xff666699, 0xff336699,
- 0xff006699, 0xffff3399, 0xffcc3399, 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099, 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66,
- 0xff66ff66, 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66, 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966, 0xffff6666,
- 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366, 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066, 0xff990066, 0xff660066, 0xff330066,
- 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33, 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33, 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933,
- 0xff669933, 0xff339933, 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633, 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,
- 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00, 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00, 0xff66cc00, 0xff33cc00,
- 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900, 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600, 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300,
- 0xff663300, 0xff333300, 0xff003300, 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd, 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044,
- 0xff000022, 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700, 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000, 0xffaa0000,
- 0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000, 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555, 0xff444444, 0xff222222, 0xff111111]
+ self.default_palette = [0xffffffff, 0xffccffff, 0xff99ffff, 0xff66ffff, 0xff33ffff, 0xff00ffff, 0xffffccff,
+ 0xffccccff, 0xff99ccff, 0xff66ccff, 0xff33ccff, 0xff00ccff, 0xffff99ff, 0xffcc99ff,
+ 0xff9999ff, 0xff6699ff, 0xff3399ff, 0xff0099ff, 0xffff66ff, 0xffcc66ff, 0xff9966ff,
+ 0xff6666ff, 0xff3366ff, 0xff0066ff, 0xffff33ff, 0xffcc33ff, 0xff9933ff, 0xff6633ff,
+ 0xff3333ff, 0xff0033ff, 0xffff00ff, 0xffcc00ff, 0xff9900ff, 0xff6600ff, 0xff3300ff,
+ 0xff0000ff, 0xffffffcc, 0xffccffcc, 0xff99ffcc, 0xff66ffcc, 0xff33ffcc, 0xff00ffcc,
+ 0xffffcccc, 0xffcccccc, 0xff99cccc, 0xff66cccc, 0xff33cccc, 0xff00cccc, 0xffff99cc,
+ 0xffcc99cc, 0xff9999cc, 0xff6699cc, 0xff3399cc, 0xff0099cc, 0xffff66cc, 0xffcc66cc,
+ 0xff9966cc, 0xff6666cc, 0xff3366cc, 0xff0066cc, 0xffff33cc, 0xffcc33cc, 0xff9933cc,
+ 0xff6633cc, 0xff3333cc, 0xff0033cc, 0xffff00cc, 0xffcc00cc, 0xff9900cc, 0xff6600cc,
+ 0xff3300cc, 0xff0000cc, 0xffffff99, 0xffccff99, 0xff99ff99, 0xff66ff99, 0xff33ff99,
+ 0xff00ff99, 0xffffcc99, 0xffcccc99, 0xff99cc99, 0xff66cc99, 0xff33cc99, 0xff00cc99,
+ 0xffff9999, 0xffcc9999, 0xff999999, 0xff669999, 0xff339999, 0xff009999, 0xffff6699,
+ 0xffcc6699, 0xff996699, 0xff666699, 0xff336699, 0xff006699, 0xffff3399, 0xffcc3399,
+ 0xff993399, 0xff663399, 0xff333399, 0xff003399, 0xffff0099, 0xffcc0099, 0xff990099,
+ 0xff660099, 0xff330099, 0xff000099, 0xffffff66, 0xffccff66, 0xff99ff66, 0xff66ff66,
+ 0xff33ff66, 0xff00ff66, 0xffffcc66, 0xffcccc66, 0xff99cc66, 0xff66cc66, 0xff33cc66,
+ 0xff00cc66, 0xffff9966, 0xffcc9966, 0xff999966, 0xff669966, 0xff339966, 0xff009966,
+ 0xffff6666, 0xffcc6666, 0xff996666, 0xff666666, 0xff336666, 0xff006666, 0xffff3366,
+ 0xffcc3366, 0xff993366, 0xff663366, 0xff333366, 0xff003366, 0xffff0066, 0xffcc0066,
+ 0xff990066, 0xff660066, 0xff330066, 0xff000066, 0xffffff33, 0xffccff33, 0xff99ff33,
+ 0xff66ff33, 0xff33ff33, 0xff00ff33, 0xffffcc33, 0xffcccc33, 0xff99cc33, 0xff66cc33,
+ 0xff33cc33, 0xff00cc33, 0xffff9933, 0xffcc9933, 0xff999933, 0xff669933, 0xff339933,
+ 0xff009933, 0xffff6633, 0xffcc6633, 0xff996633, 0xff666633, 0xff336633, 0xff006633,
+ 0xffff3333, 0xffcc3333, 0xff993333, 0xff663333, 0xff333333, 0xff003333, 0xffff0033,
+ 0xffcc0033, 0xff990033, 0xff660033, 0xff330033, 0xff000033, 0xffffff00, 0xffccff00,
+ 0xff99ff00, 0xff66ff00, 0xff33ff00, 0xff00ff00, 0xffffcc00, 0xffcccc00, 0xff99cc00,
+ 0xff66cc00, 0xff33cc00, 0xff00cc00, 0xffff9900, 0xffcc9900, 0xff999900, 0xff669900,
+ 0xff339900, 0xff009900, 0xffff6600, 0xffcc6600, 0xff996600, 0xff666600, 0xff336600,
+ 0xff006600, 0xffff3300, 0xffcc3300, 0xff993300, 0xff663300, 0xff333300, 0xff003300,
+ 0xffff0000, 0xffcc0000, 0xff990000, 0xff660000, 0xff330000, 0xff0000ee, 0xff0000dd,
+ 0xff0000bb, 0xff0000aa, 0xff000088, 0xff000077, 0xff000055, 0xff000044, 0xff000022,
+ 0xff000011, 0xff00ee00, 0xff00dd00, 0xff00bb00, 0xff00aa00, 0xff008800, 0xff007700,
+ 0xff005500, 0xff004400, 0xff002200, 0xff001100, 0xffee0000, 0xffdd0000, 0xffbb0000,
+ 0xffaa0000, 0xff880000, 0xff770000, 0xff550000, 0xff440000, 0xff220000, 0xff110000,
+ 0xffeeeeee, 0xffdddddd, 0xffbbbbbb, 0xffaaaaaa, 0xff888888, 0xff777777, 0xff555555,
+ 0xff444444, 0xff222222, 0xff111111]
# Helper function to read/write uint32
- def uint32(self, f, value = None):
+ def uint32(self, f, value=None):
if value is not None:
# Write
data = bytearray()
- data.append((value & 0xff));
- data.append((value & 0xff00)>>8);
- data.append((value & 0xff0000)>>16);
- data.append((value & 0xff000000)>>24);
+ data.append((value & 0xff))
+ data.append((value & 0xff00) >> 8)
+ data.append((value & 0xff0000) >> 16)
+ data.append((value & 0xff000000) >> 24)
f.write(data)
else:
# Read
x = bytearray(f.read(4))
if len(x) == 4:
- return x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24
+ return x[0] | x[1] << 8 | x[2] << 16 | x[3] << 24
return 0
def save(self, filename):
@@ -77,13 +100,13 @@ def save(self, filename):
for x in xrange(voxels.width):
vox = voxels.get(x, z, y)
if vox != 0:
- if not vox in helpPalette:
- r = (vox & 0xff000000)>>24
- g = (vox & 0x00ff0000)>>16
- b = (vox & 0x0000ff00)>>8
- paletteChunk.append(r | g<<8 | b <<16 | 0xff<<24)
+ if vox not in helpPalette:
+ r = (vox & 0xff000000) >> 24
+ g = (vox & 0x00ff0000) >> 16
+ b = (vox & 0x0000ff00) >> 8
+ paletteChunk.append(r | g << 8 | b << 16 | 0xff << 24)
helpPalette[vox] = len(paletteChunk) - 3
- voxelChunk.append(((helpPalette[vox])<<24) | (z<<16) | (y<<8) | x)
+ voxelChunk.append(((helpPalette[vox]) << 24) | (z << 16) | (y << 8) | x)
while len(paletteChunk) < 259:
paletteChunk.append(0xffffffff)
data.append(1076 + 4 * len(voxelChunk))
@@ -93,7 +116,7 @@ def save(self, filename):
data += paletteChunk
# Open our file
- f = open(filename,"wb")
+ f = open(filename, "wb")
for i in data:
self.uint32(f, i)
@@ -105,7 +128,7 @@ def load(self, filename):
voxels = self.api.get_voxel_data()
# Open our file
- f = open(filename,"rb")
+ f = open(filename, "rb")
meta = f.read(4)
if meta != "VOX ":
@@ -152,7 +175,7 @@ def load(self, filename):
palette = self.default_palette
else:
f.seek(paletteBegin)
- for i in xrange(0, paletteLength/4):
+ for i in xrange(0, paletteLength / 4):
palette.append(self.uint32(f))
# read voxel chunk
@@ -160,14 +183,14 @@ def load(self, filename):
voxelCount = self.uint32(f)
for i in xrange(0, voxelCount):
vox = self.uint32(f)
- ix = (vox & 0x000000ff)>>0
- iy = (vox & 0x0000ff00)>>8
- iz = (vox & 0x00ff0000)>>16
- ip = (vox & 0xff000000)>>24
- b = (palette[ip-1] & 0x00ff0000)>>16
- g = (palette[ip-1] & 0x0000ff00)>>8
- r = (palette[ip-1] & 0x000000ff)>>0
- voxels.set(ix, iz, iy, (r<<24) | (g<<16) | (b<<8) | 0xff)
+ ix = (vox & 0x000000ff) >> 0
+ iy = (vox & 0x0000ff00) >> 8
+ iz = (vox & 0x00ff0000) >> 16
+ ip = (vox & 0xff000000) >> 24
+ b = (palette[ip - 1] & 0x00ff0000) >> 16
+ g = (palette[ip - 1] & 0x0000ff00) >> 8
+ r = (palette[ip - 1] & 0x000000ff) >> 0
+ voxels.set(ix, iz, iy, (r << 24) | (g << 16) | (b << 8) | 0xff)
f.close()
register_plugin(MagicaFile, "Magica Voxel (.vox) file format IO", "1.0")
diff --git a/src/plugins/io_obj.py b/src/plugins/io_obj.py
index 6a9a77f..f4b2f3d 100644
--- a/src/plugins/io_obj.py
+++ b/src/plugins/io_obj.py
@@ -17,6 +17,7 @@
import os
from plugin_api import register_plugin
+
class ObjFile(object):
# Description of file type
@@ -37,21 +38,21 @@ def save(self, filename):
vertices, colours, _ = self.api.get_voxel_mesh()
# Open our file
- f = open(filename,"wt")
+ f = open(filename, "wt")
# Use materials
mat_pathname, mat_filename = os.path.split(filename)
name, ext = os.path.splitext(mat_filename)
if not ext:
- filename = filename+'.obj'
- mat_filename = os.path.join(mat_pathname, name)+".mtl"
+ filename = filename + '.obj'
+ mat_filename = os.path.join(mat_pathname, name) + ".mtl"
f.write("mtllib %s\r\n" % mat_filename)
# Export vertices
i = 0
while i < len(vertices):
f.write("v %f %f %f\r\n" %
- (vertices[i], vertices[i+1], vertices[i+2]))
+ (vertices[i], vertices[i + 1], vertices[i + 2]))
i += 3
# Build a list of unique colours we use so we can assign materials
@@ -59,30 +60,30 @@ def save(self, filename):
i = 0
while i < len(colours):
r = colours[i]
- g = colours[i+1]
- b = colours[i+2]
- colour = r<<24 | g<<16 | b<<8
+ g = colours[i + 1]
+ b = colours[i + 2]
+ colour = r << 24 | g << 16 | b << 8
if colour not in mats:
mats[colour] = "material_%i" % len(mats)
i += 3
# Export faces
- faces = (len(vertices)//(3*3))//2
+ faces = (len(vertices) // (3 * 3)) // 2
for i in xrange(faces):
- n = 1+(i * 6)
- r = colours[(i*18)]
- g = colours[(i*18)+1]
- b = colours[(i*18)+2]
- colour = r<<24 | g<<16 | b<<8
+ n = 1 + (i * 6)
+ r = colours[(i * 18)]
+ g = colours[(i * 18) + 1]
+ b = colours[(i * 18) + 2]
+ colour = r << 24 | g << 16 | b << 8
f.write("usemtl %s\r\n" % mats[colour])
- f.write("f %i %i %i\r\n" % (n, n+2, n+1))
- f.write("f %i %i %i\r\n" % (n+5, n+4, n+3))
+ f.write("f %i %i %i\r\n" % (n, n + 2, n + 1))
+ f.write("f %i %i %i\r\n" % (n + 5, n + 4, n + 3))
# Tidy up
f.close()
# Create our material file
- f = open(mat_filename,"wt")
+ f = open(mat_filename, "wt")
for colour, material in mats.items():
f.write("newmtl %s\r\n" % material)
r = (colour & 0xff000000) >> 24
diff --git a/src/plugins/io_png.py b/src/plugins/io_png.py
index e61903e..d50ae50 100644
--- a/src/plugins/io_png.py
+++ b/src/plugins/io_png.py
@@ -17,6 +17,7 @@
from plugin_api import register_plugin
from PySide import QtGui
+
class PngFile(object):
# Description of file type
@@ -32,7 +33,6 @@ def __init__(self, api):
# File version format we support
self._file_version = 1
-
# Called when we need to load a file. Should raise an exception if there
# is a problem.
def load(self, filename):
@@ -57,10 +57,9 @@ def load(self, filename):
for x in range(width):
for y in range(height):
- color = img.pixel(x,y)
+ color = img.pixel(x, y)
color = color << 8
- voxels.set(x,height-y-1,0, color)
-
+ voxels.set(x, height - y - 1, 0, color)
register_plugin(PngFile, "Png file format Importer", "1.0")
diff --git a/src/plugins/io_qubicle.py b/src/plugins/io_qubicle.py
index cbe9d4d..7a8de09 100644
--- a/src/plugins/io_qubicle.py
+++ b/src/plugins/io_qubicle.py
@@ -19,6 +19,8 @@
from struct import unpack
# http://www.minddesk.com/wiki/index.php?title=Qubicle_Constructor_1:Data_Exchange_With_Qubicle_Binary
+
+
class QubicleFile(object):
# Description of file type
@@ -33,20 +35,20 @@ def __init__(self, api):
self.api.register_file_handler(self)
# Helper function to read/write uint32
- def uint32(self, f, value = None):
+ def uint32(self, f, value=None):
if value is not None:
# Write
data = bytearray()
- data.append((value & 0xff));
- data.append((value & 0xff00)>>8);
- data.append((value & 0xff0000)>>16);
- data.append((value & 0xff000000)>>24);
+ data.append((value & 0xff))
+ data.append((value & 0xff00) >> 8)
+ data.append((value & 0xff0000) >> 16)
+ data.append((value & 0xff000000) >> 24)
f.write(data)
else:
# Read
x = bytearray(f.read(4))
if len(x) == 4:
- return x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24
+ return x[0] | x[1] << 8 | x[2] << 16 | x[3] << 24
return 0
def int32(self, f):
@@ -59,7 +61,7 @@ def save(self, filename):
voxels = self.api.get_voxel_data()
# Open our file
- f = open(filename,"wb")
+ f = open(filename, "wb")
# Version
self.uint32(f, 0x00000101)
@@ -98,10 +100,10 @@ def save(self, filename):
alpha = 0xff
if not vox:
alpha = 0x00
- r = (vox & 0xff000000)>>24
- g = (vox & 0xff0000)>>16
- b = (vox & 0xff00)>>8
- vox = r | g<<8 | b<<16 | alpha<<24
+ r = (vox & 0xff000000) >> 24
+ g = (vox & 0xff0000) >> 16
+ b = (vox & 0xff00) >> 8
+ vox = r | g << 8 | b << 16 | alpha << 24
self.uint32(f, vox)
# Tidy up
@@ -109,12 +111,12 @@ def save(self, filename):
# sets alpha to ff and converts brga to rgba if format
def formatVox(self, vox, format):
- r = (vox & 0x000000ff)>>0
- g = (vox & 0x0000ff00)>>8
- b = (vox & 0x00ff0000)>>16
+ r = (vox & 0x000000ff) >> 0
+ g = (vox & 0x0000ff00) >> 8
+ b = (vox & 0x00ff0000) >> 16
if format:
- return (b<<24) | (g<<16) | (r<<8) | 0xff
- return (r<<24) | (g<<16) | (b<<8) | 0xff
+ return (b << 24) | (g << 16) | (r << 8) | 0xff
+ return (r << 24) | (g << 16) | (b << 8) | 0xff
# Load a Qubicle Constructor binary file
def load(self, filename):
@@ -122,7 +124,7 @@ def load(self, filename):
voxels = self.api.get_voxel_data()
# Open our file
- f = open(filename,"rb")
+ f = open(filename, "rb")
# Version
version = self.uint32(f)
@@ -183,7 +185,7 @@ def load(self, filename):
while True:
data = self.uint32(f)
if (data == 6):
- break;
+ break
elif (data == 2):
count = self.uint32(f)
vox = self.uint32(f)
@@ -218,8 +220,10 @@ def load(self, filename):
if coords == 1:
iz = depth - z - 1
voxels.set((width - x - 1), y, iz, self.formatVox(vox, format))
- if matrix_count == 1 and dx <= 0 and dy <= 0 and dz <= 0 and (dx < 0 or dy < 0 or dz < 0): # restore attachment point
- t = "It looks like your are opening a voxel model exported by Trove. Should we try to restore the attachment point out of the .qb's metadata for you?"
+ # restore attachment point
+ if matrix_count == 1 and dx <= 0 and dy <= 0 and dz <= 0 and (dx < 0 or dy < 0 or dz < 0):
+ t = "It looks like your are opening a voxel model exported by Trove.\
+ Should we try to restore the attachment point out of the .qb's metadata for you?"
r = QMessageBox.question(None, "Restore attachment point?", t, QMessageBox.No, QMessageBox.Yes)
if r == QMessageBox.Yes:
voxels.set((max_width + dx - 1), -dy, -dz, 0xff00ffff)
diff --git a/src/plugins/io_sproxel.py b/src/plugins/io_sproxel.py
index bac736d..118f884 100644
--- a/src/plugins/io_sproxel.py
+++ b/src/plugins/io_sproxel.py
@@ -16,6 +16,7 @@
# along with this program. If not, see .
from plugin_api import register_plugin
+
class SproxelFile(object):
# Description of file type
@@ -36,14 +37,14 @@ def save(self, filename):
voxels = self.api.get_voxel_data()
# Open our file
- f = open(filename,"wt")
+ f = open(filename, "wt")
# First Sproxel line is model dimenstions
f.write("%i,%i,%i\n" % (voxels.width, voxels.height, voxels.depth))
# Then we save from the top of the model
- for y in xrange(voxels.height-1, -1, -1):
- for z in xrange(voxels.depth-1, -1, -1):
+ for y in xrange(voxels.height - 1, -1, -1):
+ for z in xrange(voxels.depth - 1, -1, -1):
line = []
for x in xrange(voxels.width):
voxel = voxels.get(x, y, z)
@@ -52,8 +53,8 @@ def save(self, filename):
else:
voxel = (voxel & 0xffffff00) | 0xff
voxel = "%x" % voxel
- line.append("#"+voxel.upper().rjust(8,"0"))
- f.write(",".join(line)+"\n")
+ line.append("#" + voxel.upper().rjust(8, "0"))
+ f.write(",".join(line) + "\n")
f.write("\n")
# Tidy up
@@ -65,16 +66,16 @@ def load(self, filename):
voxels = self.api.get_voxel_data()
# Open our file
- f = open(filename,"rt")
+ f = open(filename, "rt")
size = f.readline().strip()
- x,y,z = size.split(",")
+ x, y, z = size.split(",")
x = int(x)
y = int(y)
z = int(z)
voxels.resize(x, y, z)
# Parse the file
- for fy in xrange(y-1,-1,-1):
- for fz in xrange(z-1,-1,-1):
+ for fy in xrange(y - 1, -1, -1):
+ for fz in xrange(z - 1, -1, -1):
line = f.readline().strip().split(",")
for fx in xrange(0, x):
if line[fx] == "#00000000":
@@ -87,10 +88,10 @@ def load(self, filename):
g = int(g, 16)
b = int(b, 16)
a = 0xff
- v = r<<24 | g<<16 | b<<8 | a
+ v = r << 24 | g << 16 | b << 8 | a
voxels.set(fx, fy, fz, v)
- f.readline() # discard empty line
+ f.readline() # discard empty line
f.close()
register_plugin(SproxelFile, "Sproxel file format IO", "1.0")
diff --git a/src/plugins/io_troxel.py b/src/plugins/io_troxel.py
index 6fad581..64a2605 100644
--- a/src/plugins/io_troxel.py
+++ b/src/plugins/io_troxel.py
@@ -2,6 +2,7 @@
from struct import pack
from plugin_api import PluginAPI
+
class TroxelLink:
def __init__(self):
@@ -44,7 +45,7 @@ def export(self):
if r > 1:
data.append(126 + r)
if vox[i]:
- index = rcolors[ vox[i][2] + 256 * vox[i][1] + 65536 * vox[i][0] ]
+ index = rcolors[vox[i][2] + 256 * vox[i][1] + 65536 * vox[i][0]]
if short:
data.append(index)
else:
diff --git a/src/plugins/io_zoxel.py b/src/plugins/io_zoxel.py
index 58c8011..9df069e 100644
--- a/src/plugins/io_zoxel.py
+++ b/src/plugins/io_zoxel.py
@@ -18,6 +18,7 @@
from plugin_api import register_plugin
from constants import ZOXEL_VERSION
+
class ZoxelFile(object):
# Description of file type
@@ -44,7 +45,7 @@ def save(self, filename):
# Build data structure
data = {'version': version, 'frames': voxels.get_frame_count(),
- "creator": "Zoxel Version "+ZOXEL_VERSION}
+ "creator": "Zoxel Version " + ZOXEL_VERSION}
for f in xrange(voxels.get_frame_count()):
frame = []
@@ -54,16 +55,16 @@ def save(self, filename):
for x in range(voxels.width):
v = voxels.get(x, y, z)
if v:
- frame.append((x,y,z,v))
+ frame.append((x, y, z, v))
- data['frame{0}'.format(f+1)] = frame
+ data['frame{0}'.format(f + 1)] = frame
data['width'] = voxels.width
data['height'] = voxels.height
data['depth'] = voxels.depth
# Open our file
- f = open(filename,"wt")
+ f = open(filename, "wt")
f.write(json.dumps(data))
@@ -111,15 +112,15 @@ def load(self, filename):
if z > maxZ:
maxZ = z
# Resize
- voxels.resize(maxX+1, maxY+1, maxZ+1)
+ voxels.resize(maxX + 1, maxY + 1, maxZ + 1)
# Read the voxel data
for f in xrange(frames):
- frame = data['frame{0}'.format(f+1)]
+ frame = data['frame{0}'.format(f + 1)]
for x, y, z, v in frame:
voxels.set(x, y, z, v)
# Add another frame if required
- if f < frames-1:
+ if f < frames - 1:
voxels.add_frame(False)
# Select the first frame by default
diff --git a/src/plugins/tool_colourpick.py b/src/plugins/tool_colourpick.py
index 1cd06b2..a9dedd9 100644
--- a/src/plugins/tool_colourpick.py
+++ b/src/plugins/tool_colourpick.py
@@ -18,6 +18,7 @@
from tool import Tool
from plugin_api import register_plugin
+
class ColourPickTool(Tool):
def __init__(self, api):
diff --git a/src/plugins/tool_drag.py b/src/plugins/tool_drag.py
index b4675dd..851679e 100644
--- a/src/plugins/tool_drag.py
+++ b/src/plugins/tool_drag.py
@@ -18,6 +18,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class DragTool(Tool):
def __init__(self, api):
diff --git a/src/plugins/tool_draw.py b/src/plugins/tool_draw.py
index 970dc71..4be02a6 100644
--- a/src/plugins/tool_draw.py
+++ b/src/plugins/tool_draw.py
@@ -18,6 +18,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class DrawingTool(Tool):
def __init__(self, api):
@@ -39,8 +40,8 @@ def __init__(self, api):
# returns A Target object indicating the actual place where the voxel were
# inserted. Returns None when no insertion was made.
def _draw_voxel(self, target, shift_down, erase):
- # Works out where exactly the new voxel goes. It can collide with an existing voxel or with the bottom of the 'y' plane,
- #in which case, pos will be different than None.
+ # Works out where exactly the new voxel goes. It can collide with an existing voxel
+ # or with the bottom of the 'y' plane, in which case, pos will be different than None.
color = self.colour
if erase:
color = 0
@@ -51,9 +52,9 @@ def _draw_voxel(self, target, shift_down, erase):
target.world_y = pos[1]
target.world_z = pos[2]
- if shift_down and self.first_voxel == None:
+ if shift_down and self.first_voxel is None:
self.first_voxel = (target.world_x, target.world_y, target.world_z)
- elif self.first_voxel == None:
+ elif self.first_voxel is None:
if target.voxels.set(target.world_x, target.world_y, target.world_z, color):
return target
else:
@@ -73,11 +74,11 @@ def _draw_voxel(self, target, shift_down, erase):
return None
def _get_valid_sequence_faces(self, face):
- if( face in Face.COLLIDABLE_FACES_PLANE_X ):
+ if(face in Face.COLLIDABLE_FACES_PLANE_X):
return Face.COLLIDABLE_FACES_PLANE_Y + Face.COLLIDABLE_FACES_PLANE_Z
- elif( face in Face.COLLIDABLE_FACES_PLANE_Y ):
+ elif(face in Face.COLLIDABLE_FACES_PLANE_Y):
return Face.COLLIDABLE_FACES_PLANE_X + Face.COLLIDABLE_FACES_PLANE_Z
- elif( face in Face.COLLIDABLE_FACES_PLANE_Z ):
+ elif(face in Face.COLLIDABLE_FACES_PLANE_Z):
return Face.COLLIDABLE_FACES_PLANE_X + Face.COLLIDABLE_FACES_PLANE_Y
else:
return None
@@ -94,10 +95,10 @@ def on_drag_start(self, data):
# When dragging, Draw a new voxel next to the targeted face
def on_drag(self, data):
# In case the first click has missed a valid target.
- if( self._first_target is None ):
+ if(self._first_target is None):
return
valid_faces = self._get_valid_sequence_faces(self._first_target.face)
- if( ( not valid_faces ) or ( data.face not in valid_faces ) ):
+ if((not valid_faces) or (data.face not in valid_faces)):
return
self._draw_voxel(data, False, False)
diff --git a/src/plugins/tool_erase.py b/src/plugins/tool_erase.py
index f7c6bcf..d783ceb 100644
--- a/src/plugins/tool_erase.py
+++ b/src/plugins/tool_erase.py
@@ -18,6 +18,7 @@
from tool import Tool
from plugin_api import register_plugin
+
class EraseTool(Tool):
def __init__(self, api):
diff --git a/src/plugins/tool_extrude.py b/src/plugins/tool_extrude.py
index 071cea1..c868815 100644
--- a/src/plugins/tool_extrude.py
+++ b/src/plugins/tool_extrude.py
@@ -18,6 +18,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class ExtrudeTool(Tool):
def __init__(self, api):
@@ -36,16 +37,16 @@ def __init__(self, api):
self.regionend = None
def regionvalid(self):
- if self.regionstart == None or self.regionend == None:
+ if self.regionstart is None or self.regionend is None:
return 0, False
r = []
if self.regionstart[0] == self.regionend[0]:
- r.append(0) # Plane is on yz
+ r.append(0) # Plane is on yz
if self.regionstart[1] == self.regionend[1]:
- r.append(1) # Plane is on xz
+ r.append(1) # Plane is on xz
if self.regionstart[2] == self.regionend[2]:
- r.append(2) # Plane is on xy
- if len(r) == 1: # If plane and not line or point
+ r.append(2) # Plane is on xy
+ if len(r) == 1: # If plane and not line or point
return r.pop(), True
return 0, False
@@ -64,12 +65,14 @@ def do_extrude(self, target, value, region):
if self.regionstart[2] > self.regionend[2]:
zdelt = -1
for xidx in range(abs(value)):
- for yidx in range(abs(self.regionstart[1] - self.regionend[1])+1):
- for zidx in range(abs(self.regionstart[2] - self.regionend[2])+1):
- src = target.voxels.get(xpos, ypos+(yidx*ydelt), zpos+(zidx*zdelt))
- tgt = target.voxels.get(xpos+(xidx*xdelt)+xdelt, ypos+(yidx*ydelt), zpos+(zidx*zdelt))
+ for yidx in range(abs(self.regionstart[1] - self.regionend[1]) + 1):
+ for zidx in range(abs(self.regionstart[2] - self.regionend[2]) + 1):
+ src = target.voxels.get(xpos, ypos + (yidx * ydelt), zpos + (zidx * zdelt))
+ tgt = target.voxels.get(xpos + (xidx * xdelt) + xdelt, ypos +
+ (yidx * ydelt), zpos + (zidx * zdelt))
if tgt == 0:
- target.voxels.set(xpos+(xidx*xdelt)+xdelt, ypos+(yidx*ydelt), zpos+(zidx*zdelt), src, True, 1)
+ target.voxels.set(xpos + (xidx * xdelt) + xdelt, ypos +
+ (yidx * ydelt), zpos + (zidx * zdelt), src, True, 1)
target.voxels.completeUndoFill()
return True
if region == 1:
@@ -80,12 +83,14 @@ def do_extrude(self, target, value, region):
if self.regionstart[2] > self.regionend[2]:
zdelt = -1
for yidx in range(abs(value)):
- for xidx in range(abs(self.regionstart[0] - self.regionend[0])+1):
- for zidx in range(abs(self.regionstart[2] - self.regionend[2])+1):
- src = target.voxels.get(xpos+(xidx*xdelt), ypos, zpos+(zidx*zdelt))
- tgt = target.voxels.get(xpos+(xidx*xdelt), ypos+(yidx*ydelt)+ydelt, zpos+(zidx*zdelt))
+ for xidx in range(abs(self.regionstart[0] - self.regionend[0]) + 1):
+ for zidx in range(abs(self.regionstart[2] - self.regionend[2]) + 1):
+ src = target.voxels.get(xpos + (xidx * xdelt), ypos, zpos + (zidx * zdelt))
+ tgt = target.voxels.get(xpos + (xidx * xdelt), ypos +
+ (yidx * ydelt) + ydelt, zpos + (zidx * zdelt))
if tgt == 0:
- target.voxels.set(xpos+(xidx*xdelt), ypos+(yidx*ydelt)+ydelt, zpos+(zidx*zdelt), src, True, 1)
+ target.voxels.set(xpos + (xidx * xdelt), ypos + (yidx * ydelt) +
+ ydelt, zpos + (zidx * zdelt), src, True, 1)
target.voxels.completeUndoFill()
return True
if region == 2:
@@ -96,21 +101,23 @@ def do_extrude(self, target, value, region):
if value < 0:
zdelt = -1
for zidx in range(abs(value)):
- for xidx in range(abs(self.regionstart[0] - self.regionend[0])+1):
- for yidx in range(abs(self.regionstart[1] - self.regionend[1])+1):
- src = target.voxels.get(xpos+(xidx*xdelt), ypos+(yidx*ydelt), zpos)
- tgt = target.voxels.get(xpos+(xidx*xdelt), ypos+(yidx*ydelt), zpos+(zidx*zdelt)+zdelt)
+ for xidx in range(abs(self.regionstart[0] - self.regionend[0]) + 1):
+ for yidx in range(abs(self.regionstart[1] - self.regionend[1]) + 1):
+ src = target.voxels.get(xpos + (xidx * xdelt), ypos + (yidx * ydelt), zpos)
+ tgt = target.voxels.get(xpos + (xidx * xdelt), ypos + (yidx * ydelt),
+ zpos + (zidx * zdelt) + zdelt)
if tgt == 0:
- target.voxels.set(xpos+(xidx*xdelt), ypos+(yidx*ydelt), zpos+(zidx*zdelt)+zdelt, src, True, 1)
+ target.voxels.set(xpos + (xidx * xdelt), ypos + (yidx * ydelt),
+ zpos + (zidx * zdelt) + zdelt, src, True, 1)
target.voxels.completeUndoFill()
return True
return False
def on_mouse_click(self, data):
shift_down = not not (data.key_modifiers & QtCore.Qt.KeyboardModifier.ShiftModifier)
- if shift_down and self.regionstart == None:
+ if shift_down and self.regionstart is None:
self.regionstart = [data.world_x, data.world_y, data.world_z]
- elif self.regionstart != None:
+ elif self.regionstart is not None:
self.regionend = [data.world_x, data.world_y, data.world_z]
region, valid = self.regionvalid()
if valid:
@@ -126,15 +133,24 @@ def on_mouse_click(self, data):
directionHint = "\nPositive values mean to the back, negative mean to the front."
min = -1 * data.world_z
max = data.voxels.depth - data.world_z - 1
- value, ret = QtGui.QInputDialog.getInt(QtGui.QApplication.instance().mainwindow, "Extrude", "Extrude region: "+str(self.regionstart)+" - "+str(self.regionend)+ directionHint, 0, min, max)
+ value, ret = QtGui.QInputDialog.getInt(QtGui.QApplication.instance().mainwindow, "Extrude",
+ "Extrude region: " + str(self.regionstart) + " - " +
+ str(self.regionend) + directionHint, 0, min, max)
if ret:
self.do_extrude(data, value, region)
else:
- QtGui.QMessageBox.warning(QtGui.QApplication.instance().mainwindow, "Extrude", "The region you selected is invalid. Try again.\nMake sure that they are on a plane in any direction.\nExtrusion can only be done in straigt directions. Top, bottom, left, right, back and front.", QtGui.QMessageBox.Ok)
+ QtGui.QMessageBox.warning(QtGui.QApplication.instance().mainwindow, "Extrude",
+ ("The region you selected is invalid. Try again.\n"
+ "Make sure that they are on a plane in any direction.\n"
+ "Extrusion can only be done in straigt directions. "
+ "Top, bottom, left, right, back and front."), QtGui.QMessageBox.Ok)
self.regionstart = None
self.regionend = None
else:
- QtGui.QMessageBox.warning(QtGui.QApplication.instance().mainwindow, "Extrude", "You have not selected a region yet. Hold shift and click on two voxels that are on a flat plane in any direction.", QtGui.QMessageBox.Ok)
+ QtGui.QMessageBox.warning(QtGui.QApplication.instance().mainwindow, "Extrude",
+ ("You have not selected a region yet. "
+ "Hold shift and click on two voxels that are on a flat plane in any direction."),
+ QtGui.QMessageBox.Ok)
register_plugin(ExtrudeTool, "Extrude Tool", "1.0")
diff --git a/src/plugins/tool_fill.py b/src/plugins/tool_fill.py
index 023ec2f..4a82df2 100644
--- a/src/plugins/tool_fill.py
+++ b/src/plugins/tool_fill.py
@@ -16,6 +16,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class FillTool(Tool):
def __init__(self, api):
@@ -40,7 +41,7 @@ def on_mouse_click(self, target):
search_colour = voxel
# Don't allow invalid fills
c = self.colour.getRgb()
- fill_colour = c[0]<<24 | c[1]<<16 | c[2]<<8 | 0xff
+ fill_colour = c[0] << 24 | c[1] << 16 | c[2] << 8 | 0xff
if search_colour == fill_colour:
return
# Initialise our search list
@@ -48,23 +49,23 @@ def on_mouse_click(self, target):
search.add((target.world_x, target.world_y, target.world_z))
# Keep iterating over the search list until no more to do
while len(search):
- x,y,z = search.pop()
+ x, y, z = search.pop()
voxel = target.voxels.get(x, y, z)
if not voxel or voxel != search_colour:
continue
# Add all likely neighbours into our search list
- if target.voxels.get(x-1,y,z) == search_colour:
- search.add((x-1,y,z))
- if target.voxels.get(x+1,y,z) == search_colour:
- search.add((x+1,y,z))
- if target.voxels.get(x,y+1,z) == search_colour:
- search.add((x,y+1,z))
- if target.voxels.get(x,y-1,z) == search_colour:
- search.add((x,y-1,z))
- if target.voxels.get(x,y,z+1) == search_colour:
- search.add((x,y,z+1))
- if target.voxels.get(x,y,z-1) == search_colour:
- search.add((x,y,z-1))
+ if target.voxels.get(x - 1, y, z) == search_colour:
+ search.add((x - 1, y, z))
+ if target.voxels.get(x + 1, y, z) == search_colour:
+ search.add((x + 1, y, z))
+ if target.voxels.get(x, y + 1, z) == search_colour:
+ search.add((x, y + 1, z))
+ if target.voxels.get(x, y - 1, z) == search_colour:
+ search.add((x, y - 1, z))
+ if target.voxels.get(x, y, z + 1) == search_colour:
+ search.add((x, y, z + 1))
+ if target.voxels.get(x, y, z - 1) == search_colour:
+ search.add((x, y, z - 1))
# Set the colour of the current voxel
target.voxels.set(x, y, z, self.colour, True, len(search) == 0 and 2 or 1)
diff --git a/src/plugins/tool_fill_noise.py b/src/plugins/tool_fill_noise.py
index 62c7d77..6d03d44 100644
--- a/src/plugins/tool_fill_noise.py
+++ b/src/plugins/tool_fill_noise.py
@@ -20,6 +20,7 @@
from plugin_api import register_plugin
from random import random
+
class FillNoiseTool(Tool):
def __init__(self, api):
@@ -44,7 +45,7 @@ def on_mouse_click(self, target):
search_colour = voxel
# Don't allow invalid fills
c = self.colour.getRgb()
- fill_colour = c[0]<<24 | c[1]<<16 | c[2]<<8 | 0xff
+ fill_colour = c[0] << 24 | c[1] << 16 | c[2] << 8 | 0xff
# Initialise our search list
search = set()
search.add((target.world_x, target.world_y, target.world_z))
@@ -53,32 +54,32 @@ def on_mouse_click(self, target):
i = QtGui.QInputDialog.getDouble(self.api.mainwindow, "Intensity", "Intensity:", 0.3, 0.0, 1.0, 3.0)[0]
# Keep iterating over the search list until no more to do
while len(search):
- x,y,z = search.pop()
+ x, y, z = search.pop()
voxel = target.voxels.get(x, y, z)
if not voxel or voxel != search_colour:
continue
# Add all likely neighbours into our search list
- if target.voxels.get(x-1,y,z) == search_colour and not (x-1,y,z) in searched:
- search.add((x-1,y,z))
- if target.voxels.get(x+1,y,z) == search_colour and not (x+1,y,z) in searched:
- search.add((x+1,y,z))
- if target.voxels.get(x,y+1,z) == search_colour and not (x,y+1,z) in searched:
- search.add((x,y+1,z))
- if target.voxels.get(x,y-1,z) == search_colour and not (x,y-1,z) in searched:
- search.add((x,y-1,z))
- if target.voxels.get(x,y,z+1) == search_colour and not (x,y,z+1) in searched:
- search.add((x,y,z+1))
- if target.voxels.get(x,y,z-1) == search_colour and not (x,y,z-1) in searched:
- search.add((x,y,z-1))
+ if target.voxels.get(x - 1, y, z) == search_colour and not (x - 1, y, z) in searched:
+ search.add((x - 1, y, z))
+ if target.voxels.get(x + 1, y, z) == search_colour and not (x + 1, y, z) in searched:
+ search.add((x + 1, y, z))
+ if target.voxels.get(x, y + 1, z) == search_colour and not (x, y + 1, z) in searched:
+ search.add((x, y + 1, z))
+ if target.voxels.get(x, y - 1, z) == search_colour and not (x, y - 1, z) in searched:
+ search.add((x, y - 1, z))
+ if target.voxels.get(x, y, z + 1) == search_colour and not (x, y, z + 1) in searched:
+ search.add((x, y, z + 1))
+ if target.voxels.get(x, y, z - 1) == search_colour and not (x, y, z - 1) in searched:
+ search.add((x, y, z - 1))
# Set the colour of the current voxel
if target.mouse_button == MouseButtons.LEFT:
- nc = color.lighter(random()*200*i + 100 - 100*i)
+ nc = color.lighter(random() * 200 * i + 100 - 100 * i)
elif target.mouse_button == MouseButtons.RIGHT:
nc = QtGui.QColor(color)
- nc.setHsvF((nc.hueF()+(random()*0.2*i-0.1*i))%1,
- max(0,min(1,nc.saturationF()+(random()*2*i-i))),
- max(0,min(1,nc.valueF()+(random()*2*i-i))))
+ nc.setHsvF((nc.hueF() + (random() * 0.2 * i - 0.1 * i)) % 1,
+ max(0, min(1, nc.saturationF() + (random() * 2 * i - i))),
+ max(0, min(1, nc.valueF() + (random() * 2 * i - i))))
target.voxels.set(x, y, z, nc, True, len(search) == 0 and 2 or 1)
- searched.append((x,y,z))
+ searched.append((x, y, z))
register_plugin(FillNoiseTool, "Noisy Fill Tool", "1.0")
diff --git a/src/plugins/tool_paint.py b/src/plugins/tool_paint.py
index 93c49b3..7519264 100644
--- a/src/plugins/tool_paint.py
+++ b/src/plugins/tool_paint.py
@@ -18,6 +18,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class PaintingTool(Tool):
def __init__(self, api):
diff --git a/src/plugins/tool_shade.py b/src/plugins/tool_shade.py
index 0144825..d011f76 100644
--- a/src/plugins/tool_shade.py
+++ b/src/plugins/tool_shade.py
@@ -17,6 +17,7 @@
from tool import Tool, EventData, MouseButtons, KeyModifiers, Face
from plugin_api import register_plugin
+
class ShaderTool(Tool):
def __init__(self, api):
@@ -38,14 +39,14 @@ def on_mouse_click(self, data):
if voxel:
self.api.set_palette_colour(voxel)
if data.mouse_button == MouseButtons.LEFT:
- #Darken the colour.
+ # Darken the colour.
newColour = self.api.get_palette_colour().darker(110)
- #set the voxel's new color.
+ # set the voxel's new color.
data.voxels.set(data.world_x, data.world_y, data.world_z, newColour)
elif data.mouse_button == MouseButtons.RIGHT:
- #Lighten the colour.
+ # Lighten the colour.
newColour = self.api.get_palette_colour().lighter(110)
- #set the voxel's new color.
+ # set the voxel's new color.
data.voxels.set(data.world_x, data.world_y, data.world_z, newColour)
# Colour when dragging also
diff --git a/src/tool.py b/src/tool.py
index b185080..2020918 100644
--- a/src/tool.py
+++ b/src/tool.py
@@ -18,6 +18,8 @@
from PySide import QtGui
# Enumeration type
+
+
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
@@ -28,6 +30,7 @@ def enum(*sequential, **named):
# Keyboard modifiers
KeyModifiers = enum('CTRL', 'SHIFT', 'ALT')
+
class Face(object):
FRONT = 0 # z-
TOP = 1 # y+
@@ -45,11 +48,13 @@ class Face(object):
COLLIDABLE_FACES_PLANE_Y = FACES_PLANE_Y + [None]
COLLIDABLE_FACES_PLANE_Z = FACES_PLANE_Z
+
class EventData(object):
@property
def face(self):
return self._face
+
@face.setter
def face(self, value):
self._face = value
@@ -57,6 +62,7 @@ def face(self, value):
@property
def world_x(self):
return self._world_x
+
@world_x.setter
def world_x(self, value):
self._world_x = value
@@ -64,6 +70,7 @@ def world_x(self, value):
@property
def world_y(self):
return self._world_y
+
@world_y.setter
def world_y(self, value):
self._world_y = value
@@ -71,6 +78,7 @@ def world_y(self, value):
@property
def world_z(self):
return self._world_z
+
@world_z.setter
def world_z(self, value):
self._world_z = value
@@ -78,6 +86,7 @@ def world_z(self, value):
@property
def voxels(self):
return self._voxels
+
@voxels.setter
def voxels(self, value):
self._voxels = value
@@ -85,6 +94,7 @@ def voxels(self, value):
@property
def mouse_x(self):
return self._mouse_x
+
@mouse_x.setter
def mouse_x(self, value):
self._mouse_x = value
@@ -92,6 +102,7 @@ def mouse_x(self, value):
@property
def mouse_y(self):
return self._mouse_y
+
@mouse_y.setter
def mouse_y(self, value):
self._mouse_y = value
@@ -99,6 +110,7 @@ def mouse_y(self, value):
@property
def mouse_button(self):
return self._mouse_button
+
@mouse_button.setter
def mouse_button(self, value):
self._mouse_button = value
@@ -106,6 +118,7 @@ def mouse_button(self, value):
@property
def key_modifiers(self):
return self._key_modifiers
+
@key_modifiers.setter
def key_modifiers(self, value):
self._key_modifiers = value
@@ -113,9 +126,9 @@ def key_modifiers(self, value):
def __repr__(self):
return ('EventData(face={0},world_x={1},world_y={2},world_z={3},'
'mouse_x={4},mouse_y={5},mouse_button={6},key_modifiers={7})'.format(
- self._face, self._world_x, self._world_y, self._world_z,
- self._mouse_x, self._mouse_y, self._mouse_button,
- self._key_modifiers))
+ self._face, self._world_x, self._world_y, self._world_z,
+ self._mouse_x, self._mouse_y, self._mouse_button,
+ self._key_modifiers))
def __init__(self):
self._face = None
@@ -129,11 +142,11 @@ def __init__(self):
self._voxels = None
def __eq__(self, other):
- return ( (self._x == other._x) and
- (self._y == other._y ) and
- (self._z == other._z ) and
- (self._face == other._face ) and
- (self._voxels == other._voxels ) )
+ return ((self._x == other._x) and
+ (self._y == other._y) and
+ (self._z == other._z) and
+ (self._face == other._face) and
+ (self._voxels == other._voxels))
# Returns the coordinates of the voxel next to the selected face.
# Or None if there is not one.
@@ -146,7 +159,7 @@ def get_neighbour(self):
if self.face == Face.TOP:
y += 1
elif self.face == Face.BOTTOM:
- y -=1
+ y -= 1
elif self.face == Face.BACK:
z += 1
elif self.face == Face.FRONT:
@@ -157,6 +170,7 @@ def get_neighbour(self):
x += 1
return (x, y, z)
+
class Tool(object):
@property
diff --git a/src/undo.py b/src/undo.py
index 7006240..4a15bc6 100644
--- a/src/undo.py
+++ b/src/undo.py
@@ -15,6 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+
class UndoItem(object):
@property
@@ -34,6 +35,7 @@ def __init__(self, operation, olddata, newdata):
self._olddata = olddata
self._newdata = newdata
+
class Undo(object):
# Types of operation
@@ -44,6 +46,7 @@ class Undo(object):
@property
def enabled(self):
return self._enabled
+
@enabled.setter
def enabled(self, value):
self._enabled = value
@@ -51,6 +54,7 @@ def enabled(self, value):
@property
def frame(self):
return self._frame
+
@frame.setter
def frame(self, value):
self._frame = value
@@ -71,10 +75,10 @@ def add(self, item):
if not self._enabled:
return
# Clear future if we're somewhere in the middle of the undo history
- if self._ptr[self._frame] < len(self._buffer[self._frame])-1:
- self._buffer[self._frame] = self._buffer[self._frame][:self._ptr[self._frame]+1]
+ if self._ptr[self._frame] < len(self._buffer[self._frame]) - 1:
+ self._buffer[self._frame] = self._buffer[self._frame][:self._ptr[self._frame] + 1]
self._buffer[self._frame].append(item)
- self._ptr[self._frame] = len(self._buffer[self._frame])-1
+ self._ptr[self._frame] = len(self._buffer[self._frame]) - 1
def _valid_buffer(self):
return len(self._buffer[self._frame]) > 0
@@ -93,8 +97,8 @@ def redo(self):
return
self._ptr[self._frame] += 1
item = None
- if self._ptr[self._frame] > len(self._buffer[self._frame])-1:
- self._ptr[self._frame] = len(self._buffer[self._frame])-1
+ if self._ptr[self._frame] > len(self._buffer[self._frame]) - 1:
+ self._ptr[self._frame] = len(self._buffer[self._frame]) - 1
else:
item = self._buffer[self._frame][self._ptr[self._frame]]
return item
diff --git a/src/voxel.py b/src/voxel.py
index c8a3836..36304d2 100644
--- a/src/voxel.py
+++ b/src/voxel.py
@@ -43,6 +43,7 @@
# Occlusion factor
OCCLUSION = 0.7
+
class VoxelData(object):
# Constants for referring to axis
@@ -54,9 +55,11 @@ class VoxelData(object):
@property
def width(self):
return self._width
+
@property
def height(self):
return self._height
+
@property
def depth(self):
return self._depth
@@ -64,6 +67,7 @@ def depth(self):
@property
def changed(self):
return self._changed
+
@changed.setter
def changed(self, value):
if value and not self._changed:
@@ -76,6 +80,7 @@ def changed(self, value):
@property
def occlusion(self):
return self._occlusion
+
@occlusion.setter
def occlusion(self, value):
self._occlusion = value
@@ -114,7 +119,7 @@ def _initialise_data(self):
# Return an empty voxel space
def blank_data(self):
return [[[0 for _ in xrange(self.depth)]
- for _ in xrange(self.height)]
+ for _ in xrange(self.height)]
for _ in xrange(self.width)]
def is_valid_bounds(self, x, y, z):
@@ -143,7 +148,7 @@ def select_frame(self, frame_number):
self.changed = True
# Add a new frame by copying the current one
- def add_frame(self, index, copy_current = True):
+ def add_frame(self, index, copy_current=True):
if copy_current:
data = self.get_data()
else:
@@ -151,14 +156,14 @@ def add_frame(self, index, copy_current = True):
# If current frame is at the position of the new frame
# We must move out of the way.
if self._current_frame == index:
- self.select_frame(index-1)
+ self.select_frame(index - 1)
self._frames.insert(index, data)
self._undo.add_frame(index)
self._frame_count += 1
self.select_frame(index)
- def copy_to_current(self, index):
- data = self._frames[index-1]
+ def copy_to_current(self, index):
+ data = self._frames[index - 1]
self.set_data(data)
# Delete the current frame
@@ -183,16 +188,16 @@ def delete_frame(self):
# Change to the next frame (with wrap)
def select_next_frame(self):
- nextframe = self._current_frame+1
+ nextframe = self._current_frame + 1
if nextframe >= self._frame_count:
nextframe = 0
self.select_frame(nextframe)
# Change to the previous frame (with wrap)
def select_previous_frame(self):
- prevframe = self._current_frame-1
+ prevframe = self._current_frame - 1
if prevframe < 0:
- prevframe = self._frame_count-1
+ prevframe = self._frame_count - 1
self.select_frame(prevframe)
# Get current frame number
@@ -200,14 +205,14 @@ def get_frame_number(self):
return self._current_frame
# Set a voxel to the given state
- def set(self, x, y, z, state, undo = True, fill = 0):
+ def set(self, x, y, z, state, undo=True, fill=0):
# If this looks like a QT Color instance, convert it
if hasattr(state, "getRgb"):
c = state.getRgb()
- state = c[0]<<24 | c[1]<<16 | c[2]<<8 | 0xff
+ state = c[0] << 24 | c[1] << 16 | c[2] << 8 | 0xff
# Check bounds
- if ( not self.is_valid_bounds(x, y, z ) ):
+ if (not self.is_valid_bounds(x, y, z)):
return False
# Add to undo
if undo:
@@ -218,15 +223,15 @@ def set(self, x, y, z, state, undo = True, fill = 0):
self.completeUndoFill()
else:
self._undo.add(UndoItem(Undo.SET_VOXEL,
- (x, y, z, self._data[x][y][z]), (x, y, z, state)))
+ (x, y, z, self._data[x][y][z]), (x, y, z, state)))
# Set the voxel
self._data[x][y][z] = state
if state != EMPTY:
- if (x,y,z) not in self._cache:
- self._cache.append((x,y,z))
+ if (x, y, z) not in self._cache:
+ self._cache.append((x, y, z))
else:
- if (x,y,z) in self._cache:
- self._cache.remove((x,y,z))
+ if (x, y, z) in self._cache:
+ self._cache.remove((x, y, z))
self.changed = True
return True
@@ -237,7 +242,7 @@ def completeUndoFill(self):
# Get the state of the given voxel
def get(self, x, y, z):
- if ( not self.is_valid_bounds(x, y, z ) ):
+ if (not self.is_valid_bounds(x, y, z)):
return EMPTY
return self._data[x][y][z]
@@ -262,7 +267,7 @@ def get_vertices(self):
colour_ids = []
normals = []
uvs = []
- for x,y,z in self._cache:
+ for x, y, z in self._cache:
v, c, n, cid, uv = self._get_voxel_vertices(x, y, z)
vertices += v
colours += c
@@ -279,7 +284,7 @@ def saved(self):
# Count the number of non-empty voxels from the list of coordinates
def _count_voxels(self, coordinates):
count = 0
- for x,y,z in coordinates:
+ for x, y, z in coordinates:
if self.get(x, y, z) != EMPTY:
count += 1
return count
@@ -293,28 +298,28 @@ def _get_voxel_vertices(self, x, y, z):
uvs = []
# Remember voxel coordinates
- vx, vy, vz = x,y,z
+ vx, vy, vz = x, y, z
# Determine if we have filled voxels around us
- front = self.get(x, y, z-1) == EMPTY
- left = self.get(x-1, y, z) == EMPTY
- right = self.get(x+1, y, z) == EMPTY
- top = self.get(x, y+1, z) == EMPTY
- back = self.get(x, y, z+1) == EMPTY
- bottom = self.get(x, y-1, z) == EMPTY
+ front = self.get(x, y, z - 1) == EMPTY
+ left = self.get(x - 1, y, z) == EMPTY
+ right = self.get(x + 1, y, z) == EMPTY
+ top = self.get(x, y + 1, z) == EMPTY
+ back = self.get(x, y, z + 1) == EMPTY
+ bottom = self.get(x, y - 1, z) == EMPTY
# Get our colour
c = self.get(x, y, z)
- r = (c & 0xff000000)>>24
- g = (c & 0xff0000)>>16
- b = (c & 0xff00)>>8
+ r = (c & 0xff000000) >> 24
+ g = (c & 0xff0000) >> 16
+ b = (c & 0xff00) >> 8
# Calculate shades for our 4 occlusion levels
shades = []
for c in range(5):
shades.append((
- int(r*math.pow(OCCLUSION,c)),
- int(g*math.pow(OCCLUSION,c)),
- int(b*math.pow(OCCLUSION,c))))
+ int(r * math.pow(OCCLUSION, c)),
+ int(g * math.pow(OCCLUSION, c)),
+ int(b * math.pow(OCCLUSION, c))))
# Encode our voxel space coordinates as colours, used for face selection
# We use 7 bits per coordinate and the bottom 3 bits for face:
@@ -324,9 +329,9 @@ def _get_voxel_vertices(self, x, y, z):
# 3 - right
# 4 - back
# 5 - bottom
- voxel_id = (x & 0x7f)<<17 | (y & 0x7f)<<10 | (z & 0x7f)<<3
- id_r = (voxel_id & 0xff0000)>>16
- id_g = (voxel_id & 0xff00)>>8
+ voxel_id = (x & 0x7f) << 17 | (y & 0x7f) << 10 | (z & 0x7f) << 3
+ id_r = (voxel_id & 0xff0000) >> 16
+ id_g = (voxel_id & 0xff00) >> 8
id_b = (voxel_id & 0xff)
# Adjust coordinates to the origin
@@ -339,39 +344,39 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx,vy+1,vz-1) != EMPTY:
+ if self.get(vx, vy + 1, vz - 1) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx-1,vy,vz-1) != EMPTY:
+ if self.get(vx - 1, vy, vz - 1) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx+1,vy,vz-1) != EMPTY:
+ if self.get(vx + 1, vy, vz - 1) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx,vy-1,vz-1) != EMPTY:
+ if self.get(vx, vy - 1, vz - 1) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx-1,vy-1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz - 1) != EMPTY:
occ1 += 1
- if self.get(vx-1,vy+1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz - 1) != EMPTY:
occ2 += 1
- if self.get(vx+1,vy-1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz - 1) != EMPTY:
occ3 += 1
- if self.get(vx+1,vy+1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz - 1) != EMPTY:
occ4 += 1
- vertices += (x, y, z)
+ vertices += (x, y, z)
colours += shades[occ1]
- vertices += (x, y+1, z)
+ vertices += (x, y + 1, z)
colours += shades[occ2]
- vertices += (x+1, y, z)
+ vertices += (x + 1, y, z)
colours += shades[occ3]
- vertices += (x+1, y, z)
+ vertices += (x + 1, y, z)
colours += shades[occ3]
- vertices += (x, y+1, z)
+ vertices += (x, y + 1, z)
colours += shades[occ2]
- vertices += (x+1, y+1, z)
+ vertices += (x + 1, y + 1, z)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (0, 0, 1) * 6
colour_ids += (id_r, id_g, id_b) * 6
# Top face
@@ -381,39 +386,39 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx,vy+1,vz+1) != EMPTY:
+ if self.get(vx, vy + 1, vz + 1) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx-1,vy+1,vz) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx+1,vy+1,vz) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx,vy+1,vz-1) != EMPTY:
+ if self.get(vx, vy + 1, vz - 1) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx-1,vy+1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz - 1) != EMPTY:
occ1 += 1
- if self.get(vx+1,vy+1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz - 1) != EMPTY:
occ3 += 1
- if self.get(vx+1,vy+1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz + 1) != EMPTY:
occ4 += 1
- if self.get(vx-1,vy+1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz + 1) != EMPTY:
occ2 += 1
- vertices += (x, y+1, z)
+ vertices += (x, y + 1, z)
colours += shades[occ1]
- vertices += (x, y+1, z-1)
+ vertices += (x, y + 1, z - 1)
colours += shades[occ2]
- vertices += (x+1, y+1, z)
+ vertices += (x + 1, y + 1, z)
colours += shades[occ3]
- vertices += (x+1, y+1, z)
+ vertices += (x + 1, y + 1, z)
colours += shades[occ3]
- vertices += (x, y+1, z-1)
+ vertices += (x, y + 1, z - 1)
colours += shades[occ2]
- vertices += (x+1, y+1, z-1)
+ vertices += (x + 1, y + 1, z - 1)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (0, 1, 0) * 6
colour_ids += (id_r, id_g, id_b | 1) * 6
# Right face
@@ -423,39 +428,39 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx+1,vy+1,vz) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx+1,vy,vz-1) != EMPTY:
+ if self.get(vx + 1, vy, vz - 1) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx+1,vy,vz+1) != EMPTY:
+ if self.get(vx + 1, vy, vz + 1) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx+1,vy-1,vz) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx+1,vy-1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz - 1) != EMPTY:
occ1 += 1
- if self.get(vx+1,vy+1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz - 1) != EMPTY:
occ2 += 1
- if self.get(vx+1,vy-1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz + 1) != EMPTY:
occ3 += 1
- if self.get(vx+1,vy+1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz + 1) != EMPTY:
occ4 += 1
- vertices += (x+1, y, z)
+ vertices += (x + 1, y, z)
colours += shades[occ1]
- vertices += (x+1, y+1, z)
+ vertices += (x + 1, y + 1, z)
colours += shades[occ2]
- vertices += (x+1, y, z-1)
+ vertices += (x + 1, y, z - 1)
colours += shades[occ3]
- vertices += (x+1, y, z-1)
+ vertices += (x + 1, y, z - 1)
colours += shades[occ3]
- vertices += (x+1, y+1, z)
+ vertices += (x + 1, y + 1, z)
colours += shades[occ2]
- vertices += (x+1, y+1, z-1)
+ vertices += (x + 1, y + 1, z - 1)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (1, 0, 0) * 6
colour_ids += (id_r, id_g, id_b | 3) * 6
# Left face
@@ -465,39 +470,39 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx-1,vy+1,vz) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx-1,vy,vz+1) != EMPTY:
+ if self.get(vx - 1, vy, vz + 1) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx-1,vy,vz-1) != EMPTY:
+ if self.get(vx - 1, vy, vz - 1) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx-1,vy-1,vz) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx-1,vy-1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz + 1) != EMPTY:
occ1 += 1
- if self.get(vx-1,vy+1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz + 1) != EMPTY:
occ2 += 1
- if self.get(vx-1,vy-1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz - 1) != EMPTY:
occ3 += 1
- if self.get(vx-1,vy+1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz - 1) != EMPTY:
occ4 += 1
- vertices += (x, y, z-1)
+ vertices += (x, y, z - 1)
colours += shades[occ1]
- vertices += (x, y+1, z-1)
+ vertices += (x, y + 1, z - 1)
colours += shades[occ2]
vertices += (x, y, z)
colours += shades[occ3]
vertices += (x, y, z)
colours += shades[occ3]
- vertices += (x, y+1, z-1)
+ vertices += (x, y + 1, z - 1)
colours += shades[occ2]
- vertices += (x, y+1, z)
+ vertices += (x, y + 1, z)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (-1, 0, 0) * 6
colour_ids += (id_r, id_g, id_b | 2) * 6
# Back face
@@ -507,39 +512,39 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx,vy+1,vz+1) != EMPTY:
+ if self.get(vx, vy + 1, vz + 1) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx+1,vy,vz+1) != EMPTY:
+ if self.get(vx + 1, vy, vz + 1) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx-1,vy,vz+1) != EMPTY:
+ if self.get(vx - 1, vy, vz + 1) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx,vy-1,vz+1) != EMPTY:
+ if self.get(vx, vy - 1, vz + 1) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx+1,vy-1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz + 1) != EMPTY:
occ1 += 1
- if self.get(vx+1,vy+1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy + 1, vz + 1) != EMPTY:
occ2 += 1
- if self.get(vx-1,vy-1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz + 1) != EMPTY:
occ3 += 1
- if self.get(vx-1,vy+1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy + 1, vz + 1) != EMPTY:
occ4 += 1
- vertices += (x+1, y, z-1)
+ vertices += (x + 1, y, z - 1)
colours += shades[occ1]
- vertices += (x+1, y+1, z-1)
+ vertices += (x + 1, y + 1, z - 1)
colours += shades[occ2]
- vertices += (x, y, z-1)
+ vertices += (x, y, z - 1)
colours += shades[occ3]
- vertices += (x, y, z-1)
+ vertices += (x, y, z - 1)
colours += shades[occ3]
- vertices += (x+1, y+1, z-1)
+ vertices += (x + 1, y + 1, z - 1)
colours += shades[occ2]
- vertices += (x, y+1, z-1)
+ vertices += (x, y + 1, z - 1)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (0, 0, -1) * 6
colour_ids += (id_r, id_g, id_b | 4) * 6
# Bottom face
@@ -549,77 +554,76 @@ def _get_voxel_vertices(self, x, y, z):
occ3 = 0
occ4 = 0
if self._occlusion:
- if self.get(vx,vy-1,vz-1) != EMPTY:
+ if self.get(vx, vy - 1, vz - 1) != EMPTY:
occ2 += 1
occ4 += 1
- if self.get(vx-1,vy-1,vz) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz) != EMPTY:
occ1 += 1
occ2 += 1
- if self.get(vx+1,vy-1,vz) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz) != EMPTY:
occ3 += 1
occ4 += 1
- if self.get(vx,vy-1,vz+1) != EMPTY:
+ if self.get(vx, vy - 1, vz + 1) != EMPTY:
occ1 += 1
occ3 += 1
- if self.get(vx-1,vy-1,vz+1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz + 1) != EMPTY:
occ1 += 1
- if self.get(vx-1,vy-1,vz-1) != EMPTY:
+ if self.get(vx - 1, vy - 1, vz - 1) != EMPTY:
occ2 += 1
- if self.get(vx+1,vy-1,vz+1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz + 1) != EMPTY:
occ3 += 1
- if self.get(vx+1,vy-1,vz-1) != EMPTY:
+ if self.get(vx + 1, vy - 1, vz - 1) != EMPTY:
occ4 += 1
- vertices += (x, y, z-1)
+ vertices += (x, y, z - 1)
colours += shades[occ1]
vertices += (x, y, z)
colours += shades[occ2]
- vertices += (x+1, y, z-1)
+ vertices += (x + 1, y, z - 1)
colours += shades[occ3]
- vertices += (x+1, y, z-1)
+ vertices += (x + 1, y, z - 1)
colours += shades[occ3]
vertices += (x, y, z)
colours += shades[occ2]
- vertices += (x+1, y, z)
+ vertices += (x + 1, y, z)
colours += shades[occ4]
- uvs += (0,0,0,1,1,0,1,0,0,1,1,1)
+ uvs += (0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1)
normals += (0, -1, 0) * 6
colour_ids += (id_r, id_g, id_b | 5) * 6
return (vertices, colours, normals, colour_ids, uvs)
-
# Return vertices for a floor grid
def get_grid_vertices(self):
grid = []
- #builds the Y_plane
- for z in xrange(self.depth+1):
+ # builds the Y_plane
+ for z in xrange(self.depth + 1):
gx, gy, gz = self.voxel_to_world(0, 0, z)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(self.width, 0, z)
grid += (gx, gy, gz)
- for x in xrange(self.width+1):
+ for x in xrange(self.width + 1):
gx, gy, gz = self.voxel_to_world(x, 0, 0)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(x, 0, self.depth)
grid += (gx, gy, gz)
- #builds the Z_plane
- for x in xrange(self.width+1):
+ # builds the Z_plane
+ for x in xrange(self.width + 1):
gx, gy, gz = self.voxel_to_world(x, 0, self.depth)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(x, self.height, self.depth)
grid += (gx, gy, gz)
- for y in xrange(self.height+1):
+ for y in xrange(self.height + 1):
gx, gy, gz = self.voxel_to_world(0, y, self.depth)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(self.width, y, self.depth)
grid += (gx, gy, gz)
- #builds the X_plane
- for y in xrange(self.height+1):
+ # builds the X_plane
+ for y in xrange(self.height + 1):
gx, gy, gz = self.voxel_to_world(0, y, 0)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(0, y, self.depth)
grid += (gx, gy, gz)
- for z in xrange(self.depth+1):
+ for z in xrange(self.depth + 1):
gx, gy, gz = self.voxel_to_world(0, 0, z)
grid += (gx, gy, gz)
gx, gy, gz = self.voxel_to_world(0, self.height, z)
@@ -628,17 +632,17 @@ def get_grid_vertices(self):
# Convert voxel space coordinates to world space
def voxel_to_world(self, x, y, z):
- x = (x - self.width//2)-0.5
- y = (y - self.height//2)-0.5
- z = (z - self.depth//2)-0.5
+ x = (x - self.width // 2) - 0.5
+ y = (y - self.height // 2) - 0.5
+ z = (z - self.depth // 2) - 0.5
z = -z
return x, y, z
# Convert world space coordinates to voxel space
def world_to_voxel(self, x, y, z):
- x = (x + self.width//2)+0.5
- y = (y + self.height//2)+0.5
- z = (z - self.depth//2)-0.5
+ x = (x + self.width // 2) + 0.5
+ y = (y + self.height // 2) + 0.5
+ z = (z - self.depth // 2) - 0.5
z = -z
return x, y, z
@@ -677,15 +681,15 @@ def get_bounding_box(self):
minz = z
if z > maxz:
maxz = z
- width = (maxx-minx)+1
- height = (maxy-miny)+1
- depth = (maxz-minz)+1
+ width = (maxx - minx) + 1
+ height = (maxy - miny) + 1
+ depth = (maxz - minz) + 1
return minx, miny, minz, width, height, depth
# Resize the voxel space. If no dimensions given, adjust to bounding box.
# We offset all voxels on all axis by the given amount.
# Resize all animation frames
- def resize(self, width = None, height = None, depth = None, shift = 0):
+ def resize(self, width=None, height=None, depth=None, shift=0):
# Reset undo buffer
self._undo.clear()
# No dimensions, use bounding box
@@ -695,21 +699,21 @@ def resize(self, width = None, height = None, depth = None, shift = 0):
for i, frame in enumerate(self._frames):
# Create new data structure of the required size
data = [[[0 for _ in xrange(depth)]
- for _ in xrange(height)]
+ for _ in xrange(height)]
for _ in xrange(width)]
# Adjust ranges
movewidth = min(width, cwidth)
moveheight = min(height, cheight)
movedepth = min(depth, cdepth)
# Calculate translation
- dx = (0-mx)+shift
- dy = (0-my)+shift
- dz = (0-mz)+shift
+ dx = (0 - mx) + shift
+ dy = (0 - my) + shift
+ dz = (0 - mz) + shift
# Copy data over at new location
- for x in xrange(mx, mx+movewidth):
- for y in xrange(my, my+moveheight):
- for z in xrange(mz, mz+movedepth):
- data[x+dx][y+dy][z+dz] = frame[x][y][z]
+ for x in xrange(mx, mx + movewidth):
+ for y in xrange(my, my + moveheight):
+ for z in xrange(mz, mz + movedepth):
+ data[x + dx][y + dy][z + dz] = frame[x][y][z]
self._frames[i] = data
self._data = self._frames[self._current_frame]
# Set new dimensions
@@ -726,7 +730,7 @@ def rotate_about_axis(self, axis):
self._undo.clear()
if axis == self.Y_AXIS:
- width = self.depth # note swap
+ width = self.depth # note swap
height = self.height
depth = self.width
elif axis == self.X_AXIS:
@@ -742,7 +746,7 @@ def rotate_about_axis(self, axis):
# Create new temporary data structure
data = [[[0 for _ in xrange(depth)]
- for _ in xrange(height)]
+ for _ in xrange(height)]
for _ in xrange(width)]
# Copy data over at new location
@@ -750,16 +754,16 @@ def rotate_about_axis(self, axis):
for ty in xrange(0, self.height):
for tz in xrange(0, self.depth):
if axis == self.Y_AXIS:
- dx = (-tz)-1
+ dx = (-tz) - 1
dy = ty
dz = tx
elif axis == self.X_AXIS:
dx = tx
- dy = (-tz)-1
+ dy = (-tz) - 1
dz = ty
elif axis == self.Z_AXIS:
dx = ty
- dy = (-tx)-1
+ dy = (-tx) - 1
dz = tz
data[dx][dy][dz] = frame[tx][ty][tz]
self._frames[i] = data
@@ -782,7 +786,7 @@ def mirror_in_axis(self, axis):
# Create new temporary data structure
data = [[[0 for _ in xrange(self.depth)]
- for _ in xrange(self.height)]
+ for _ in xrange(self.height)]
for _ in xrange(self.width)]
# Copy data over at new location
@@ -791,16 +795,16 @@ def mirror_in_axis(self, axis):
for tz in xrange(0, self.depth):
if axis == self.Y_AXIS:
dx = tx
- dy = (-ty)-1
+ dy = (-ty) - 1
dz = tz
elif axis == self.X_AXIS:
- dx = (-tx)-1
+ dx = (-tx) - 1
dy = ty
dz = tz
elif axis == self.Z_AXIS:
dx = tx
dy = ty
- dz = (-tz)-1
+ dz = (-tz) - 1
data[dx][dy][dz] = frame[tx][ty][tz]
self._frames[i] = data
@@ -810,7 +814,7 @@ def mirror_in_axis(self, axis):
self.changed = True
# Translate the voxel data.
- def translate(self, x, y, z, undo = True):
+ def translate(self, x, y, z, undo=True):
# Sanity
if x == 0 and y == 0 and z == 0:
return
@@ -818,19 +822,19 @@ def translate(self, x, y, z, undo = True):
# Add to undo
if undo:
self._undo.add(UndoItem(Undo.TRANSLATE,
- (-x, -y, -z), (x, y, z)))
+ (-x, -y, -z), (x, y, z)))
# Create new temporary data structure
data = [[[0 for _ in xrange(self.depth)]
- for _ in xrange(self.height)]
+ for _ in xrange(self.height)]
for _ in xrange(self.width)]
# Copy data over at new location
for tx in xrange(0, self.width):
for ty in xrange(0, self.height):
for tz in xrange(0, self.depth):
- dx = (tx+x) % self.width
- dy = (ty+y) % self.height
- dz = (tz+z) % self.depth
+ dx = (tx + x) % self.width
+ dy = (ty + y) % self.height
+ dz = (tz + z) % self.depth
data[dx][dy][dz] = self._data[tx][ty][tz]
self._data = data
self._frames[self._current_frame] = self._data
@@ -873,5 +877,6 @@ def redo(self):
# Enable/Disable undo buffer
def disable_undo(self):
self._undo.enabled = False
+
def enable_undo(self):
self._undo.enabled = True
diff --git a/src/voxel_grid.py b/src/voxel_grid.py
index c53e3f2..f4fe59a 100644
--- a/src/voxel_grid.py
+++ b/src/voxel_grid.py
@@ -22,6 +22,8 @@
##
# Constants for the planes, to be used with a dictionary.
+
+
class GridPlanes(object):
X = "x"
Y = "y"
@@ -29,13 +31,16 @@ class GridPlanes(object):
##
# Represents a plane to be used in the grid
+
+
class GridPlane(object):
##
# @param voxels Reference to the VoxelData
# @param plane The plane where this grid belongs
# @param offset The offset of the plane, relative to their negative end ( X = Left, Y = Bottom, Z = Front )
# @param visible Indicates if the plane is visible or not
- def __init__( self, voxels, plane, offset, visible, color = QtGui.QColor("white") ):
+
+ def __init__(self, voxels, plane, offset, visible, color=QtGui.QColor("white")):
self._voxels = voxels
self._plane = plane
self._offset = 0
@@ -57,6 +62,7 @@ def __init__( self, voxels, plane, offset, visible, color = QtGui.QColor("white"
@property
def voxels(self):
return self._voxels
+
@voxels.setter
def voxels(self, voxels):
self._voxels = voxels
@@ -64,29 +70,32 @@ def voxels(self, voxels):
@property
def plane(self):
return self._plane
+
@plane.setter
def plane(self, value):
- assert value in ( GridPlanes.X, GridPlanes.Y, GridPlanes.Z )
- if( value != self._plane ):
+ assert value in (GridPlanes.X, GridPlanes.Y, GridPlanes.Z)
+ if(value != self._plane):
self._plane = value
self.update_vertices()
@property
def offset(self):
return self._offset
+
@offset.setter
def offset(self, value):
assert isinstance(value, int)
offset_limit = self._offset_plane_limit[self.plane]()
- if( value > offset_limit ):
+ if(value > offset_limit):
value = offset_limit
- if( value != self._offset ):
+ if(value != self._offset):
self._offset = value
self.update_vertices()
@property
def visible(self):
return self._visible
+
@visible.setter
def visible(self, value):
assert isinstance(value, bool)
@@ -95,9 +104,10 @@ def visible(self, value):
@property
def color(self):
return self._color
+
@color.setter
def color(self, value):
- assert isinstance( value, QtGui.QColor )
+ assert isinstance(value, QtGui.QColor)
self._color = value
@property
@@ -107,67 +117,68 @@ def vertices(self):
def update_vertices(self):
self._vertices = self._methods_get_plane_vertices[self._plane]()
self._vertices_array = array.array("f", self._vertices).tostring()
- self._num_vertices = len(self._vertices)//3
+ self._num_vertices = len(self._vertices) // 3
def _get_grid_vertices_x_plane(self):
vertices = []
height = self._voxels.height
depth = self._voxels.depth
- for y in xrange(height+1):
- vertices += self._voxels.voxel_to_world( self.offset, y, 0 )
- vertices += self._voxels.voxel_to_world( self.offset, y, depth )
- for z in xrange(depth+1):
- vertices += self._voxels.voxel_to_world( self.offset, 0, z )
- vertices += self._voxels.voxel_to_world( self.offset, height, z )
+ for y in xrange(height + 1):
+ vertices += self._voxels.voxel_to_world(self.offset, y, 0)
+ vertices += self._voxels.voxel_to_world(self.offset, y, depth)
+ for z in xrange(depth + 1):
+ vertices += self._voxels.voxel_to_world(self.offset, 0, z)
+ vertices += self._voxels.voxel_to_world(self.offset, height, z)
return vertices
def _get_grid_vertices_y_plane(self):
vertices = []
width = self._voxels.width
depth = self._voxels.depth
- for z in xrange(depth+1):
- vertices += self._voxels.voxel_to_world( 0, self.offset, z )
- vertices += self._voxels.voxel_to_world( width, self.offset, z )
- for x in xrange(width+1):
- vertices += self._voxels.voxel_to_world( x, self.offset, 0 )
- vertices += self._voxels.voxel_to_world( x, self.offset, depth )
+ for z in xrange(depth + 1):
+ vertices += self._voxels.voxel_to_world(0, self.offset, z)
+ vertices += self._voxels.voxel_to_world(width, self.offset, z)
+ for x in xrange(width + 1):
+ vertices += self._voxels.voxel_to_world(x, self.offset, 0)
+ vertices += self._voxels.voxel_to_world(x, self.offset, depth)
return vertices
def _get_grid_vertices_z_plane(self):
vertices = []
width = self._voxels.width
height = self._voxels.height
- for x in xrange(width+1):
- vertices += self._voxels.voxel_to_world( x, 0, self.offset )
- vertices += self._voxels.voxel_to_world( x, height, self.offset )
- for y in xrange(height+1):
- vertices += self._voxels.voxel_to_world( 0, y, self.offset )
- vertices += self._voxels.voxel_to_world( width, y, self.offset )
+ for x in xrange(width + 1):
+ vertices += self._voxels.voxel_to_world(x, 0, self.offset)
+ vertices += self._voxels.voxel_to_world(x, height, self.offset)
+ for y in xrange(height + 1):
+ vertices += self._voxels.voxel_to_world(0, y, self.offset)
+ vertices += self._voxels.voxel_to_world(width, y, self.offset)
return vertices
+
class VoxelGrid(object):
- def __init__(self, widget ):
+ def __init__(self, widget):
self._voxels = widget
self._planes = {}
- def add_grid_plane(self, plane, offset, visible, color = QtGui.QColor("white") ):
+ def add_grid_plane(self, plane, offset, visible, color=QtGui.QColor("white")):
key = (plane, offset)
- if( key in self._planes.keys() ):
+ if(key in self._planes.keys()):
self._planes[key].visible = visible
else:
- grid_plane = GridPlane( self._voxels, plane, offset, visible, color )
+ grid_plane = GridPlane(self._voxels, plane, offset, visible, color)
self._planes[key] = grid_plane
def remove_grid_plane(self, plane, offset):
key = (plane, offset)
- if( key in self._planes.keys() ):
+ if(key in self._planes.keys()):
del self._planes[key]
# Return vertices for a floor grid
def get_grid_plane(self, plane, offset):
- key = ( plane, offset )
- if( key in self._planes.keys() ):
+ key = (plane, offset)
+ if(key in self._planes.keys()):
return self._planes[key]
else:
return None
@@ -186,14 +197,14 @@ def paint(self):
glDisable(GL_TEXTURE_2D)
for grid in self._planes.itervalues():
- if( not grid.visible ):
+ if(not grid.visible):
continue
red = grid.color.redF()
green = grid.color.greenF()
blue = grid.color.blueF()
# Grid colour
- glColor3f(red,green,blue)
+ glColor3f(red, green, blue)
# Enable vertex buffers
glEnableClientState(GL_VERTEX_ARRAY)
@@ -211,11 +222,11 @@ def paint(self):
glEnable(GL_LIGHTING)
glEnable(GL_TEXTURE_2D)
- def scale_offsets(self, width_scale = None, height_scale = None, depth_scale = None ):
+ def scale_offsets(self, width_scale=None, height_scale=None, depth_scale=None):
for grid in self._planes.itervalues():
- if( grid.plane == GridPlanes.X and width_scale ):
+ if(grid.plane == GridPlanes.X and width_scale):
grid.offset = int(round(grid.offset * width_scale))
- elif( grid.plane == GridPlanes.Y and height_scale ):
+ elif(grid.plane == GridPlanes.Y and height_scale):
grid.offset = int(round(grid.offset * height_scale))
- elif( grid.plane == GridPlanes.Z and depth_scale ):
+ elif(grid.plane == GridPlanes.Z and depth_scale):
grid.offset = int(round(grid.offset * depth_scale))
diff --git a/src/voxel_widget.py b/src/voxel_widget.py
index 5daf286..d1b2ec3 100644
--- a/src/voxel_widget.py
+++ b/src/voxel_widget.py
@@ -28,6 +28,7 @@
from voxel_grid import VoxelGrid
import time
+
class GLWidget(QtOpenGL.QGLWidget):
# Constants for referring to axis
@@ -43,6 +44,7 @@ class GLWidget(QtOpenGL.QGLWidget):
@property
def axis_grids(self):
return self._display_axis_grids
+
@axis_grids.setter
def axis_grids(self, value):
self._display_axis_grids = value
@@ -51,6 +53,7 @@ def axis_grids(self, value):
@property
def wireframe(self):
return self._display_wireframe
+
@wireframe.setter
def wireframe(self, value):
self._display_wireframe = value
@@ -59,6 +62,7 @@ def wireframe(self, value):
@property
def voxel_colour(self):
return self._voxel_colour
+
@voxel_colour.setter
def voxel_colour(self, value):
self._voxel_colour = value
@@ -66,6 +70,7 @@ def voxel_colour(self, value):
@property
def background(self):
return self._background_colour
+
@background.setter
def background(self, value):
self._background_colour = value
@@ -74,6 +79,7 @@ def background(self, value):
@property
def voxel_edges(self):
return self._voxeledges
+
@voxel_edges.setter
def voxel_edges(self, value):
self._voxeledges = value
@@ -89,7 +95,7 @@ def grids(self):
drag_event = QtCore.Signal()
end_drag_event = QtCore.Signal()
- def __init__(self, parent = None):
+ def __init__(self, parent=None):
glformat = QtOpenGL.QGLFormat()
glformat.setVersion(1, 1)
glformat.setProfile(QtOpenGL.QGLFormat.CoreProfile)
@@ -106,9 +112,9 @@ def __init__(self, parent = None):
# Mouse position
self._mouse = QtCore.QPoint()
self._mouse_absolute = QtCore.QPoint()
- self.mouse_delta_relative = (0,0)
- self.mouse_delta_absolute = (0,0)
- self.mouse_position = (0,0)
+ self.mouse_delta_relative = (0, 0)
+ self.mouse_delta_absolute = (0, 0)
+ self.mouse_position = (0, 0)
# Default camera
self.reset_camera(False)
# zoom
@@ -124,12 +130,12 @@ def __init__(self, parent = None):
# Grid manager
self._grids = VoxelGrid(self.voxels)
# create the default _grids
- self.grids.add_grid_plane(GridPlanes.X, offset = 0, visible = True,
- color = QtGui.QColor(0x6c, 0x7d, 0x67))
- self.grids.add_grid_plane(GridPlanes.Y, offset = 0, visible = True,
- color = QtGui.QColor(0x65, 0x65, 0x7b))
- self.grids.add_grid_plane(GridPlanes.Z, offset = self.voxels.depth,
- visible = True, color = QtGui.QColor(0x7b, 0x65, 0x68))
+ self.grids.add_grid_plane(GridPlanes.X, offset=0, visible=True,
+ color=QtGui.QColor(0x6c, 0x7d, 0x67))
+ self.grids.add_grid_plane(GridPlanes.Y, offset=0, visible=True,
+ color=QtGui.QColor(0x65, 0x65, 0x7b))
+ self.grids.add_grid_plane(GridPlanes.Z, offset=self.voxels.depth,
+ visible=True, color=QtGui.QColor(0x7b, 0x65, 0x68))
# Used to track the z component of various mouse activity
self._depth_focus = 1
# Keep track how long mouse buttons are down for
@@ -151,7 +157,7 @@ def refresh(self):
self.updateGL()
# Reset camera position to defaults
- def reset_camera(self, update = True):
+ def reset_camera(self, update=True):
self._translate_x = 0
self._translate_y = 0
self._translate_z = -30
@@ -319,7 +325,7 @@ def mousePressEvent(self, event):
self._mouse = QtCore.QPoint(event.pos())
self._mouse_absolute = QtCore.QPoint(event.pos())
- self.mouse_position = (self._mouse.x(),self._mouse.y())
+ self.mouse_position = (self._mouse.x(), self._mouse.y())
self._button_down = None
if event.buttons() & QtCore.Qt.LeftButton:
@@ -353,14 +359,14 @@ def mousePressEvent(self, event):
def mouseMoveEvent(self, event):
- self.mouse_position = (self._mouse.x(),self._mouse.y())
+ self.mouse_position = (self._mouse.x(), self._mouse.y())
ctrl = (self._key_modifiers
& QtCore.Qt.KeyboardModifier.ControlModifier) != 0
shift = (self._key_modifiers
& QtCore.Qt.KeyboardModifier.ShiftModifier) != 0
alt = (self._key_modifiers
- & QtCore.Qt.KeyboardModifier.AltModifier) != 0
+ & QtCore.Qt.KeyboardModifier.AltModifier) != 0
# Screen units delta
dx = event.x() - self._mouse.x()
@@ -369,7 +375,7 @@ def mouseMoveEvent(self, event):
# Right mouse button held down with CTRL/cmd key - rotate
# Or middle mouse button held
if ((event.buttons() & QtCore.Qt.RightButton and ctrl)
- or ((event.buttons() & QtCore.Qt.MiddleButton) and not ctrl)):
+ or ((event.buttons() & QtCore.Qt.MiddleButton) and not ctrl)):
self._rotating = True
self._rotate_x = self._rotate_x + dy
self._rotate_y = self._rotate_y + dx
@@ -378,7 +384,7 @@ def mouseMoveEvent(self, event):
# Middle mouse button held down with CTRL - translate
# or right mouse button with alt
elif ((event.buttons() & QtCore.Qt.MiddleButton and ctrl)
- or (event.buttons() & QtCore.Qt.RightButton and alt)):
+ or (event.buttons() & QtCore.Qt.RightButton and alt)):
self._rotating = True
# Work out the translation in 3d space
self._translate_x = self._translate_x + dx * self._htranslate
@@ -389,7 +395,7 @@ def mouseMoveEvent(self, event):
# Remember the mouse deltas
self.mouse_delta_relative = (dx, dy)
self.mouse_delta_absolute = (event.x() - self._mouse_absolute.x(),
- event.y() - self._mouse_absolute.y())
+ event.y() - self._mouse_absolute.y())
# Maybe we are dragging
if time.time() - self._mousedown_time > 0.3 and not self._dragging:
@@ -483,7 +489,7 @@ def plane_intersection(self, x, y):
planes = (
Plane(Vector3(1, 0, 0), origin[0]),
Plane(Vector3(0, 1, 0), origin[1]),
- Plane(Vector3(0, 0, 1), origin[2]+0.001))
+ Plane(Vector3(0, 0, 1), origin[2] + 0.001))
intersection = None, None, None
distance = sys.maxint
for plane in planes:
@@ -492,7 +498,7 @@ def plane_intersection(self, x, y):
if intersect:
# Adjust to voxel space coordinates
x, y, z = self.voxels.world_to_voxel(intersect.x,
- intersect.y, intersect.z)
+ intersect.y, intersect.z)
x = int(x)
y = int(y)
z = int(z)
@@ -522,7 +528,7 @@ def view_axis(self):
# Convert window x,y coordinates into x,y,z world coordinates, also return
# the depth
- def window_to_world(self, x, y, z = None):
+ def window_to_world(self, x, y, z=None):
# Find depth
y = self._height - y
if z is None:
diff --git a/src/zoxel.py b/src/zoxel.py
index 8869c6d..f7a33b7 100644
--- a/src/zoxel.py
+++ b/src/zoxel.py
@@ -19,6 +19,7 @@
from PySide import QtGui
from mainwindow import MainWindow
+
def main():
# create application
app = QtGui.QApplication(sys.argv)