mathmaker  0.4(alpha)
mathmaker_dev/core/geometry.py
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 xrange(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     vertex0 = property(get_vertex0,
00274                        doc = "First vertex of the Triangle")
00275 
00276 
00277 
00278 
00279 
00280     # --------------------------------------------------------------------------
00281     ##
00282     #   @brief Returns vertex1 (as a Point)
00283     def get_vertex1(self):
00284         return self._vertices[1]
00285     # --------------------------------------------------------------------------
00286     vertex1 = property(get_vertex1,
00287                        doc = "Second vertex of the Triangle")
00288 
00289 
00290 
00291 
00292 
00293     # --------------------------------------------------------------------------
00294     ##
00295     #   @brief Returns vertex2 (as a Point)
00296     def get_vertex2(self):
00297         return self._vertices[2]
00298     # --------------------------------------------------------------------------
00299     vertex2 = property(get_vertex2,
00300                        doc = "Third vertex of the Triangle")
00301 
00302 
00303 
00304 
00305 
00306     # --------------------------------------------------------------------------
00307     ##
00308     #   @brief Returns the three vertices (as a list of Points)
00309     def get_vertices(self):
00310         return self._vertices
00311     # --------------------------------------------------------------------------
00312     vertices = property(get_vertices,
00313                         doc = "The three vertices (in a list)")
00314 
00315 
00316 
00317 
00318 
00319     # --------------------------------------------------------------------------
00320     ##
00321     #   @brief Returns the angle of rotation around the isobarycenter
00322     def get_rotation_angle(self):
00323         return self._rotation_angle
00324     # --------------------------------------------------------------------------
00325     rotation_angle = property(get_rotation_angle,
00326                               doc = "Angle of rotation around the isobarycenter")
00327 
00328 
00329 
00330 
00331 
00332     # --------------------------------------------------------------------------
00333     ##
00334     #   @brief Returns angle0 (as an Angle)
00335     def get_angle0(self):
00336         return self._angles[0]
00337     # --------------------------------------------------------------------------
00338     angle0 = property(get_angle0,
00339                       doc = "First angle of the Triangle")
00340 
00341 
00342 
00343 
00344 
00345     # --------------------------------------------------------------------------
00346     ##
00347     #   @brief Returns angle1 (as an Angle)
00348     def get_angle1(self):
00349         return self._angles[1]
00350     # --------------------------------------------------------------------------
00351     angle1 = property(get_angle1,
00352                       doc = "Second angle of the Triangle")
00353 
00354 
00355 
00356 
00357 
00358     # --------------------------------------------------------------------------
00359     ##
00360     #   @brief Returns angle2 (as an Angle)
00361     def get_angle2(self):
00362         return self._angles[2]
00363     # --------------------------------------------------------------------------
00364     angle2 = property(get_angle2,
00365                       doc = "Third angle of the Triangle")
00366 
00367 
00368 
00369 
00370 
00371     # --------------------------------------------------------------------------
00372     ##
00373     #   @brief Returns [angles]   (as a list of Angles)
00374     def get_angles(self):
00375         return self._angles
00376     # --------------------------------------------------------------------------
00377     angles = property(get_angles,
00378                       doc = "The angles' list of the Triangle")
00379 
00380 
00381 
00382 
00383 
00384     # --------------------------------------------------------------------------
00385     ##
00386     #   @brief Returns side0 (as a Segment)
00387     def get_side0(self):
00388         return self._sides[0]
00389     # --------------------------------------------------------------------------
00390     side0 = property(get_side0,
00391                      doc = "First side of the Triangle")
00392 
00393 
00394 
00395 
00396 
00397     # --------------------------------------------------------------------------
00398     ##
00399     #   @brief Returns side1 (as a Segment)
00400     def get_side1(self):
00401         return self._sides[1]
00402     # --------------------------------------------------------------------------
00403     side1 = property(get_side1,
00404                      doc = "Second side of the Triangle")
00405 
00406 
00407 
00408 
00409 
00410     # --------------------------------------------------------------------------
00411     ##
00412     #   @brief Returns side2 (as a Segment)
00413     def get_side2(self):
00414         return self._sides[2]
00415     # --------------------------------------------------------------------------
00416     side2 = property(get_side2,
00417                      doc = "Third side of the Triangle")
00418 
00419 
00420 
00421 
00422 
00423     # --------------------------------------------------------------------------
00424     ##
00425     #   @brief Returns [sides]   (as a list of Segments)
00426     def get_sides(self):
00427         return self._sides
00428     # --------------------------------------------------------------------------
00429     sides = property(get_sides,
00430                      doc = "The sides' list of the Triangle")
00431 
00432 
00433 
00434 
00435 
00436     # --------------------------------------------------------------------------
00437     ##
00438     #   @brief Creates the euk string to put in the file
00439     #   @param options Any options
00440     #   @return The string to put in the picture file
00441     def into_euk(self, **options):
00442         box_values = self.work_out_euk_box()
00443         result = "box " + str(box_values[0]) + ", " \
00444                         + str(box_values[1]) + ", " \
00445                         + str(box_values[2]) + ", " \
00446                         + str(box_values[3])
00447 
00448         result += "\n\n"
00449 
00450         for vertex in self.vertices:
00451             result += vertex.name + " = point(" + str(vertex.x) \
00452                                               + ", " \
00453                                               + str(vertex.y) + ")\n"
00454 
00455         result += "\n\n"
00456 
00457         result += "draw"
00458 
00459         result += "\n  "
00460 
00461         result += "(" + self.vertex0.name + "." \
00462                       + self.vertex1.name + "." \
00463                       + self.vertex2.name + ")"
00464 
00465         scale_factor = 1
00466         angle_correction = 0
00467 
00468         sides_angles_offsets = {self.sides[0] : 0,
00469                                 self.sides[1] : 180 - self.angle1.measure,
00470                                 self.sides[2] : self.angle0.measure
00471                                }
00472 
00473         labels_angle_correction_signs = {self.sides[0] : "-",
00474                                          self.sides[1] : "-",
00475                                          self.sides[2] : "+"
00476                                         }
00477 
00478         labels_ref_points = {self.sides[0] : self.vertex0.name,
00479                              self.sides[1] : self.vertex1.name,
00480                              self.sides[2] : self.vertex0.name
00481                             }
00482 
00483 
00484         for side in self.sides:
00485             if side.label != None and side.label != Value(""):
00486                 x = side.length
00487                 scale_factor = round(Decimal(str(1.6*x)),
00488                                      Decimal('0.1'),
00489                                      rounding=ROUND_UP
00490                                     )
00491                 if x <= 3:
00492                     angle_correction = round(Decimal(str(-8*x + 33)),
00493                                              Decimal('0.1'),
00494                                              rounding=ROUND_UP
00495                                             )
00496                 else:
00497                     angle_correction = round(Decimal(str( \
00498                                                 1.1/(1-0.95*math.exp(-0.027*x))
00499                                                         )
00500                                                     ),
00501                                              Decimal('0.1'),
00502                                              rounding=ROUND_UP
00503                                             )
00504 
00505                 label_position_angle = round(Decimal(str(self.rotation_angle))\
00506                                              + \
00507                                              Decimal(str(\
00508                                                     sides_angles_offsets[side])),
00509                                              Decimal('1'),
00510                                              rounding=ROUND_HALF_EVEN
00511                                             )
00512 
00513                 rotate_box_angle = Decimal(label_position_angle)
00514 
00515                 if (rotate_box_angle >= 90 \
00516                     and rotate_box_angle <= 270):
00517                 #___
00518                     rotate_box_angle -= Decimal("180")
00519                 elif (rotate_box_angle <= -90 \
00520                     and rotate_box_angle >= -270):
00521                #___
00522                     rotate_box_angle += Decimal("180")
00523 
00524                 result += "\n  "
00525                 result += "$\\rotatebox{"
00526                 result += str(rotate_box_angle)
00527                 result += "}{"
00528                 result += side.label.into_str(display_unit='yes',
00529                                            graphic_display='yes')
00530                 result += "}$ "
00531                 result += labels_ref_points[side] + " "
00532                 result += str(label_position_angle)
00533                 result += " " + labels_angle_correction_signs[side] + " "
00534                 result += str(angle_correction) + " deg "
00535                 result += str(scale_factor)
00536                 result += "\n"
00537 
00538 
00539         for angle in self.angles:
00540             if angle.label != None and angle.label != Value(""):
00541                 scale_factor = Decimal('2.7')
00542                 if Decimal(str(angle.measure)) < Decimal('28.5'):
00543                     scale_factor = round(Decimal('38.1')\
00544                                               *pow(Decimal(str(angle.measure)),
00545                                                    Decimal('-0.8')
00546                                                   ),
00547                                          Decimal('0.01'),
00548                                          rounding=ROUND_HALF_UP
00549                                          )
00550 
00551                 label_position_angle = Decimal(str(angle.label_display_angle)) \
00552                                        + Decimal(str(self.rotation_angle))
00553                 rotate_box_angle = Decimal(label_position_angle)
00554 
00555                 if (rotate_box_angle >= 90 \
00556                     and rotate_box_angle <= 270):
00557                 #___
00558                     rotate_box_angle -= Decimal("180")
00559                 elif (rotate_box_angle <= -90 \
00560                     and rotate_box_angle >= -270):
00561                 #___
00562                     rotate_box_angle += Decimal("180")
00563 
00564                 result += "\n  "
00565                 result += "$\\rotatebox{"
00566                 result += str(rotate_box_angle)
00567                 result += "}{"
00568                 result += angle.label.into_str(display_unit='yes',
00569                                             graphic_display='yes')
00570                 result += "}$ "
00571                 result += angle.vertex.name + " "
00572                 result += str(label_position_angle) + " deg "
00573                 result += str(scale_factor)
00574                 result += "\n"
00575 
00576         result += "\nend"
00577 
00578         result += "\n\n"
00579 
00580         result += "label"
00581 
00582         result += "\n"
00583 
00584         for angle in self.angles:
00585             if angle.mark != "":
00586                 result += "  " + angle.point0.name + ", " \
00587                         + angle.vertex.name + ", " \
00588                         + angle.point2.name \
00589                         + " " \
00590                         + angle.mark
00591                 result += "\n"
00592 
00593         result += "  " + self.vertex0.name + " " \
00594                + str(self.rotation_angle) + " + 200 deg"
00595 
00596         result += "\n"
00597 
00598         result += "  " + self.vertex1.name + " " \
00599                + str(self.rotation_angle) + " - 45 deg"
00600 
00601         result += "\n"
00602 
00603         result += "  " + self.vertex2.name + " " \
00604                + str(self.rotation_angle) + " + 65 deg"
00605 
00606         result += "\nend"
00607 
00608         return result
00609 
00610 
00611 
00612 
00613 
00614     # --------------------------------------------------------------------------
00615     ##
00616     #   @brief Works out the dimensions of the box
00617     #   @param options Any options
00618     #   @return (x1, y1, x2, y2)
00619     def work_out_euk_box(self, **options):
00620         x_list = [self.vertex0.x,
00621                   self.vertex1.x,
00622                   self.vertex2.x
00623                   ]
00624         y_list = [self.vertex0.y,
00625                   self.vertex1.y,
00626                   self.vertex2.y
00627                   ]
00628 
00629         return (min(x_list)-Decimal("0.6"), min(y_list)-Decimal("0.6"),
00630                 max(x_list)+Decimal("0.6"), max(y_list)+Decimal("0.6"))
00631 
00632 
00633 
00634 
00635 
00636 
00637 # ------------------------------------------------------------------------------
00638 # --------------------------------------------------------------------------
00639 # ------------------------------------------------------------------------------
00640 ##
00641 # @class RightTriangle
00642 # @brief
00643 class RightTriangle(Triangle):
00644 
00645 
00646 
00647 
00648 
00649     # --------------------------------------------------------------------------
00650     ##
00651     #   @brief Constructor.
00652     #   @param arg : RightTriangle |
00653     #                ((str, str, str), 'sketch'
00654     #        OR :                      {'leg0' : nb0, 'leg1' : nb1}
00655     #        OR : (not implemented yet){'leg0' : nb0, 'angle0' : nb1}
00656     #                )
00657     #            NB : the three str will be the vertices' names
00658     #                 The second name will be the right corner
00659     #                 so, hypotenuse will be vertices_names[0] & [2]
00660     #            NB : 'sketch' will just choose (reasonnably) random values
00661     #   @param options
00662     #   Options details :
00663     #   - rotate_around_gravity_center = 'no'|'any'|nb
00664     #                        (nb being the angle,
00665     #               defaulting to 'any' if sketch or 'no' if not a sketch)
00666     #   FOLLOWING ONES HAVE BEEN REPLACED BY MATCHING SETTERS
00667     #   - label_leg0, label_leg1, label_hypotenuse,
00668     #   - dont_label_right_angle, label_angle0, label_angle2
00669     #   @warning Might raise...
00670     def __init__(self, arg, **options):
00671         if not (isinstance(arg, RightTriangle) or type(arg) == tuple):
00672             raise error.WrongArgument(' RightTriangle|tuple ',
00673                                       str(type(arg)))
00674 
00675         self._vertices = [None, None, None]
00676         self._rotation_angle = 0
00677         self._sides = [None, None, None]
00678         self._name = ""
00679 
00680         if type(arg) == tuple:
00681             if not len(arg) == 2:
00682                 raise error.WrongArgument(' tuple of length 2 ',
00683                                           ' tuple of length ' \
00684                                           + str(len(arg))
00685                                          )
00686             vertices_names = arg[0]
00687             construction_data = arg[1]
00688 
00689             if not type(vertices_names) == tuple:
00690                 raise error.WrongArgument(' a tuple ', str(vertices_names))
00691 
00692             if not type(vertices_names[0]) == str \
00693                 and type(vertices_names[1]) == str \
00694                 and type(vertices_names[2]) == str:
00695             #___
00696                 raise error.WrongArgument(' three strings ',
00697                                         ' one of them at least is not a string')
00698 
00699             rotation = 0
00700 
00701             if 'rotate_around_isobarycenter' in options \
00702                 and options['rotate_around_isobarycenter'] == 'randomly':
00703             #___
00704                 rotation = randomly.integer(0, 35) * 10
00705 
00706             elif 'rotate_around_isobarycenter' in options \
00707                 and is_.a_number(options['rotate_around_isobarycenter']):
00708             #___
00709                 rotation = options['rotate_around_isobarycenter']
00710 
00711             leg0_length = 0
00712             leg1_length = 0
00713 
00714             if construction_data == 'sketch':
00715                 leg0_length = Decimal(str(randomly.integer(35, 55)))/10
00716                 leg1_length = Decimal(str(randomly.integer(7, 17))) \
00717                               / Decimal("20") * leg0_length
00718 
00719             elif type(construction_data) == dict \
00720                 and 'leg0' in construction_data \
00721                 and is_.a_number(construction_data['leg0']) \
00722                 and 'leg1' in construction_data \
00723                 and is_.a_number(construction_data['leg1']):
00724             #___
00725                 leg0_length = construction_data['leg0']
00726                 leg1_length = construction_data['leg1']
00727 
00728             else:
00729                 raise error.WrongArgument(" 'sketch' | " \
00730                                         + "{'leg0' : nb0, 'leg1' : nb1}",
00731                                           str(construction_data))
00732 
00733             Triangle.__init__(self,
00734                               ((vertices_names[0],
00735                                 vertices_names[1],
00736                                 vertices_names[2]
00737                                 ),
00738                                {'side0' : leg0_length,
00739                                 'angle1' : 90,
00740                                 'side1' : leg1_length
00741                                }
00742                               ),
00743                               rotate_around_isobarycenter=rotation
00744                              )
00745 
00746         else:
00747             # copy of a given RightTriangle
00748             self._vertices = [arg.vertex0.clone(),
00749                               arg.vertex1.clone(),
00750                               arg.vertex2.clone()
00751                              ]
00752             self._rotation_angle = arg.rotation_angle
00753             self._sides = [arg.side0.clone(),
00754                            arg.side1.clone(),
00755                            arg.side2.clone()
00756                           ]
00757             self._angles = [arg.angle0.clone(),
00758                             arg.angle1.clone(),
00759                             arg.angle2.clone()
00760                            ]
00761             # the other fields are re-created hereafter
00762 
00763         self._name = self.vertex0.name + self.vertex1.name + self.vertex2.name
00764 
00765         self.right_angle.set_mark("right")
00766 
00767         random_number = ""
00768         for i in xrange(8):
00769             random_number += str(randomly.integer(0, 9))
00770 
00771         self._filename = _("RightTriangle") + "_" + self.name \
00772                          + "-" + random_number
00773 
00774 
00775 
00776 
00777 
00778 
00779 
00780     # --------------------------------------------------------------------------
00781     ##
00782     #   @brief Returns leg0 (as a Segment)
00783     def get_leg0(self):
00784         return self._sides[0]
00785     # --------------------------------------------------------------------------
00786     leg0 = property(get_leg0,
00787                     doc = "First leg of the Triangle")
00788 
00789 
00790 
00791 
00792 
00793     # --------------------------------------------------------------------------
00794     ##
00795     #   @brief Returns leg1 (as a Segment)
00796     def get_leg1(self):
00797         return self._sides[1]
00798     # --------------------------------------------------------------------------
00799     leg1 = property(get_leg1,
00800                     doc = "Second leg of the Triangle")
00801 
00802 
00803 
00804 
00805 
00806     # --------------------------------------------------------------------------
00807     ##
00808     #   @brief Returns legs (as a Segment)
00809     def get_legs(self):
00810         return [self.leg0, self.leg1]
00811     # --------------------------------------------------------------------------
00812     legs = property(get_legs,
00813                     doc = "The two legs of the Right Triangle (in a list)")
00814 
00815 
00816 
00817 
00818 
00819     # --------------------------------------------------------------------------
00820     ##
00821     #   @brief Returns hypotenuse (as a Segment)
00822     def get_hypotenuse(self):
00823         return self._sides[2]
00824     # --------------------------------------------------------------------------
00825     hypotenuse = property(get_hypotenuse,
00826                           doc = "Hypotenuse of the Right Triangle")
00827 
00828 
00829 
00830 
00831 
00832     # --------------------------------------------------------------------------
00833     ##
00834     #   @brief Returns Tthe right angle (as an Angle)
00835     def get_right_angle(self):
00836         return self.angle1
00837     # --------------------------------------------------------------------------
00838     right_angle = property(get_right_angle,
00839                            doc = "Right Angle of the Right Triangle")
00840 
00841 
00842 
00843 
00844 
00845     # --------------------------------------------------------------------------
00846     ##
00847     #   @brief Creates the correct pythagorean equality hyp²=leg0²+leg1²
00848     #   @return an Equality but not usable to calculate (see substequality)
00849     def pythagorean_equality(self, **options):
00850 
00851         objcts = [Item(('+', self.hypotenuse.length_name, 2)),
00852                   Sum([Item(('+', self.leg0.length_name, 2)),
00853                        Item(('+', self.leg1.length_name, 2))]
00854                      )]
00855 
00856         return Equality(objcts, **options)
00857 
00858 
00859 
00860 
00861 # --------------------------------------------------------------------------
00862     ##
00863     #   @brief Creates the correct (substitutable) pythagorean equality
00864     #   @brief Uses the labels to determine the result...
00865     #   @return a SubstitutableEquality
00866     def pythagorean_substequality(self, **options):
00867         # First, check the number of numeric data
00868         # and find the unknown side
00869         n_numeric_data = 0
00870         unknown_side = ""
00871         if self.leg0.label.is_numeric():
00872             n_numeric_data += 1
00873         elif self.leg0.label.raw_value == "":
00874             unknown_side = 'leg0'
00875         if self.leg1.label.is_numeric():
00876             n_numeric_data += 1
00877         elif self.leg1.label.raw_value == "":
00878             unknown_side = 'leg1'
00879         if self.hypotenuse.label.is_numeric():
00880             n_numeric_data += 1
00881         elif self.hypotenuse.label.raw_value == "":
00882             unknown_side = 'hypotenuse'
00883 
00884         if n_numeric_data != 2:
00885             raise error.ImpossibleAction("creation of a pythagorean equality "\
00886                                          "when the number of known numeric " \
00887                                          "values is different from 2.")
00888 
00889         # Now create the SubstitutableEquality (so, also create the dictionnary)
00890         if unknown_side == 'leg0':
00891             subst_dict = {Value(self.leg1.length_name): self.leg1.label,
00892                           Value(self.hypotenuse.length_name): \
00893                                                         self.hypotenuse.label
00894                          }
00895             objcts = [Item(('+', self.leg0.length_name, 2)),
00896                       Sum([Item(('+', self.hypotenuse.length_name, 2)),
00897                            Item(('-', self.leg1.length_name, 2))]
00898                          )]
00899 
00900         elif unknown_side == 'leg1':
00901             subst_dict = {Value(self.leg0.length_name): self.leg0.label,
00902                           Value(self.hypotenuse.length_name): \
00903                                                         self.hypotenuse.label
00904                          }
00905             objcts = [Item(('+', self.leg1.length_name, 2)),
00906                       Sum([Item(('+', self.hypotenuse.length_name, 2)),
00907                            Item(('-', self.leg0.length_name, 2))]
00908                          )]
00909 
00910         elif unknown_side == 'hypotenuse':
00911             subst_dict = {Value(self.leg0.length_name): self.leg0.label,
00912                           Value(self.leg1.length_name): self.leg1.label
00913                          }
00914             objcts = [Item(('+', self.hypotenuse.length_name, 2)),
00915                       Sum([Item(('+', self.leg0.length_name, 2)),
00916                            Item(('+', self.leg1.length_name, 2))]
00917                          )]
00918 
00919         else:
00920             raise error.ImpossibleAction("creation of a pythagorean equality "\
00921                                          "because no unknown side was found")
00922 
00923 
00924         return SubstitutableEquality(objcts, subst_dict)
00925 
00926