Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/volumeobject.py
diff options
context:
space:
mode:
authorpmoxhay <pmoxhay@earthlink.net>2009-02-28 18:15:02 (GMT)
committer pmoxhay <pmoxhay@earthlink.net>2009-02-28 18:15:02 (GMT)
commit4684498585d38d95bbc97fd2ffc2e279fef87bfd (patch)
treef722f05d918db807ed10e5bc216863363fe98a23 /volumeobject.py
parentbb29c1b4b54d558659fcd54a11437751ba89c9d0 (diff)
Several volume problems are now functional.
Need to animate filling and pouring.
Diffstat (limited to 'volumeobject.py')
-rw-r--r--volumeobject.py237
1 files changed, 162 insertions, 75 deletions
diff --git a/volumeobject.py b/volumeobject.py
index 980aef7..b35881b 100644
--- a/volumeobject.py
+++ b/volumeobject.py
@@ -39,8 +39,13 @@ class VolumeObject(ShapeObject):
self.lower_radius = lower_radius
self.upper_radius = upper_radius
+ self.water_height = 0
+ self.water_lower_radius = lower_radius
+ self.water_upper_radius = lower_radius
+
self.pos = pos
self.volume = self.calculate_volume()
+ self.water_volume = self.calculate_water_volume()
self.selectable = True
@@ -48,12 +53,101 @@ class VolumeObject(ShapeObject):
self.rotatable = False
self.calculate_bounds()
- print "VolumeObject constructor: volume =", self.volume
+ self.contains_water = False
+ self.full = False
+
+ #print "VolumeObject constructor: volume =", self.volume
def calculate_volume(self):
- return (math.pi * self.height / 3.0) *(self.lower_radius * self.lower_radius + self.lower_radius * self.upper_radius + self.upper_radius * self.upper_radius)
+ return (math.pi * self.height / 3.0) * \
+ (self.lower_radius * self.lower_radius + self.lower_radius * self.upper_radius + self.upper_radius * self.upper_radius)
+
+ def calculate_water_volume(self):
+ return (math.pi * self.water_height / 3.0) * \
+ (self.lower_radius * self.lower_radius + self.lower_radius * self.water_upper_radius + self.water_upper_radius * self.water_upper_radius)
+
+ def fill_to_given_volume(self, volume):
+ #print "******fill_to_given_volume called: volume =", volume
+ a = (self.upper_radius - self.lower_radius)**2
+ #print " a =", a
+ b = 3.0 * self.lower_radius * (self.upper_radius - self.lower_radius)
+ #print " b =", b
+ c = 3.0 * self.lower_radius ** 2
+ #print " c =", c
+ d = -3.0 * volume/(math.pi * self.height)
+ #print " d =", d
+
+ solution = self.cubic(a, b, c, d)
+ #print " solution =", solution
+
+ if volume <= 0.0:
+ self.water_height = 0.0
+ self.water_upper_radius = self.lower_radius
+ else:
+ self.water_height = solution[0] * self.height
+ self.water_upper_radius = self.lower_radius + self.water_height * (self.upper_radius - self.lower_radius)/self.height
+
+ #print "******fill_to_given_volume called: self.upper_radius =", self.upper_radius
+ #print "******fill_to_given_volume called: self.water_upper_radius =", self.water_upper_radius
+
+ self.water_volume = self.calculate_water_volume()
+
+ # Solve a cubic equation.
+ def cubic(self, a, b, c, d=None):
+ from math import cos
+
+ if a == 0:
+ return self.quadratic(b, c, d)[0], self.quadratic(b, c, d)[1], 0
+
+ if d:
+ # (ax^3 + bx^2 + cx + d = 0)
+ a, b, c = b / float(a), c / float(a), d / float(a)
+
+ t = a / 3.0
+ p, q = b - 3 * t**2, c - b * t + 2 * t**3
+ u, v = self.quadratic(q, -(p/3.0)**3)
+
+ if type(u) == type(0j):
+ # Complex cube root.
+ r, w = polar(u.real, u.imag)
+ y1 = 2 * self.cbrt(r) * cos(w / 3.0)
+ else:
+ # Real root .
+ y1 = self.cbrt(u) + self.cbrt(v)
+ y2, y3 = self.quadratic(y1, p + y1**2)
+
+ return y1 - t, y2 - t, y3 - t
+
+ # Solve a quadratic equation.
+ def quadratic(self, a, b, c=None):
+ import math, cmath
+
+ if a == 0:
+ return -c/float(b), 0
+
+ if c: # (ax^2 + bx + c = 0)
+ a, b = b / float(a), c / float(a)
+ t = a / 2.0
+ r = t**2 - b
+ if r >= 0:
+ # Real roots.
+ y1 = math.sqrt(r)
+ else:
+ # Complex roots.
+ y1 = cmath.sqrt(r)
+
+ y2 = -y1
+ return y1 - t, y2 - t
+ # Calculate a cube root.
+ def cbrt(self, x):
+ from math import pow
+ if x >= 0:
+ return pow(x, 1.0/3.0)
+ else:
+ return -pow(abs(x), 1.0/3.0)
+
# Modify to take into account trapezoids above and to the right.
def is_in_container(self):
for p in self.points:
@@ -64,40 +158,96 @@ class VolumeObject(ShapeObject):
return True
def draw_ellipse(self, cr, x, y, width, height):
- cr.save();
- cr.translate (x + width / 2., y + height / 2.);
- cr.scale(width / 2., height / 2.);
- cr.arc(0., 0., 1., 0., 2 * math.pi);
+ cr.save()
+ cr.translate (x + width / 2., y + height / 2.)
+ cr.scale(width / 2., height / 2.)
+ cr.arc(0., 0., 1., 0., 2 * math.pi)
+ cr.restore()
+
+ def fill_ellipse(self, cr, x, y, width, height):
+ cr.save()
+ cr.translate (x + width / 2., y + height / 2.)
+ cr.scale(width / 2., height / 2.)
+ cr.arc(0., 0., 1., 0., 2 * math.pi)
+ cr.set_source_rgb(0.37, 0.74, 1.0)
+ cr.fill()
cr.restore();
def draw(self, cr):
cr.scale(self.scale, self.scale)
-
+
# Transform the points.
points = [self.transform_point(p) for p in self.points]
+ water_points = points
+ water_points = [
+ Vector(water_points[0].x + (self.upper_radius - self.lower_radius) * (self.height - self.water_height)/float(self.height), water_points[0].y - self.height + self.water_height), \
+ Vector(water_points[1].x - (self.upper_radius - self.lower_radius) * (self.height - self.water_height)/float(self.height), water_points[1].y - self.height + self.water_height), \
+ Vector(water_points[2].x, water_points[2].y), \
+ Vector(water_points[3].x, water_points[3].y)]
+
+ water_points[0] = Vector(water_points[0].x, water_points[3].y - self.water_height)
+ water_points[1] = Vector(water_points[1].x, water_points[2].y - self.water_height)
+ water_points[2] = Vector(water_points[2].x, water_points[2].y)
+ water_points[3] = Vector(water_points[3].x, water_points[3].y)
+
+ # Draw the water, if any.
+ cr.save()
+ # Generate the shape.
+ cr.move_to(water_points[0].x, water_points[0].y)
+ for p in water_points:
+ cr.line_to(p.x, p.y)
+ cr.line_to(water_points[0].x, water_points[0].y)
+ cr.close_path()
+
+ #Draw the fill.s
+ cr.set_source_rgb(0.37, 0.74, 1.0)
+ cr.fill()
+ cr.restore()
+
+ # Fill in the lower ellipse.
+ cr.save()
+ if not self.water_height == 0:
+ self.fill_ellipse(cr, self.pos.x - self.lower_radius, self.pos.y + self.height/2.0 - self.lower_radius/4.0, 2.0 * self.lower_radius, self.lower_radius/2.0)
+ cr.restore()
+
+ # Fill in the upper ellipse.
+ cr.save()
+ if not self.water_height == 0:
+ self.fill_ellipse(cr, self.pos.x - self.water_upper_radius, self.pos.y + self.height/2.0 - self.water_height - self.water_upper_radius/4.0, \
+ 2.0 * self.water_upper_radius, self.water_upper_radius/2.0)
+ cr.restore()
+
+ # Draw the upper ellipse
+ if not self.water_height == 0:
+ cr.save()
+ cr.set_source_rgb(0.0, 0.0, 1.0)
+ cr.set_line_width(4.0)
+ self.draw_ellipse(cr, self.pos.x - self.water_upper_radius, self.pos.y + self.height/2.0 - self.water_height - self.water_upper_radius/4.0, 2.0 * self.water_upper_radius, self.water_upper_radius/2.0)
+ cr.stroke()
+ cr.restore()
# Generate the shape.
cr.move_to(points[1].x, points[1].y)
cr.line_to(points[2].x, points[2].y)
-
+
# Draw the outline.
if self.selected:
cr.set_dash((10, 10), 0)
cr.set_source_rgb(0.0, 0.0, 0.0)
cr.set_line_width(4.0)
cr.stroke()
-
+
# Generate the shape.
cr.move_to(points[0].x, points[0].y)
cr.line_to(points[3].x, points[3].y)
-
+
# Draw the outline.
if self.selected:
cr.set_dash((10, 10), 0)
cr.set_source_rgb(0.0, 0.0, 0.0)
cr.set_line_width(4.0)
cr.stroke()
-
+
# Draw the lower ellipse
cr.save()
if self.selected:
@@ -107,18 +257,16 @@ class VolumeObject(ShapeObject):
self.draw_ellipse(cr, self.pos.x - self.lower_radius, self.pos.y + self.height/2.0 - self.lower_radius/4.0, 2.0 * self.lower_radius, self.lower_radius/2.0)
cr.stroke()
cr.restore()
-
+
# Draw the upper ellipse
cr.save()
if self.selected:
cr.set_dash((10, 10), 0)
cr.set_source_rgb(0.0, 0.0, 0.0)
cr.set_line_width(4.0)
- #cr.arc(self.pos.x, self.pos.y - self.size.y/2, self.size.x/2, 0.0, 2.0 * math.pi)
self.draw_ellipse(cr, self.pos.x - self.upper_radius, self.pos.y - self.height/2.0 - self.upper_radius/4.0, 2.0 * self.upper_radius, self.upper_radius/2.0)
cr.stroke()
cr.restore()
-
# Draw the symbol (capital letter representing the shapes's area).
if self.symbol_visible:
@@ -128,64 +276,3 @@ class VolumeObject(ShapeObject):
cr.move_to(self.pos.x - x_bearing - width/2, self.pos.y - y_bearing - height/2)
cr.show_text(self.symbol)
- ## Algorithm to test whether point is inside the polygon
- #def contains_point(self, pos):
- # n = 0
- # p = pos
- #
- # for i in range (0, len(self.points) ):
- # p1 = self.points[i]
- # p2 = self.points[(i+1) % len(self.points)]
- #
- # p1 = self.transform_point(p1)
- # p2 = self.transform_point(p2)
- #
- # if p.y > min(p1.y, p2.y):
- # if p.y <= max(p1.y, p2.y):
- # if p.x <= max(p1.x, p2.x):
- # if p1.y != p2.y:
- # x = (p.y-p1.y)*(p2.x-p1.x)/(p2.y-p1.y)+p1.x
- # if p1.x == p2.x or p.x <= x:
- # n = n + 1
- #
- # if n % 2 == 0:
- # return(False)
- # else:
- # return(True)
- #
- #def is_in_container(self):
- # for p in self.points:
- # p = self.transform_point(p)
- # if p.x < -2 or p.x > DRAGGING_RECT_WIDTH + 2 or \
- # p.y < -1 or p.y > DRAGGING_RECT_HEIGHT:
- # return False
- # return True
- #
- #def move(self, pos):
- # # Tentatively place in the object in the new position
- # last_pos = self.pos
- # self.pos = pos
- #
- # # If any point is out of bounds, move object back to last position.
- # if not self.is_in_container():
- # self.pos = last_pos
- #
- # self.calculate_bounds()
- #
- # if self.container:
- # self.container.queue_draw()
- #
- #def rotate(self, angle):
- # # Tentatively rotate the object to the new angle
- # last_angle = self.angle
- # self.angle = angle
- #
- # # If any point is out of bounds, move object back to last angle.
- # if not self.is_in_container():
- # self.angle = last_angle
- #
- # self.calculate_bounds()
- #
- # self.container.queue_draw()
- #
- #