source: pyromaths/trunk/fuentes/src/pyromaths/ex/sixiemes/angles.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: 17.3 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 pyromaths.outils import Geometrie
27from pyromaths import ex
28
29
30def eq_droites(A, B):
31    (xA, yA) = A
32    (xB, yB) = B
33    a = ((yB - yA) * 1.0) / (xB - xA)
34    b = ((xB * yA - xA * yB) * 1.0) / (xB - xA)
35    return (a, b)
36
37
38def inter_droites(A, B, C, D):
39    """
40    Calcule les coordonnées du point d'intersection des droites (AB) et (CD)
41    """
42
43    (a1, b1) = eq_droites(A, B)
44    (a2, b2) = eq_droites(C, D)
45    if a1 == a2:  # droites parallèles
46        xI = A[0]
47        yI = A[1]
48    else:
49        xI = ((b2 - b1) * 1.0) / (a1 - a2)
50        yI = ((a1 * b2 - a2 * b1) * 1.0) / (a1 - a2)
51    return (xI, yI)
52
53
54def dist_pt_droite(A, B, C):
55    """
56    calcule la distance du point C à la droite (AB)
57    """
58
59    (a, b) = eq_droites(A, B)
60    (xC, yC) = C
61    d = (abs(a * xC - yC + b) * 1.0) / math.sqrt(a ** 2 + 1)
62    return d
63
64
65def dist_points(A, B):
66    """ Calcul la distance entre deux points"""
67
68    (xA, yA) = A
69    (xB, yB) = B
70    d = math.sqrt((xB - xA) ** 2 + (yB - yA) ** 2)
71    return d
72
73
74def coord_projete(A, B, C):
75    """
76    Calcule les coordonnées du projeté orthogonal de C sur la droite (AB)
77    """
78
79    (xA, yA) = A
80    (xB, yB) = B
81    (xC, yC) = C
82    n = dist_points(A, B)
83    p = (xB - xA) / n
84    q = (yB - yA) / n
85    s = p * (xC - xA) + q * (yC - yA)
86    return (xA + s * p, yA + s * q)
87
88
89def verifie_distance_mini(A, B, C, D):
90    """
91    Vérifie que la distance minimale entre [AB] et [AC] est supérieure à dmin
92    """
93
94    dmin = 1.2
95    (xA, yA) = A
96    (xB, yB) = B
97    if xA > xB:
98        (xA, yA, xB, yB) = (xB, yB, xA, yA)
99    (xC, yC) = C
100    (xD, yD) = D
101    if xC > xD:
102        (xC, yC, xD, yD) = (xD, yD, xC, yC)
103    (xI, dummy) = inter_droites(A, B, C, D)
104    if xA <= xI <= xB and xC <= xI <= xD or xA <= coord_projete(A, B, C)[0] <= \
105        xB and dist_pt_droite(A, B, C) < dmin or xA <= coord_projete(A,
106            B, D)[0] <= xB and dist_pt_droite(A, B, D) < dmin or xC <= \
107        coord_projete(C, D, A)[0] <= xD and dist_pt_droite(C, D, A) < \
108        dmin or xC <= coord_projete(C, D, B)[0] <= xD and dist_pt_droite(C,
109            D, B) < dmin or dist_points(A, C) < dmin or dist_points(A, D) < \
110        dmin or dist_points(B, C) < dmin or dist_points(B, D) < dmin:
111        isValid = False
112    else:
113        isValid = True
114    return isValid
115
116
117def verifie_angle(lpoints, A, B, C):
118    """
119    Vérifie que l'angle BAC ne coupe pas les autres angles déjà tracés
120    """
121
122    if len(lpoints) == 0:  # Premier angle créé
123        isValid = True
124    else:
125        for i in range(len(lpoints)):
126            (A1, B1, C1) = (lpoints[i])[:3]
127            isValid = verifie_distance_mini(A, B, A1, B1) and \
128                verifie_distance_mini(A, B, A1, C1) and \
129                verifie_distance_mini(A, C, A1, B1) and \
130                verifie_distance_mini(A, C, A1, C1)
131            if not isValid:
132                break
133    return isValid
134
135
136def cree_angles(nb_angles, xmax, ymax):
137    '''
138    crée une série d\'angles "non séquents"
139    '''
140
141    (xmax, ymax) = (xmax - .5, ymax - .5)  # taille de l'image en cm
142    lg_seg = 6  # longueur des côtés des angles
143    lpoints = []
144    cpt = 0  # evite une boucle infinie
145    while len(lpoints) < nb_angles and cpt < 1000:
146        (xA, yA) = (randrange(5, xmax * 10) / 10.0, randrange(5, ymax *
147                    10) / 10.0)
148        alpha = randrange(360)  # angle entre un côté et l'horizontal
149        if len(lpoints) < nb_angles / 2:
150            beta = randrange(90, 180)  # crée un angle droit ou obtus
151        else:
152            beta = randrange(0, 75) + 15  # crée un angle aigu (entre 15° et 89°)
153        xB = xA + lg_seg * math.cos((alpha * math.pi) / 180)
154        yB = yA + lg_seg * math.sin((alpha * math.pi) / 180)
155        xC = xA + lg_seg * math.cos(((alpha + beta) * math.pi) / 180)
156        yC = yA + lg_seg * math.sin(((alpha + beta) * math.pi) / 180)
157        (A, B, C) = ((xA, yA), (xB, yB), (xC, yC))
158        if xA != xB and xA != xC and .5 < xB < xmax and .5 < yB < ymax and \
159            .5 < xC < xmax and .5 < yC < ymax and verifie_angle(lpoints,
160                A, B, C):
161            lpoints.append((A, B, C, alpha, beta))
162        else:
163            cpt = cpt + 1
164
165    # print len(lpoints)
166
167    return lpoints
168
169
170def PosAngle(alpha, beta):
171    """retourne les angles pour placer les points sur la figure"""
172
173    A = (alpha + beta / 2.0 + 180) % 360
174    B = (alpha - 90) % 360
175    C = (alpha + beta + 90) % 360
176    return (A, B, C)
177
178
179def PointName(l3noms, indice):
180    liste = []
181    for i in range(3):
182        liste.append(l3noms[i])
183    return tuple(liste)
184
185
186def figure(exo, cor, lpoints, lnoms, xmax, ymax):
187    exo.append("\\begin{pspicture}(%s,%s)" % (xmax, ymax))
188    exo.append("\\psframe(0,0)(%s,%s)" % (xmax, ymax))
189    exo.append("\\psset{PointSymbol=none,MarkAngleRadius=0.6}")
190    cor.append("\\begin{pspicture}(%s,%s)" % (xmax, ymax))
191    cor.append("\\psset{PointSymbol=none,MarkAngleRadius=0.6}")
192    cor.append("\\psframe(0,0)(%s,%s)" % (xmax, ymax))
193    for i in range(len(lnoms)):
194        points_exo = ''
195        points_cor = ''
196        points_exo += "\\pstGeonode[PointName={%s,%s,%s}," % lnoms[i]
197        points_cor += "\\pstGeonode[PointName={%s,%s,%s}," % lnoms[i]
198        points_exo += "PosAngle={%s,%s,%s}]" % PosAngle(lpoints[i][3], lpoints[i][4])
199        points_cor += "PosAngle={%s,%s,%s}]" % PosAngle(lpoints[i][3], lpoints[i][4])
200        for j in range(3):
201            points_exo += "(%.2f,%.2f)" % lpoints[i][j]
202            points_exo += "{a%s%s}" % (j, i)
203            points_cor += "(%.2f,%.2f)" % lpoints[i][j]
204            points_cor += "{a%s%s}" % (j, i)
205        exo.append(points_exo)
206        cor.append(points_cor)
207        exo.append("\\pstMarkAngle{a%s%s}{a%s%s}{a%s%s}{}" % (1, i, 0, i, 2, i))
208        cor.append("\\pstMarkAngle{a%s%s}{a%s%s}{a%s%s}{}" % (1, i, 0, i, 2, i))
209        exo.append("\\pstLineAB[nodesepB=-.5]{a0%s}{a1%s}\\pstLineAB[arrows=-|,linestyle=none]{a0%s}{a1%s}" % (i, i, i, i))
210        cor.append("\\pstLineAB[nodesepB=-.5]{a0%s}{a1%s}\\pstLineAB[arrows=-|,linestyle=none]{a0%s}{a1%s}" % (i, i, i, i))
211        exo.append("\\pstLineAB[nodesepB=-.5]{a0%s}{a2%s}\\pstLineAB[arrows=-|,linestyle=none]{a0%s}{a2%s}" % (i, i, i, i))
212        cor.append("\\pstLineAB[nodesepB=-.5]{a0%s}{a2%s}\\pstLineAB[arrows=-|,linestyle=none]{a0%s}{a2%s}" % (i, i, i, i))
213    exo.append("\\end{pspicture}\\par")
214    cor.append("\\end{pspicture}\\par")
215    return (exo, cor)
216
217
218def reponses(exo, cor, lpoints, lnoms):
219    cor.append("\\begin{multicols}{4}")
220    for i in range(len(lnoms)):
221        cor.append("$\\widehat{%s%s%s}=%s\degres$\\par" % (lnoms[i][1],
222                 lnoms[i][0], lnoms[i][2], lpoints[i][4]))
223        if lpoints[i][4] < 90:
224            cor.append("angle aigu\\par")
225        elif lpoints[i][4] > 90:
226            cor.append("angle obtus\\par")
227        else:
228            cor.append("angle droit\\par")
229    cor.append("\\end{multicols}")
230    exo.append("\\begin{tabularx}{\\textwidth}{|*{4}{X|}}")
231    exo.append("\\hline angle 1 : & angle 2 : & angle 3 : & angle 4 : \\\\")
232    exo.append("\\hline &&& \\\\ &&& \\\\ &&& \\\\ \\hline")
233    exo.append("\\end{tabularx}")
234
235
236def MesureAngles():
237    nb_angles = 4
238    (xmax, ymax) = (18, 8)  # taille de l'image en cm
239    lnoms = []
240    lpoints = []
241    cpt = 0
242    while len(lpoints) < nb_angles:
243        if cpt > 1000:
244            lpoints = []
245            cpt = 0
246        lpoints = cree_angles(nb_angles, xmax, ymax)
247        cpt = cpt + 1
248    tmpl = Geometrie.choix_points(3 * nb_angles)
249    for i in range(nb_angles):
250        lnoms.append(tuple(tmpl[3 * i:3 * i + 3]))
251    exo = ["\\exercice", "Nommer, mesurer et donner la nature de chacun des angles suivants :\\par "]
252    cor = ["\\exercice*", "Nommer, mesurer et donner la nature de chacun des angles suivants :\\par "]
253    figure(exo, cor, lpoints, lnoms, xmax, ymax)
254    reponses(exo, cor, lpoints, lnoms)
255    return (exo, cor)
256
257MesureAngles.description = u'Mesurer des angles'
258
259class ConstruireZigZag(ex.TexExercise):
260
261    description = u'Construire des angles'
262
263    def __init__(self):
264        """ Crée une liste de nbp points situés à la distance lg les uns des
265        autres"""
266        from pyromaths.outils.Conversions import radians
267        from math import sin, cos
268        self.lg, nbp = 4, 6
269        fini = False
270        while not fini:
271            ar = randrange(80, 91)
272            angles_relatifs = [ar]
273            angles_absolus = [ar]
274            ar = radians(ar)
275            points = [(.2, .2), (.2 + self.lg * cos(ar), .2 + self.lg * sin(ar))]
276            for i in range(nbp - 1):
277                point = (-1, -1)
278                cpt = 0  # évite les boucles infinies
279                while (not point[0] < 16.2 or not 0.2 < point[1] < self.lg + 1) and cpt < 100:
280                    if i % 2:
281                        aa = randrange(angles_absolus[-1], 80)
282                    else:
283                        aa = randrange(-80, angles_absolus[-1])
284                    ar = 180 - abs(aa - angles_absolus[-1])
285                    aar = radians(aa)
286                    point = (points[-1][0] + self.lg * cos(aar), points[-1][1] + self.lg * sin(aar))
287                    cpt += 1
288                if cpt == 100:
289                    break
290                else:
291                    points.append(point)
292                    angles_absolus.append(aa)
293                    angles_relatifs.append(ar)
294            if cpt < 100: fini = True
295        self.points, self.angles_relatifs, self.angles_absolus = points, angles_relatifs, angles_absolus
296
297    def tex_place_les_points_zigzag(self, corrige=False):
298        exo = "\\pstGeonode[PosAngle=%.2f, PointSymbol=x](%.2f, %.2f){%s} " % \
299                (self.angles_absolus[0] - 180, self.points[0][0], self.points[0][1], chr(65))
300        if not corrige:
301            exo += "\\pstGeonode[PosAngle=%.2f, PointSymbol=x](%.2f, %.2f){B} " % \
302                (self.angles_absolus[1] + self.angles_relatifs[1] / 2. - 180, self.points[1][0], self.points[1][1])
303            exo += "\pstSegmentMark{A}{B}\n"
304        x1, y1 = inter_droites(self.points[0], self.points[-1], self.points[1], self.points[-2])
305        if 0 < x1 < 18 and 0 < y1 < self.lg + 2:
306            cas = 0
307        else:
308            x1, y1 = inter_droites(self.points[0], self.points[-2], self.points[1], self.points[-1])
309            cas = 1
310        for i in range(1, 5):
311            exo += "\pscircle[linecolor=Gray](%.2f, %.2f){%.1f}\n" % (x1, y1, i / 10.)
312        if corrige:
313            for i in range(1, len(self.angles_relatifs)):
314                if self.angles_absolus[i - 1] > self.angles_absolus[i]:
315                    exo += "\\pstGeonode[PosAngle=%.2f](%.2f, %.2f){%s} " % \
316                            (self.angles_absolus[i] - self.angles_relatifs[i] / 2. - 180, self.points[i][0], self.points[i][1], chr(i + 65))
317                else:
318                    exo += "\\pstGeonode[PosAngle=%.2f](%.2f, %.2f){%s} " % \
319                            (self.angles_absolus[i] + self.angles_relatifs[i] / 2. - 180, self.points[i][0], self.points[i][1], chr(i + 65))
320
321                exo += "\pstSegmentMark{%s}{%s}\n" % (chr(i + 64), chr(i + 65))
322            exo += "\\pstGeonode[PosAngle=%.2f, PointSymbol=x](%.2f, %.2f){%s} " % \
323                    (self.angles_absolus[-1], self.points[-1][0], self.points[-1][1], chr(len(self.points) + 64))
324            exo += "\pstSegmentMark{%s}{%s}\n" % (chr(len(self.points) + 63), chr(len(self.points) + 64))
325            for i in range(len(self.angles_relatifs) - 1):
326                if self.angles_absolus[i] > self.angles_absolus[i + 1]:
327                    if self.angles_relatifs[i + 1] == 90:
328                        exo += "\\pstRightAngle{%s}{%s}{%s}\n" % \
329                                (chr(i + 65), chr(i + 66), chr(i + 67))
330                    else:
331                        exo += "\\pstMarkAngle{%s}{%s}{%s}{%s\\degres}\n" % \
332                                (chr(i + 65), chr(i + 66), chr(i + 67), self.angles_relatifs[i + 1])
333                else:
334                    if self.angles_relatifs[i + 1] == 90:
335                        exo += "\\pstRightAngle{%s}{%s}{%s}\n" % \
336                                (chr(i + 67), chr(i + 66), chr(i + 65))
337                    else:
338                        exo += "\\pstMarkAngle{%s}{%s}{%s}{%s\\degres}\n" % \
339                                (chr(i + 67), chr(i + 66), chr(i + 65), self.angles_relatifs[i + 1])
340            if cas:
341                exo += "\psline[linestyle=dotted](B)(G) "
342                exo += "\psline[linestyle=dotted](A)(F)"
343            else:
344                exo += "\psline[linestyle=dotted](B)(F) "
345                exo += "\psline[linestyle=dotted](A)(G)"
346        return exo
347
348    def tex_commun(self):
349        exo = [u'Construire sur la figure ci-dessous les points $C$, $D$, $E$, $F$ et $G$ pour obtenir un zigzag tel que :\\par']
350        exo_t = '$'
351        for i in range(len(self.angles_relatifs) - 1):
352            exo_t += r"\widehat{%s%s%s}=%s\degres \qquad " % (chr(i + 65), chr(i + 66), chr(i + 67), self.angles_relatifs[i + 1])
353        exo_t += r'$\par'
354        exo.append(exo_t)
355        exo.append(u"Quand le travail est fait avec une bonne précision, les ")
356        x1, y1 = inter_droites(self.points[0], self.points[-1], self.points[1], self.points[-2])
357        if 0 < x1 < 18 and 0 < y1 < self.lg + 2:
358            exo.append(u"droites $(AG)$ et $(BF)$ se coupent au c\\oe ur de la cible.\\par")
359        else:
360            exo.append(u"droites $(AF)$ et $(BG)$ se coupent au c\\oe ur de la cible.")
361        exo.append(r'\begin{center}')
362        exo.append("\\fbox{\n\\begin{pspicture}(-.4,-.4)(16.4, %s)\n" % (self.lg + 1.5))
363        return exo
364
365
366    def tex_statement(self):
367        exo = [r'\exercice']
368        exo.append(u'Voici deux exemples de zigzags :\par')
369        exo.append(r'\psset{unit=3.5mm,PointSymbol=none}')
370        exo.append(r'\begin{pspicture}(-.4,-1)(16.4, 7.5)')
371        exo.append(r'%\psgrid')
372        exo.append(r'\pstGeonode[PosAngle=-96.00,PointSymbol=x](0.20, 0.20){A}')
373        exo.append(r'\pstGeonode[PosAngle=-265.00](0.83, 6.17){B} \pstSegmentMark{A}{B}')
374        exo.append(r'\pstGeonode[PosAngle=-87.50](2.48, 0.40){C} \pstSegmentMark{B}{C}')
375        exo.append(r'\pstGeonode[PosAngle=-241.00](3.63, 6.29){D} \pstSegmentMark{C}{D}')
376        exo.append(r'\pstGeonode[PosAngle=-90.00](9.23, 4.14){E} \pstSegmentMark{D}{E}')
377        exo.append(r'\pstGeonode[PosAngle=-299.50](14.83, 6.29){F} \pstSegmentMark{E}{F}')
378        exo.append(r'\pstGeonode[PosAngle=-80.00,PointSymbol=x](15.87, 0.38){G}')
379        exo.append(r'\pstSegmentMark{F}{G}')
380        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{A}{B}{C}{}')
381        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{D}{C}{B}{}')
382        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{C}{D}{E}{}')
383        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{F}{E}{D}{}')
384        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{E}{F}{G}{}')
385        exo.append(r'\end{pspicture}')
386        exo.append(r'\hspace{2cm}')
387        exo.append(r'\begin{pspicture}(-.4,-1)(16.4, 7.5)')
388        exo.append(r'\pstGeonode[PosAngle=-91.00,PointSymbol=x](0.20, 0.20){A}')
389        exo.append(r'\pstGeonode[PosAngle=-263.50](0.30, 6.20){B} \pstSegmentMark{A}{B}')
390        exo.append(r'\pstGeonode[PosAngle=-101.00](1.76, 0.38){C} \pstSegmentMark{B}{C}')
391        exo.append(r'\pstGeonode[PosAngle=-259.00](5.28, 5.23){D} \pstSegmentMark{C}{D}')
392        exo.append(r'\pstGeonode[PosAngle=-82.50](10.37, 2.05){E} \pstSegmentMark{D}{E}')
393        exo.append(r'\pstGeonode[PosAngle=-286.00](14.46, 6.44){F} \pstSegmentMark{E}{F}')
394        exo.append(r'\pstGeonode[PosAngle=-79.00,PointSymbol=x](15.61, 0.55){G}')
395        exo.append(r'\pstSegmentMark{F}{G}')
396        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{A}{B}{C}{}')
397        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{D}{C}{B}{}')
398        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{C}{D}{E}{}')
399        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{F}{E}{D}{}')
400        exo.append(r'\pstMarkAngle[MarkAngleRadius=1.5]{E}{F}{G}{}')
401        exo.append(r'\end{pspicture}\par')
402        exo.append(r'\psset{unit=1cm}')
403        exo.extend(self.tex_commun())
404        exo.append(self.tex_place_les_points_zigzag(corrige=False))
405        exo.append(r'\end{pspicture}')
406        exo.append('}\n\\end{center}')
407        return exo
408
409    def tex_answer(self):
410        exo = [r'\exercice*']
411        exo.extend(self.tex_commun())
412        exo.append(self.tex_place_les_points_zigzag(corrige=True))
413        exo.append(r'\end{pspicture}')
414        exo.append('}\n\\end{center}')
415        return exo
416
Note: See TracBrowser for help on using the repository browser.