mathmaker  0.6(alpha)
mamk_misc/doc/mathmaker4doxygen/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 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