mathmaker
0.6(alpha)
|
00001 # -*- coding: utf-8 -*- 00002 00003 # Mathmaker creates automatically maths exercises sheets with their answers 00004 # Copyright 2006-2014 Nicolas Hainaux <nico_h@users.sourceforge.net> 00005 00006 # This file is part of Mathmaker. 00007 00008 # Mathmaker is free software; you can redistribute it and/or modify 00009 # it under the terms of the GNU General Public License as published by 00010 # the Free Software Foundation; either version 3 of the License, or 00011 # any later version. 00012 00013 # Mathmaker is distributed in the hope that it will be useful, 00014 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 # GNU General Public License for more details. 00017 00018 # You should have received a copy of the GNU General Public License 00019 # along with Mathmaker; if not, write to the Free Software 00020 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00021 00022 # ------------------------------------------------------------------------------ 00023 # -------------------------------------------------------------------------- 00024 # ------------------------------------------------------------------------------ 00025 ## 00026 # @package core.geometry 00027 # @brief Mathematical geometrical objects. 00028 00029 import math 00030 import locale 00031 from decimal import * 00032 from base import * 00033 from base_geometry import * 00034 from lib import * 00035 from lib import randomly 00036 from lib.maths_lib import * 00037 from core.calculus import * 00038 from lib.common import cfg 00039 00040 if debug.ENABLED: 00041 from lib.common import latex 00042 import machine 00043 00044 markup_choice = cfg.get_value_from_file('MARKUP', 'USE') 00045 00046 if markup_choice == 'latex': 00047 from lib.common.latex import MARKUP 00048 00049 try: 00050 locale.setlocale(locale.LC_ALL, default.LANGUAGE + '.' + default.ENCODING) 00051 except: 00052 locale.setlocale(locale.LC_ALL, '') 00053 00054 # GLOBAL 00055 #expression_begins = True 00056 00057 00058 00059 00060 00061 00062 # ------------------------------------------------------------------------------ 00063 # -------------------------------------------------------------------------- 00064 # ------------------------------------------------------------------------------ 00065 ## 00066 # @class Triangle 00067 # @brief 00068 class Triangle(Drawable): 00069 00070 00071 00072 00073 00074 # -------------------------------------------------------------------------- 00075 ## 00076 # @brief Constructor. 00077 # @param arg : Triangle | 00078 # ((str, str, str), (not implemented yet)'sketch' 00079 # OR : {'side0':nb0, 'angle1':nb1, 'side1':nb2} 00080 # OR : (not implemented yet){'side0':nb0, 'side1':nb1, 'side2':nb2} 00081 # OR : (not implemented yet) etc. 00082 # ) 00083 # NB : the three str will be the vertices' names 00084 # NB : 'sketch' will just choose (reasonnably) random values 00085 # @param options 00086 # Options details : 00087 # - rotate_around_gravity_center = 'no'|'any'|nb 00088 # (nb being the angle, 00089 # defaulting to 'any' if sketch or 'no' if not a sketch) 00090 # FOLLOWING STUFF CAN BE REPLACED BY SETTERS 00091 # - label_side0, label_side1, label_side2, 00092 # - mark_side0, mark_side1, mark_side2, 00093 # - label_angle0, label_angle1, label_angle2, 00094 # - mark_angle0, mark_angle1, mark_angle2, 00095 # @warning Might raise... 00096 def __init__(self, arg, **options): 00097 if not (isinstance(arg, Triangle) or type(arg) == tuple): 00098 raise error.WrongArgument(' Triangle|tuple ', 00099 str(type(arg))) 00100 00101 self._vertices = [None, None, None] 00102 self._sides = [None, None, None] 00103 self._angles = [None, None, None] 00104 self._name = "" 00105 self._rotation_angle = 0 00106 00107 if type(arg) == tuple: 00108 if not len(arg) == 2: 00109 raise error.WrongArgument(' tuple of length 2 ', 00110 ' tuple of length ' \ 00111 + str(len(arg)) 00112 ) 00113 00114 vertices_names = arg[0] 00115 construction_data = arg[1] 00116 00117 if not type(vertices_names) == tuple: 00118 raise error.WrongArgument(' a tuple ', str(vertices_names)) 00119 00120 if not type(vertices_names[0]) == str \ 00121 and type(vertices_names[1]) == str \ 00122 and type(vertices_names[2]) == str: 00123 #___ 00124 raise error.WrongArgument(' three strings ', 00125 ' one of them at least is not a string') 00126 00127 if not (construction_data == 'sketch' \ 00128 or (type(construction_data) == dict \ 00129 and 'side0' in construction_data \ 00130 and is_.a_number(construction_data['side0']) \ 00131 and (('side1' in construction_data \ 00132 and is_.a_number(construction_data['side1']) \ 00133 ) \ 00134 or \ 00135 (('angle1' in construction_data \ 00136 and is_.a_number(construction_data['angle1']) \ 00137 ) \ 00138 ) \ 00139 ) \ 00140 ) \ 00141 ): 00142 #___ 00143 raise error.WrongArgument(" 'sketch' | " \ 00144 + "{'side0':nb0, 'angle1':nb1, 'side1':nb2} | ", 00145 str(construction_data)) 00146 00147 start_vertex = [None, None, None] 00148 00149 side0_length = construction_data['side0'] 00150 side1_length = construction_data['side1'] 00151 00152 if 'rotate_around_isobarycenter' in options: 00153 if options['rotate_around_isobarycenter'] == 'randomly': 00154 self._rotation_angle = randomly.integer(0, 35) * 10 00155 elif is_.a_number(options['rotate_around_isobarycenter']): 00156 self._rotation_angle = \ 00157 options['rotate_around_isobarycenter'] 00158 00159 start_vertex[0] = Point([vertices_names[0], 00160 (0, 0) 00161 ] 00162 ) 00163 start_vertex[1] = Point([vertices_names[1], 00164 (side0_length, 0) 00165 ] 00166 ) 00167 start_vertex[2] = Point([vertices_names[2], 00168 (side0_length \ 00169 - side1_length*Decimal(str(math.cos(\ 00170 deg_to_rad(construction_data['angle1'])))), 00171 side1_length*Decimal(str(math.sin( \ 00172 deg_to_rad(construction_data['angle1'])))) 00173 ) 00174 ] 00175 ) 00176 00177 if self._rotation_angle != 0: 00178 G = barycenter([start_vertex[0], 00179 start_vertex[1], 00180 start_vertex[2] 00181 ], 00182 "G" 00183 ) 00184 00185 self._vertices = (Point(\ 00186 start_vertex[0].rotate(G, 00187 self._rotation_angle, 00188 keep_name=True 00189 ) 00190 ), 00191 Point(\ 00192 start_vertex[1].rotate(G, 00193 self._rotation_angle, 00194 keep_name=True 00195 ) 00196 ), 00197 Point(\ 00198 start_vertex[2].rotate(G, 00199 self._rotation_angle, 00200 keep_name=True 00201 ) 00202 ) 00203 ) 00204 00205 else: 00206 self._vertices = (start_vertex[0].clone(), 00207 start_vertex[1].clone(), 00208 start_vertex[2].clone() 00209 ) 00210 00211 self._sides = (Segment((self._vertices[0], 00212 self._vertices[1] 00213 ) 00214 ), 00215 Segment((self._vertices[1], 00216 self._vertices[2] 00217 ) 00218 ), 00219 Segment((self._vertices[2], 00220 self._vertices[0] 00221 ) 00222 ) 00223 ) 00224 00225 self._angles[0] = Angle((self.vertex1, self.vertex0, self.vertex2)) 00226 self._angles[1] = Angle((self.vertex2, self.vertex1, self.vertex0)) 00227 self._angles[2] = Angle((self.vertex0, self.vertex2, self.vertex1)) 00228 00229 self._angles[0].set_label_display_angle(self._angles[0].measure/2) 00230 self._angles[1].set_label_display_angle(180 \ 00231 - self._angles[1].measure/2) 00232 self._angles[2].set_label_display_angle(180 \ 00233 + self._angles[0].measure \ 00234 + self._angles[2].measure/2) 00235 00236 else: 00237 # copy of a given Triangle 00238 self._vertices = [arg.vertex0.clone(), 00239 arg.vertex1.clone(), 00240 arg.vertex2.clone() 00241 ] 00242 self._rotation_angle = arg.rotation_angle 00243 self._sides = [arg.side0.clone(), 00244 arg.side1.clone(), 00245 arg.side2.clone() 00246 ] 00247 self._angles = [arg.angle0.clone(), 00248 arg.angle1.clone(), 00249 arg.angle2.clone() 00250 ] 00251 00252 self._name = self.vertex0.name + self.vertex1.name + self.vertex2.name 00253 00254 random_number = "" 00255 for i in range(8): 00256 random_number += str(randomly.integer(0, 9)) 00257 00258 self._filename = _("Triangle") + "_" + self.name \ 00259 + "-" + random_number 00260 00261 00262 00263 00264 00265 00266 00267 # -------------------------------------------------------------------------- 00268 ## 00269 # @brief Returns vertex0 (as a Point) 00270 def get_vertex0(self): 00271 return self._vertices[0] 00272 00273 00274 00275 00276 00277 # -------------------------------------------------------------------------- 00278 ## 00279 # @brief Returns vertex1 (as a Point) 00280 def get_vertex1(self): 00281 return self._vertices[1] 00282 00283 00284 00285 00286 00287 # -------------------------------------------------------------------------- 00288 ## 00289 # @brief Returns vertex2 (as a Point) 00290 def get_vertex2(self): 00291 return self._vertices[2] 00292 00293 00294 00295 00296 00297 00298 # -------------------------------------------------------------------------- 00299 ## 00300 # @brief Returns the three vertices (as a list of Points) 00301 def get_vertices(self): 00302 return self._vertices 00303 00304 00305 00306 00307 00308 # -------------------------------------------------------------------------- 00309 ## 00310 # @brief Returns the angle of rotation around the isobarycenter 00311 def get_rotation_angle(self): 00312 return self._rotation_angle 00313 00314 00315 00316 00317 00318 # -------------------------------------------------------------------------- 00319 ## 00320 # @brief Returns angle0 (as an Angle) 00321 def get_angle0(self): 00322 return self._angles[0] 00323 00324 00325 00326 00327 00328 # -------------------------------------------------------------------------- 00329 ## 00330 # @brief Returns angle1 (as an Angle) 00331 def get_angle1(self): 00332 return self._angles[1] 00333 00334 00335 00336 00337 00338 # -------------------------------------------------------------------------- 00339 ## 00340 # @brief Returns angle2 (as an Angle) 00341 def get_angle2(self): 00342 return self._angles[2] 00343 00344 00345 00346 00347 00348 # -------------------------------------------------------------------------- 00349 ## 00350 # @brief Returns [angles] (as a list of Angles) 00351 def get_angles(self): 00352 return self._angles 00353 00354 00355 00356 00357 00358 # -------------------------------------------------------------------------- 00359 ## 00360 # @brief Returns side0 (as a Segment) 00361 def get_side0(self): 00362 return self._sides[0] 00363 00364 00365 00366 00367 00368 # -------------------------------------------------------------------------- 00369 ## 00370 # @brief Returns side1 (as a Segment) 00371 def get_side1(self): 00372 return self._sides[1] 00373 00374 00375 00376 00377 00378 # -------------------------------------------------------------------------- 00379 ## 00380 # @brief Returns side2 (as a Segment) 00381 def get_side2(self): 00382 return self._sides[2] 00383 00384 00385 00386 00387 00388 # -------------------------------------------------------------------------- 00389 ## 00390 # @brief Returns [sides] (as a list of Segments) 00391 def get_sides(self): 00392 return self._sides 00393 00394 00395 00396 00397 00398 vertex0 = property(get_vertex0, 00399 doc = "First vertex of the Triangle") 00400 00401 vertex1 = property(get_vertex1, 00402 doc = "Second vertex of the Triangle") 00403 00404 00405 vertex2 = property(get_vertex2, 00406 doc = "Third vertex of the Triangle") 00407 00408 vertices = property(get_vertices, 00409 doc = "The three vertices (in a list)") 00410 00411 angle0 = property(get_angle0, 00412 doc = "First angle of the Triangle") 00413 00414 angle1 = property(get_angle1, 00415 doc = "Second angle of the Triangle") 00416 00417 angle2 = property(get_angle2, 00418 doc = "Third angle of the Triangle") 00419 00420 angles = property(get_angles, 00421 doc = "The angles' list of the Triangle") 00422 00423 rotation_angle = property(get_rotation_angle, 00424 doc = "Angle of rotation around the isobarycenter") 00425 00426 side0 = property(get_side0, 00427 doc = "First side of the Triangle") 00428 00429 side1 = property(get_side1, 00430 doc = "Second side of the Triangle") 00431 00432 side2 = property(get_side2, 00433 doc = "Third side of the Triangle") 00434 00435 sides = property(get_sides, 00436 doc = "The sides' list of the Triangle") 00437 00438 00439 00440 00441 # -------------------------------------------------------------------------- 00442 ## 00443 # @brief Creates the euk string to put in the file 00444 # @param options Any options 00445 # @return The string to put in the picture file 00446 def into_euk(self, **options): 00447 box_values = self.work_out_euk_box() 00448 result = "box " + str(box_values[0]) + ", " \ 00449 + str(box_values[1]) + ", " \ 00450 + str(box_values[2]) + ", " \ 00451 + str(box_values[3]) 00452 00453 result += "\n\n" 00454 00455 for vertex in self.vertices: 00456 result += vertex.name + " = point(" + str(vertex.x) \ 00457 + ", " \ 00458 + str(vertex.y) + ")\n" 00459 00460 result += "\n\n" 00461 00462 result += "draw" 00463 00464 result += "\n " 00465 00466 result += "(" + self.vertex0.name + "." \ 00467 + self.vertex1.name + "." \ 00468 + self.vertex2.name + ")" 00469 00470 scale_factor = 1 00471 angle_correction = 0 00472 00473 sides_angles_offsets = {self.sides[0] : 0, 00474 self.sides[1] : 180 - self.angle1.measure, 00475 self.sides[2] : self.angle0.measure 00476 } 00477 00478 labels_angle_correction_signs = {self.sides[0] : "-", 00479 self.sides[1] : "-", 00480 self.sides[2] : "+" 00481 } 00482 00483 labels_ref_points = {self.sides[0] : self.vertex0.name, 00484 self.sides[1] : self.vertex1.name, 00485 self.sides[2] : self.vertex0.name 00486 } 00487 00488 00489 for side in self.sides: 00490 if side.label != None and side.label != Value(""): 00491 x = side.length 00492 scale_factor = round(Decimal(str(1.6*x)), 00493 Decimal('0.1'), 00494 rounding=ROUND_UP 00495 ) 00496 if x <= 3: 00497 angle_correction = round(Decimal(str(-8*x + 33)), 00498 Decimal('0.1'), 00499 rounding=ROUND_UP 00500 ) 00501 else: 00502 angle_correction = round(Decimal(str( \ 00503 1.1/(1-0.95*math.exp(-0.027*x)) 00504 ) 00505 ), 00506 Decimal('0.1'), 00507 rounding=ROUND_UP 00508 ) 00509 00510 label_position_angle = round(Decimal(str(self.rotation_angle))\ 00511 + \ 00512 Decimal(str(\ 00513 sides_angles_offsets[side])), 00514 Decimal('1'), 00515 rounding=ROUND_HALF_EVEN 00516 ) 00517 00518 rotate_box_angle = Decimal(label_position_angle) 00519 00520 if (rotate_box_angle >= 90 \ 00521 and rotate_box_angle <= 270): 00522 #___ 00523 rotate_box_angle -= Decimal("180") 00524 elif (rotate_box_angle <= -90 \ 00525 and rotate_box_angle >= -270): 00526 #___ 00527 rotate_box_angle += Decimal("180") 00528 00529 result += "\n " 00530 result += "$\\rotatebox{" 00531 result += str(rotate_box_angle) 00532 result += "}{" 00533 result += side.label.into_str(display_unit='yes', 00534 graphic_display='yes') 00535 result += "}$ " 00536 result += labels_ref_points[side] + " " 00537 result += str(label_position_angle) 00538 result += " " + labels_angle_correction_signs[side] + " " 00539 result += str(angle_correction) + " deg " 00540 result += str(scale_factor) 00541 result += "\n" 00542 00543 00544 for angle in self.angles: 00545 if angle.label != None and angle.label != Value(""): 00546 scale_factor = Decimal('2.7') 00547 if Decimal(str(angle.measure)) < Decimal('28.5'): 00548 scale_factor = round(Decimal('38.1')\ 00549 *pow(Decimal(str(angle.measure)), 00550 Decimal('-0.8') 00551 ), 00552 Decimal('0.01'), 00553 rounding=ROUND_HALF_UP 00554 ) 00555 00556 label_position_angle = Decimal(str(angle.label_display_angle)) \ 00557 + Decimal(str(self.rotation_angle)) 00558 rotate_box_angle = Decimal(label_position_angle) 00559 00560 if (rotate_box_angle >= 90 \ 00561 and rotate_box_angle <= 270): 00562 #___ 00563 rotate_box_angle -= Decimal("180") 00564 elif (rotate_box_angle <= -90 \ 00565 and rotate_box_angle >= -270): 00566 #___ 00567 rotate_box_angle += Decimal("180") 00568 00569 result += "\n " 00570 result += "$\\rotatebox{" 00571 result += str(rotate_box_angle) 00572 result += "}{" 00573 result += angle.label.into_str(display_unit='yes', 00574 graphic_display='yes') 00575 result += "}$ " 00576 result += angle.vertex.name + " " 00577 result += str(label_position_angle) + " deg " 00578 result += str(scale_factor) 00579 result += "\n" 00580 00581 result += "\nend" 00582 00583 result += "\n\n" 00584 00585 result += "label" 00586 00587 result += "\n" 00588 00589 for angle in self.angles: 00590 if angle.mark != "": 00591 result += " " + angle.point0.name + ", " \ 00592 + angle.vertex.name + ", " \ 00593 + angle.point2.name \ 00594 + " " \ 00595 + angle.mark 00596 result += "\n" 00597 00598 result += " " + self.vertex0.name + " " \ 00599 + str(self.rotation_angle) + " + 200 deg" 00600 00601 result += "\n" 00602 00603 result += " " + self.vertex1.name + " " \ 00604 + str(self.rotation_angle) + " - 45 deg" 00605 00606 result += "\n" 00607 00608 result += " " + self.vertex2.name + " " \ 00609 + str(self.rotation_angle) + " + 65 deg" 00610 00611 result += "\nend" 00612 00613 return result 00614 00615 00616 00617 00618 00619 # -------------------------------------------------------------------------- 00620 ## 00621 # @brief Works out the dimensions of the box 00622 # @param options Any options 00623 # @return (x1, y1, x2, y2) 00624 def work_out_euk_box(self, **options): 00625 x_list = [self.vertex0.x, 00626 self.vertex1.x, 00627 self.vertex2.x 00628 ] 00629 y_list = [self.vertex0.y, 00630 self.vertex1.y, 00631 self.vertex2.y 00632 ] 00633 00634 return (min(x_list)-Decimal("0.6"), min(y_list)-Decimal("0.6"), 00635 max(x_list)+Decimal("0.6"), max(y_list)+Decimal("0.6")) 00636 00637 00638 00639 00640 00641 00642 # ------------------------------------------------------------------------------ 00643 # -------------------------------------------------------------------------- 00644 # ------------------------------------------------------------------------------ 00645 ## 00646 # @class RightTriangle 00647 # @brief 00648 class RightTriangle(Triangle): 00649 00650 00651 00652 00653 00654 # -------------------------------------------------------------------------- 00655 ## 00656 # @brief Constructor. 00657 # @param arg : RightTriangle | 00658 # ((str, str, str), 'sketch' 00659 # OR : {'leg0' : nb0, 'leg1' : nb1} 00660 # OR : (not implemented yet){'leg0' : nb0, 'angle0' : nb1} 00661 # ) 00662 # NB : the three str will be the vertices' names 00663 # The second name will be the right corner 00664 # so, hypotenuse will be vertices_names[0] & [2] 00665 # NB : 'sketch' will just choose (reasonnably) random values 00666 # @param options 00667 # Options details : 00668 # - rotate_around_gravity_center = 'no'|'any'|nb 00669 # (nb being the angle, 00670 # defaulting to 'any' if sketch or 'no' if not a sketch) 00671 # FOLLOWING ONES HAVE BEEN REPLACED BY MATCHING SETTERS 00672 # - label_leg0, label_leg1, label_hypotenuse, 00673 # - dont_label_right_angle, label_angle0, label_angle2 00674 # @warning Might raise... 00675 def __init__(self, arg, **options): 00676 if not (isinstance(arg, RightTriangle) or type(arg) == tuple): 00677 raise error.WrongArgument(' RightTriangle|tuple ', 00678 str(type(arg))) 00679 00680 self._vertices = [None, None, None] 00681 self._rotation_angle = 0 00682 self._sides = [None, None, None] 00683 self._name = "" 00684 00685 if type(arg) == tuple: 00686 if not len(arg) == 2: 00687 raise error.WrongArgument(' tuple of length 2 ', 00688 ' tuple of length ' \ 00689 + str(len(arg)) 00690 ) 00691 vertices_names = arg[0] 00692 construction_data = arg[1] 00693 00694 if not type(vertices_names) == tuple: 00695 raise error.WrongArgument(' a tuple ', str(vertices_names)) 00696 00697 if not type(vertices_names[0]) == str \ 00698 and type(vertices_names[1]) == str \ 00699 and type(vertices_names[2]) == str: 00700 #___ 00701 raise error.WrongArgument(' three strings ', 00702 ' one of them at least is not a string') 00703 00704 rotation = 0 00705 00706 if 'rotate_around_isobarycenter' in options \ 00707 and options['rotate_around_isobarycenter'] == 'randomly': 00708 #___ 00709 rotation = randomly.integer(0, 35) * 10 00710 00711 elif 'rotate_around_isobarycenter' in options \ 00712 and is_.a_number(options['rotate_around_isobarycenter']): 00713 #___ 00714 rotation = options['rotate_around_isobarycenter'] 00715 00716 leg0_length = 0 00717 leg1_length = 0 00718 00719 if construction_data == 'sketch': 00720 leg0_length = Decimal(str(randomly.integer(35, 55)))/10 00721 leg1_length = Decimal(str(randomly.integer(7, 17))) \ 00722 / Decimal("20") * leg0_length 00723 00724 elif type(construction_data) == dict \ 00725 and 'leg0' in construction_data \ 00726 and is_.a_number(construction_data['leg0']) \ 00727 and 'leg1' in construction_data \ 00728 and is_.a_number(construction_data['leg1']): 00729 #___ 00730 leg0_length = construction_data['leg0'] 00731 leg1_length = construction_data['leg1'] 00732 00733 else: 00734 raise error.WrongArgument(" 'sketch' | " \ 00735 + "{'leg0' : nb0, 'leg1' : nb1}", 00736 str(construction_data)) 00737 00738 Triangle.__init__(self, 00739 ((vertices_names[0], 00740 vertices_names[1], 00741 vertices_names[2] 00742 ), 00743 {'side0' : leg0_length, 00744 'angle1' : 90, 00745 'side1' : leg1_length 00746 } 00747 ), 00748 rotate_around_isobarycenter=rotation 00749 ) 00750 00751 else: 00752 # copy of a given RightTriangle 00753 self._vertices = [arg.vertex0.clone(), 00754 arg.vertex1.clone(), 00755 arg.vertex2.clone() 00756 ] 00757 self._rotation_angle = arg.rotation_angle 00758 self._sides = [arg.side0.clone(), 00759 arg.side1.clone(), 00760 arg.side2.clone() 00761 ] 00762 self._angles = [arg.angle0.clone(), 00763 arg.angle1.clone(), 00764 arg.angle2.clone() 00765 ] 00766 # the other fields are re-created hereafter 00767 00768 self._name = self.vertex0.name + self.vertex1.name + self.vertex2.name 00769 00770 self.right_angle.set_mark("right") 00771 00772 random_number = "" 00773 for i in range(8): 00774 random_number += str(randomly.integer(0, 9)) 00775 00776 self._filename = _("RightTriangle") + "_" + self.name \ 00777 + "-" + random_number 00778 00779 00780 00781 00782 00783 00784 00785 # -------------------------------------------------------------------------- 00786 ## 00787 # @brief Returns leg0 (as a Segment) 00788 def get_leg0(self): 00789 return self._sides[0] 00790 00791 00792 00793 00794 00795 # -------------------------------------------------------------------------- 00796 ## 00797 # @brief Returns leg1 (as a Segment) 00798 def get_leg1(self): 00799 return self._sides[1] 00800 00801 00802 00803 00804 00805 # -------------------------------------------------------------------------- 00806 ## 00807 # @brief Returns legs (as a Segment) 00808 def get_legs(self): 00809 return [self.leg0, self.leg1] 00810 00811 00812 00813 00814 00815 # -------------------------------------------------------------------------- 00816 ## 00817 # @brief Returns hypotenuse (as a Segment) 00818 def get_hypotenuse(self): 00819 return self._sides[2] 00820 00821 00822 00823 00824 00825 # -------------------------------------------------------------------------- 00826 ## 00827 # @brief Returns Tthe right angle (as an Angle) 00828 def get_right_angle(self): 00829 return self.angle1 00830 00831 00832 00833 00834 00835 leg0 = property(get_leg0, 00836 doc = "First leg of the Triangle") 00837 00838 leg1 = property(get_leg1, 00839 doc = "Second leg of the Triangle") 00840 00841 legs = property(get_legs, 00842 doc = "The two legs of the Right Triangle (in a list)") 00843 00844 hypotenuse = property(get_hypotenuse, 00845 doc = "Hypotenuse of the Right Triangle") 00846 00847 right_angle = property(get_right_angle, 00848 doc = "Right Angle of the Right Triangle") 00849 00850 00851 00852 00853 00854 # -------------------------------------------------------------------------- 00855 ## 00856 # @brief Creates the correct pythagorean equality hyp²=leg0²+leg1² 00857 # @return an Equality but not usable to calculate (see substequality) 00858 def pythagorean_equality(self, **options): 00859 00860 objcts = [Item(('+', self.hypotenuse.length_name, 2)), 00861 Sum([Item(('+', self.leg0.length_name, 2)), 00862 Item(('+', self.leg1.length_name, 2))] 00863 )] 00864 00865 return Equality(objcts, **options) 00866 00867 00868 00869 00870 # -------------------------------------------------------------------------- 00871 ## 00872 # @brief Creates the correct (substitutable) pythagorean equality 00873 # @brief Uses the labels to determine the result... 00874 # @return a SubstitutableEquality 00875 def pythagorean_substequality(self, **options): 00876 # First, check the number of numeric data 00877 # and find the unknown side 00878 n_numeric_data = 0 00879 unknown_side = "" 00880 if self.leg0.label.is_numeric(): 00881 n_numeric_data += 1 00882 elif self.leg0.label.raw_value == "": 00883 unknown_side = 'leg0' 00884 if self.leg1.label.is_numeric(): 00885 n_numeric_data += 1 00886 elif self.leg1.label.raw_value == "": 00887 unknown_side = 'leg1' 00888 if self.hypotenuse.label.is_numeric(): 00889 n_numeric_data += 1 00890 elif self.hypotenuse.label.raw_value == "": 00891 unknown_side = 'hypotenuse' 00892 00893 if n_numeric_data != 2: 00894 raise error.ImpossibleAction("creation of a pythagorean equality "\ 00895 "when the number of known numeric " \ 00896 "values is different from 2.") 00897 00898 # Now create the SubstitutableEquality (so, also create the dictionnary) 00899 if unknown_side == 'leg0': 00900 subst_dict = {Value(self.leg1.length_name): self.leg1.label, 00901 Value(self.hypotenuse.length_name): \ 00902 self.hypotenuse.label 00903 } 00904 objcts = [Item(('+', self.leg0.length_name, 2)), 00905 Sum([Item(('+', self.hypotenuse.length_name, 2)), 00906 Item(('-', self.leg1.length_name, 2))] 00907 )] 00908 00909 elif unknown_side == 'leg1': 00910 subst_dict = {Value(self.leg0.length_name): self.leg0.label, 00911 Value(self.hypotenuse.length_name): \ 00912 self.hypotenuse.label 00913 } 00914 objcts = [Item(('+', self.leg1.length_name, 2)), 00915 Sum([Item(('+', self.hypotenuse.length_name, 2)), 00916 Item(('-', self.leg0.length_name, 2))] 00917 )] 00918 00919 elif unknown_side == 'hypotenuse': 00920 subst_dict = {Value(self.leg0.length_name): self.leg0.label, 00921 Value(self.leg1.length_name): self.leg1.label 00922 } 00923 objcts = [Item(('+', self.hypotenuse.length_name, 2)), 00924 Sum([Item(('+', self.leg0.length_name, 2)), 00925 Item(('+', self.leg1.length_name, 2))] 00926 )] 00927 00928 else: 00929 raise error.ImpossibleAction("creation of a pythagorean equality "\ 00930 "because no unknown side was found") 00931 00932 00933 return SubstitutableEquality(objcts, subst_dict) 00934 00935