Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/threedobject.py
diff options
context:
space:
mode:
authorpmoxhay <pmoxhay@earthlink.net>2009-06-03 18:17:33 (GMT)
committer pmoxhay <pmoxhay@earthlink.net>2009-06-03 18:17:33 (GMT)
commitce10acc9fd1b02ca9a455fdf9b098432b622636b (patch)
tree76b5a70ec07597fd7389420011511f1010e601ce /threedobject.py
parent92999db805438b80fb505038dc65c55af00cd484 (diff)
Masses no longer disappear in AnswerBox.
Diffstat (limited to 'threedobject.py')
-rw-r--r--threedobject.py290
1 files changed, 276 insertions, 14 deletions
diff --git a/threedobject.py b/threedobject.py
index eebc348..b42e54d 100644
--- a/threedobject.py
+++ b/threedobject.py
@@ -20,25 +20,126 @@ from movableobject import MovableObject
import gtk, math
class ThreeDObject(MovableObject):
- """Quasi three-dimensional object."""
+ """Movable pseudo-three-dimensional shape object."""
- def __init__(self, color, symbol, size, pos, mass=1):
- #print "ThreeDObject constructor called: size =", size
+ def __init__(self, color, symbol, points, pos, angle, mass=1):
MovableObject.__init__(self)
self.color = color
self.symbol = symbol
- self.size = size
- self.width = size.x
- self.height = size.y
+ self.points = points
self.pos = pos
+ self.angle = angle
+
+ #print "ThreeDObject constructor: points =", self.points
+
+ self.area = 0
+ self.centroid = Vector(0, 0)
+ self.bounds_min = Vector(0, 0)
+ self.bounds_max = Vector(0, 0)
+
self.mass = mass
+ #self.size = Vector(150, 200)
+ #self.size = Vector(125, 225)
+
+ self.rotatable = False
self.selectable = True
+
+ # Calculate the area and centroid of the shape
+ self.calculate_area_and_centroid()
+
+ # Transform the points of the polygon to center-of-mass coordinates
+ self.points = [p - self.centroid for p in self.points]
+
+ # Get the current bounding rectangle.
+ self.calculate_bounds()
self.symbol_visible = True
- self.rotatable = False
+
+ def calculate_area_and_centroid(self):
+ # Calculate the area.
+ self.area = 0
+ for i in range (0, len(self.points) ):
+ p1 = self.points[i]
+ p2 = self.points[(i+1) % len(self.points)]
+ self.area += (p1.x*p2.y - p2.x*p1.y)/2
+
+ # Need to take absolute value?
+ #self.area = abs(self.area)
+
+ # Calculate the centroid (center of mass).
+ self.centroid = Vector(1, 1)
+ for i in range (0, len(self.points) ):
+ p1 = self.points[i]
+ p2 = self.points[(i+1) % len(self.points)]
+ self.centroid += (p1+p2) * (p1.x*p2.y - p2.x*p1.y) / (6 * self.area)
+
+ # Calculate the "move only" radius (the radius of a circle whose area is half the area of the shape).
+ # (Modify for a long, thin object?)
+ self.move_only_radius = math.sqrt(self.area/(2 * math.pi))
+ def calculate_bounds(self):
+ # Get the current width and height of the bounding rectangle.
+ self.bounds_min = Vector(float('inf'), float('inf'))
+ self.bounds_max = Vector(float('-inf'), float('-inf'))
+ for p in self.points:
+ p = self.transform_point(p)
+ p = p.scaled(self.scale)
+ self.bounds_min = self.bounds_min.min(p)
+ self.bounds_max = self.bounds_max.max(p)
+
+ # Adjust the bounds to show the trapezoids.
+ self.bounds_min -= Vector(2, 2 + self.scale * 50)
+ self.bounds_max += Vector(2, 2)
+
+ def get_bounds(self):
+ return self.bounds_min, self.bounds_max
+
+ def transform_point(self, p):
+ return p.rotate(self.angle) + self.pos
+
+ def inside_move_area(self, point):
+ self.point = point
+ boolean = False
+
+ # If the point is near the center of the object, return True.
+ if ((self.point - self.pos).length() < self.move_only_radius):
+ boolean = True
+
+ return boolean
+
+ # Enables user to "see both areas" in answer box by clicking.
+ def select_by_button_press(self):
+ other = None
+
+ self.container.select_object(self)
+
+ if self.in_answer_box and (self.container.problem_type == 'area' or self.container.problem_type == 'cutting'):
+ i = 0
+
+ for o in self.container.objects:
+ if isinstance(o, ShapeObject):
+ if not o == self:
+ other = o
+ i += 1
+
+ if not self.selected:
+ self.container.select_object(self)
+ else:
+ self.container.select_object(other)
+
+ # Switch self and other to make selection work correctly in answer box?
+ #if not self.selected:
+ # self.container.select_object(other)
+ #else:
+ # self.container.select_object(self)
+
+ self.container.adjust_tab_order()
+
+ else:
+ self.container.select_object(self)
+
def draw_poly(self, cr, points):
# Generate the shape.
cr.move_to(points[0].x, points[0].y)
@@ -67,10 +168,10 @@ class ThreeDObject(MovableObject):
# Calculate the points.
front_points = [
- self.pos + Vector(-self.size.x/2, -self.size.y/2),
- self.pos + Vector( self.size.x/2, -self.size.y/2),
- self.pos + Vector( self.size.x/2, self.size.y/2),
- self.pos + Vector(-self.size.x/2, self.size.y/2) ]
+ self.pos + self.points[0],
+ self.pos + self.points[1],
+ self.pos + self.points[2],
+ self.pos + self.points[3] ]
back_points = [p + Vector(50, -50) for p in front_points]
@@ -89,8 +190,169 @@ class ThreeDObject(MovableObject):
x_bearing, y_bearing, width, height = cr.text_extents(self.symbol)[:4]
cr.move_to(self.pos.x - x_bearing - width/2, self.pos.y - y_bearing - height/2)
cr.show_text(self.symbol)
+
+ #def draw(self, cr):
+ # cr.scale(self.scale, self.scale)
+ #
+ # # Transform the points.
+ # points = [self.transform_point(p) for p in self.points]
+ #
+ # # Generate the shape.
+ # cr.move_to(points[0].x, points[0].y)
+ # for p in points:
+ # cr.line_to(p.x, p.y)
+ # cr.line_to(points[0].x, points[0].y)
+ # cr.close_path()
+ #
+ # # Draw the fill.
+ # if self.selected:
+ # cr.set_source_rgb(self.color[0]*1.6, self.color[1]*1.6, self.color[2]*1.6)
+ # else:
+ # cr.set_source_rgb(self.color[0], self.color[1], self.color[2])
+ # cr.fill_preserve()
+ #
+ # # Draw the outline.
+ # if self.selected:
+ # cr.set_dash((10, 10), 0)
+ # cr.set_source_rgb(self.color[0]*0.75, self.color[1]*0.75, self.color[2]*0.75)
+ # cr.set_line_width(4.0)
+ # cr.stroke()
+ #
+ # # Draw the symbol (capital letter representing the shapes's area).
+ # if self.symbol_visible:
+ # cr.set_source_rgb(0, 0, 0)
+ # cr.set_font_size(50)
+ # x_bearing, y_bearing, width, height = cr.text_extents(self.symbol)[:4]
+ # cr.move_to(self.pos.x - x_bearing - width/2, self.pos.y - y_bearing - height/2)
+ # cr.show_text(self.symbol)
- def get_bounds(self):
- return self.pos + Vector(-self.size.x/2 - 2, -self.size.y/2 - 50 - 2), \
- self.pos + Vector( self.size.x/2 + 50 + 2, self.size.y/2 + 2)
+ # 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 > self.container.DRAGGING_RECT_WIDTH + 2 or \
+ p.y < -1 or p.y > self.container.DRAGGING_RECT_HEIGHT:
+ return False
+ return True
+
+## Copyright 2008 by Peter Moxhay and Wade Brainerd.
+## This file is part of Math.
+##
+## Math is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## Math is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Math. If not, see <http://www.gnu.org/licenses/>.
+#from objectarea import Object
+#from vector import Vector
+#from movableobject import MovableObject
+#
+#import gtk, math
+#
+#class ThreeDObject(MovableObject):
+# """Quasi three-dimensional object."""
+#
+# def __init__(self, color, symbol, size, pos, mass=1):
+# #print "ThreeDObject constructor called: size =", size
+# MovableObject.__init__(self)
+#
+# self.color = color
+# self.symbol = symbol
+# self.size = size
+# self.width = size.x
+# self.height = size.y
+# self.pos = pos
+# self.mass = mass
+#
+# self.selectable = True
+#
+# self.symbol_visible = True
+# self.rotatable = False
+#
+# def draw_poly(self, cr, points):
+# # Generate the shape.
+# cr.move_to(points[0].x, points[0].y)
+# for p in points:
+# cr.line_to(p.x, p.y)
+# cr.close_path()
+#
+# # Draw the fill.
+# if self.selected:
+# cr.set_source_rgb(self.color[0]*1.6, self.color[1]*1.6, self.color[2]*1.6)
+# else:
+# cr.set_source_rgb(self.color[0], self.color[1], self.color[2])
+# cr.fill_preserve()
+#
+# # Draw the outline.
+# if self.selected:
+# cr.set_dash((10, 10), 0)
+# cr.set_source_rgb(self.color[0]*0.75, self.color[1]*0.75, self.color[2]*0.75)
+# cr.set_line_width(4.0)
+# cr.stroke()
+#
+# def draw(self, cr):
+# # Beveled corners look better.
+# cr.set_line_join(1)
+# cr.scale(self.scale, self.scale)
+#
+# # Calculate the points.
+# front_points = [
+# self.pos + Vector(-self.size.x/2, -self.size.y/2),
+# self.pos + Vector( self.size.x/2, -self.size.y/2),
+# self.pos + Vector( self.size.x/2, self.size.y/2),
+# self.pos + Vector(-self.size.x/2, self.size.y/2) ]
+#
+# back_points = [p + Vector(50, -50) for p in front_points]
+#
+# self.draw_poly(cr, front_points)
+#
+# # Draw the top trapezoid.
+# self.draw_poly(cr, [ front_points[0], back_points[0], back_points[1], front_points[1] ])
+#
+# # Draw the side trapezoid.
+# self.draw_poly(cr, [ front_points[1], back_points[1], back_points[2], front_points[2] ])
+#
+# # Draw the symbol (capital letter representing the shapes's area).
+# if self.symbol_visible:
+# cr.set_source_rgb(0, 0, 0)
+# cr.set_font_size(50)
+# x_bearing, y_bearing, width, height = cr.text_extents(self.symbol)[:4]
+# cr.move_to(self.pos.x - x_bearing - width/2, self.pos.y - y_bearing - height/2)
+# cr.show_text(self.symbol)
+#
+# def get_bounds(self):
+# return self.pos + Vector(-self.size.x/2 - 2, -self.size.y/2 - 50 - 2), \
+# self.pos + Vector( self.size.x/2 + 50 + 2, self.size.y/2 + 2)
+#