source: pyromaths/trunk/fuentes/src/pyromaths/outils/Geometrie.py @ 423

Last change on this file since 423 was 423, checked in by mabarracus, 4 years ago

add sources from pyromaths 15.10

File size: 14.1 KB
Line 
1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3#
4# Pyromaths
5# Un programme en Python qui permet de créer des fiches d'exercices types de
6# mathématiques niveau collège ainsi que leur corrigé en LaTeX.
7# Copyright (C) 2006 -- Jérôme Ortais (jerome.ortais@pyromaths.org)
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation; either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program; if not, write to the Free Software
21# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22#
23
24import math
25from random import randrange
26from Conversions import degres, radians
27def choix_points(n):
28    """
29    choisit n points parmi A, B, C, ..., Z
30    @param n: nombre de points \xc3\xa0 choisir
31    @type n: integer
32    """
33    points = [chr(i + 65) for i in range(26)]
34    liste = []
35    for i in range(n):
36        liste.append(points.pop(randrange(len(points))))
37    return liste
38
39couples_pythagore = (
40    (12, 16, 20),
41    (15, 20, 25),
42    (10, 24, 26),
43    (20, 21, 29),
44    (18, 24, 30),
45    (16, 30, 34),
46    (21, 28, 35),
47    (12, 35, 37),
48    (15, 36, 39),
49    (24, 32, 40),
50    (27, 36, 45),
51    (14, 48, 50),
52    (30, 40, 50),
53    (24, 45, 51),
54    (20, 48, 52),
55    (28, 45, 53),
56    (33, 44, 55),
57    (40, 42, 58),
58    (36, 48, 60),
59    (11, 60, 61),
60    (16, 63, 65),
61    (25, 60, 65),
62    (33, 56, 65),
63    (39, 52, 65),
64    (32, 60, 68),
65    (42, 56, 70),
66    (48, 55, 73),
67    (24, 70, 74),
68    (21, 72, 75),
69    (45, 60, 75),
70    (30, 72, 78),
71    (48, 64, 80),
72    (18, 80, 82),
73    (13, 84, 85),
74    (36, 77, 85),
75    (40, 75, 85),
76    (51, 68, 85),
77    (60, 63, 87),
78    (39, 80, 89),
79    (54, 72, 90),
80    (35, 84, 91),
81    (57, 76, 95),
82    (65, 72, 97),
83    (28, 96, 100),
84    (60, 80, 100),
85    (20, 99, 101),
86    (48, 90, 102),
87    (40, 96, 104),
88    (63, 84, 105),
89    (56, 90, 106),
90    (60, 91, 109),
91    (66, 88, 110),
92    (36, 105, 111),
93    (15, 112, 113),
94    (69, 92, 115),
95    (80, 84, 116),
96    (45, 108, 117),
97    (56, 105, 119),
98    (72, 96, 120),
99    (22, 120, 122),
100    (27, 120, 123),
101    (35, 120, 125),
102    (44, 117, 125),
103    (75, 100, 125),
104    (32, 126, 130),
105    (50, 120, 130),
106    (66, 112, 130),
107    (78, 104, 130),
108    (81, 108, 135),
109    (64, 120, 136),
110    (88, 105, 137),
111    (84, 112, 140),
112    (55, 132, 143),
113    (17, 144, 145),
114    (24, 143, 145),
115    (87, 116, 145),
116    (100, 105, 145),
117    (96, 110, 146),
118    (48, 140, 148),
119    (51, 140, 149),
120    (42, 144, 150),
121    (90, 120, 150),
122    (72, 135, 153),
123    (93, 124, 155),
124    (60, 144, 156),
125    (85, 132, 157),
126    (84, 135, 159),
127    (96, 128, 160),
128    (36, 160, 164),
129    (99, 132, 165),
130    (65, 156, 169),
131    (119, 120, 169),
132    (26, 168, 170),
133    (72, 154, 170),
134    (80, 150, 170),
135    (102, 136, 170),
136    (52, 165, 173),
137    (120, 126, 174),
138    (49, 168, 175),
139    (105, 140, 175),
140    (78, 160, 178),
141    (108, 144, 180),
142    (19, 180, 181),
143    (70, 168, 182),
144    (33, 180, 183),
145    (57, 176, 185),
146    (60, 175, 185),
147    (104, 153, 185),
148    (111, 148, 185),
149    (88, 165, 187),
150    (114, 152, 190),
151    (95, 168, 193),
152    (130, 144, 194),
153    (48, 189, 195),
154    (75, 180, 195),
155    (99, 168, 195),
156    (117, 156, 195),
157    (28, 195, 197),
158    (56, 192, 200),
159    (120, 160, 200),
160    )
161
162def trouve_couples_pythagore(max):
163    ls = []
164    for i in xrange(26):
165        for j in xrange(i - 1):
166            a = i
167            b = j + 1
168            for k in xrange(140):
169                x = (2 * k + 1) * (a ** 2 - b ** 2)
170                y = (2 * k + 1) * (2 * a * b)
171                z = (2 * k + 1) * (a ** 2 + b ** 2)
172                if z > max:
173                    break
174                ls.append(tuple(sorted([x, y, z])))
175    ls.sort(key=operator.itemgetter(2))
176    cpt = 1
177    while cpt < len(ls):
178        if ls[cpt] == ls[cpt - 1]:
179            ls.pop(cpt)
180        else:
181            cpt += 1
182    return tuple(ls)
183
184#----------------------------------------------------
185# Cotation des longeurs sur une figure psTricks
186# A, B sont les coordonnées de deux points
187# cotation_h écrit au dessus du segment
188#----------------------------------------------------
189
190def cotation(A, B, longueur, couleur="", unite="cm"):
191    (xA, yA) = A
192    (xB, yB) = B
193    if couleur != "":
194        couleur = "\\color{%s}" % couleur
195    return u"\\pcline[linestyle=none](%.3f,%.3f)(%.3f,%.3f\\bput{:U}{%s\\unit[%s]{%s}}" % (xA, yA, xB, yB, couleur, longueur, unite)
196
197def cotation_h(A, B, longueur, couleur="", unite="cm"):
198    (xA, yA) = A
199    (xB, yB) = B
200    if couleur != "":
201        couleur = "\\color{%s}" % couleur
202    return u"\\pcline[linestyle=none](%.3f,%.3f)(%.3f,%.3f\\aput{:U}{%s\\unit[%s]{%s}}" % (xA, yA, xB, yB, couleur, longueur, unite)
203
204# def trouve_couples_pythagore(valeurmax):
205#    (liste, listecouples) = ([], [])
206#    for a in range(valeurmax):
207#        liste.append(a ** 2)
208#    for c in range(valeurmax):
209#        for b in range(int((c + 1) / 2 ** .5)):
210#            if liste.count((c + 1) ** 2 - (b + 1) ** 2):
211#                a = liste.index((c + 1) ** 2 - (b + 1) ** 2)
212#                listeinter = [c + 1, b + 1, a]
213#                listeinter.sort()
214#                if listeinter[0] > 9:
215#                    listecouples.append(tuple(listeinter))
216#
217#                if listecouples==[] :
218#                   listecouples.append(tuple(listeinter))
219#                else :
220#                    ajout=1
221#                    for i in xrange(len(listecouples)) :
222#                        if not(listeinter[2]%listecouples[i][2]) and not(listeinter[1]%listecouples[i][1]) and not(listeinter[0]%listecouples[i][0]) :
223#                            if listeinter[2]//listecouples[i][2]==listeinter[1]//listecouples[i][1]==listeinter[0]//listecouples[i][0] : ajout=0
224#                    if ajout :
225#                        listeinter=[c+1,b+1,a]
226#                        listeinter.sort()
227#                        listecouples.append(tuple(listeinter))
228#
229#    return tuple(listecouples)
230class Metapost:
231
232    def __init__(self):
233        self.text = []
234        self.num = 1
235
236    def fin(self):
237        self.text.append("end;")
238        return self
239
240    def triangle(
241        self,
242        A,
243        B,
244        C,
245        a=0,
246        b=0,
247        c=0,
248        alpha=0,
249        beta=0,
250        gamma=0,
251        rotation=0,
252        angledroit=0,
253        ):
254        """Construit un triangle en metapost quelles que soient les données.
255        La base est le côté [AB] de longueur c.
256
257        @param A, b, C : nom des trois sommets (obligatoire)
258        @param a, b, c : longueurs des trois côtés opposés au sommet de même nom
259        @param alpha, beta, gamma : mesure des 3 angles de sommets A, B et C
260        @param rotation: mesure en degrés de l'angle de la rotation de centre A
261                         appliquée au triangle
262        @param angledroit: doit-on afficher l'angle droit ?
263        """
264
265        self.text.append("beginfig(%s);\n" % self.num)
266        self.text.append("u:=1cm;\n")
267        self.text.append("pair %s, %s, %s, m[];\n" % (A, B, C))
268        self.text.append("picture $;\n")
269        self.text.append(%s=origin;\n" % A)
270        if angledroit:
271            marques = [0, 0, 0, "%s \degres" % alpha, "%s \degres" % beta, "%s \degres" % gamma]
272            if a: marques[0] = "%s cm" % a
273            if b: marques[1] = "%s cm" % b
274            if c: marques[2] = "%s cm" % c
275            points = [A, B, C]
276        # on donne les trois longueurs des 3 côtés
277
278        if a and b and c:
279            alpha = degres(math.acos(((b ** 2 + c ** 2) - a ** 2 * 1.) / ((2 * 
280                     b) * c)))
281            beta = degres(math.acos(((c ** 2 + a ** 2) - b ** 2 * 1.) / ((2 * 
282                    c) * a)))
283        elif a and b and gamma:
284
285        # Un angle et les deux côtés adjacents
286
287            (c, beta, alpha) = self.triangle_angle_cotes_adjacents(a, b,
288                    gamma)
289        elif b and c and alpha:
290            (a, gamma, beta) = self.triangle_angle_cotes_adjacents(b, c,
291                    alpha)
292        elif c and a and beta:
293            (b, alpha, gamma) = self.triangle_angle_cotes_adjacents(c, a,
294                    beta)
295        elif b and c and beta:
296
297        # Un angle, le côté opposé et un côté adjacent
298
299            (a, alpha, gamma) = self.triangle_angle_cote_adjacent_cote_oppose(b,
300                    c, beta)
301        elif b and a and beta:
302            (c, gamma, alpha) = self.triangle_angle_cote_adjacent_cote_oppose(b,
303                    a, beta)
304        elif a and b and alpha:
305            (c, gamma, beta) = self.triangle_angle_cote_adjacent_cote_oppose(a,
306                    b, alpha)
307        elif a and c and alpha:
308            (b, beta, gamma) = self.triangle_angle_cote_adjacent_cote_oppose(a,
309                    c, alpha)
310        elif c and a and gamma:
311            (b, beta, alpha) = self.triangle_angle_cote_adjacent_cote_oppose(c,
312                    a, gamma)
313        elif c and b and gamma:
314            (a, alpha, beta) = self.triangle_angle_cote_adjacent_cote_oppose(c,
315                    b, gamma)
316        elif alpha and beta and c:
317
318        # Deux angles et le côté commun
319
320            pass  # on sait faire
321        elif beta and gamma and a:
322            c = (a * math.sin((gamma * math.pi) / 180)) / math.sin(((beta + 
323                    gamma) * math.pi) / 180)
324            alpha = (180 - beta) - gamma
325        elif alpha and gamma and b:
326            c = (b * math.sin((gamma * math.pi) / 180)) / math.sin(((alpha + 
327                    gamma) * math.pi) / 180)
328            beta = (180 - alpha) - gamma
329        elif a and alpha and beta:
330
331        # Deux angles et un côté non commun
332
333            c = (a * math.sin(((alpha + beta) * math.pi) / 180)) / math.sin((alpha * 
334                    math.pi) / 180)
335        elif a and alpha and gamma:
336            c = (a * math.sin((gamma * math.pi) / 180)) / math.sin((alpha * 
337                    math.pi) / 180)
338            beta = (180 - alpha) - gamma
339        elif b and beta and alpha:
340            c = (b * math.sin(((alpha + beta) * math.pi) / 180)) / math.sin((beta * 
341                    math.pi) / 180)
342        elif b and beta and gamma:
343            c = (b * math.sin((gamma * math.pi) / 180)) / math.sin((beta * 
344                    math.pi) / 180)
345            alpha = (180 - beta) - gamma
346        elif c and alpha and gamma:
347            beta = (180 - alpha) - gamma
348        elif c and beta and gamma:
349            alpha = (180 - beta) - gamma
350        alpha = alpha + rotation
351        beta = beta - rotation
352
353
354        self.text.append(%s= (%s*u, 0) rotated %s;\n" % (B, c, rotation))
355        self.text.append(%s = %s + whatever*dir(%s);\n" % (C, A, alpha))
356        self.text.append(%s = %s + whatever*dir(180-%s);\n" % (C, B, beta))
357        self.text.append("  draw %s -- %s -- %s -- cycle;\n" % (A, B, C))
358
359        # Codage de l'angle droit s'il y en a un.
360
361        if angledroit:
362            if alpha - rotation == 90:
363                self.text.append("  draw (%s+5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s)+\n" % (A, B, A, A, B, A))
364                self.text.append("      5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s));\n" % (C, A, A, C, A))
365            elif beta + rotation == 90:
366                self.text.append("  draw (%s+5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s)+\n" % (B, A, B, B, A, B))
367                self.text.append("      5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s));\n" % (C, B, B, C, B))
368            elif gamma == 90:
369                self.text.append("  draw (%s+5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s)+\n" % (C, A, C, C, A, C))
370                self.text.append("      5*unitvector(%s-%s))--(%s+5*unitvector(%s-%s));\n" % (B, C, C, B, C))
371            for i in range(3):
372                if marques[i]:
373                    self.text.append("  m3:=unitvector(%s-%s) rotated 90;\n" % (points[(i + 1) % 3], points[(i + 2) % 3]))
374                    self.text.append("  $:=image(\n")
375                    self.text.append("    label(btex %s etex rotated angle(%s-%s),(%s+%s)/2+2mm*m3);\n" % (marques[i], points[(i + 1) % 3], points[(i + 2) % 3], points[(i + 1) % 3], points[(i + 2) % 3]))
376                    self.text.append("    );\n  draw $;\n")
377        self.text.append("  label.llft(btex $%s$ etex, %s);\n" % (A, A))
378        self.text.append("  label.lrt(btex $%s$ etex, %s);\n" % (B, B))
379        self.text.append("  label.top(btex $%s$ etex, %s);\n" % (C, C))
380        self.text.append("""endfig;
381
382""")
383        self.num = self.num + 1
384        return self
385
386    def triangle_angle_cotes_adjacents(self, a, b, gamma):
387        c = math.sqrt(a ** 2 + b ** 2 - 2 * a * b * math.cos(radians(gamma)))
388        alpha = 90. - gamma / 2 + degres(math.atan((((a - b) * 1.) / (a + b)) / 
389                math.tan(radians(gamma / 2))))
390        beta = 90. - gamma / 2 - degres(math.atan((a - b) * 1. / (a + b) / 
391                math.tan(radians(gamma / 2))))
392        return (c, beta, alpha)
393
394    def triangle_angle_cote_adjacent_cote_oppose(self, b, c, beta):
395        if b <= c * math.sin((beta * math.pi) / 180):
396            alpha = gamma = a = 0  # Pas possible de résoudre
397        else:
398            gamma = degres(math.asin(((c * math.sin((beta * math.pi) / 180)) / 
399                     b) * 1.))
400            alpha = (180 - beta) - gamma
401            a = math.sqrt(b ** 2 - c ** 2 * math.sin((beta * math.pi) / 
402                          180) ** 2) + c * math.cos((beta * math.pi) / 
403                    180)
404        return (a, alpha, gamma)
405
406
407# fig = Metapost()
408# fig = Metapost.triangle(
409    # fig, "A", "B",  "C", a=3, b=4.2, c=4.2, rotation=10, angledroit=1)
410# fig = Metapost.triangle(
411    # fig, "D", "E",  "F", a=4, b=5.7, c=6.5, rotation=90, angledroit=1)
412# fig = Metapost.triangle(
413    # fig, "G", "H",  "I", a=3.5, b=3.5, c=3.5, rotation=0, angledroit=1)
414# fig = Metapost.triangle(
415    # fig, "J", "K",  "L", a=4, b=4.5, c=4.5, rotation=30, angledroit=1)
416# fig = Metapost.fin(fig)
417# print string.join(fig.text, "")
Note: See TracBrowser for help on using the repository browser.