#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Pyromaths
# Un programme en Python qui permet de créer des fiches d'exercices types de
# mathématiques niveau collège ainsi que leur corrigé en LaTeX.
# Copyright (C) 2006 -- Jérôme Ortais (jerome.ortais@pyromaths.org)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
import random
from math import cos, sin, radians, pi
from ..outils.decimaux import decimaux
from ..outils.Arithmetique import pgcd
div180 = [[1,180],[2,90],[3,60],[4,45],[5,36],[6,30],[9,20],[10,18],[12,15]]
# Radians représentés en fait par des fractions
def deg2rad(n):
"""Effectue la conversion de degrés entre 0 et 360° vers radians."""
p = pgcd(n,180)
return [n/p,180/p]
def simprad(liste):
"""Simplifie la fraction d'un angle en radians."""
p = pgcd(liste[0],liste[1])
if p > 1:
return [f/p for f in liste]
else:
return liste
def rad2deg(liste):
"""Effectue la conversion de radians entre 0 et 2pi vers degrés."""
return liste[0]*180/liste[1] # Attention résultat entier, donc faux si liste[1] ne divise pas 180
def rad2tex(liste):
"""Prépare l'écriture de radians en latex."""
if liste[0]==0:
frac = "$0$"
elif liste[0]==liste[1]:
frac = "$\\pi$"
elif liste[0]==-liste[1]:
frac = "$-\\pi$"
elif liste[0]==1:
frac = "$\\dfrac{\\pi}{"+str(liste[1])+"}$"
elif liste[0]==-1:
frac = "$\\dfrac{-\\pi}{"+str(liste[1])+"}$"
elif liste[1]==-1: # Probablement inutile
frac = "$"+str(-liste[0])+"\\pi$"
elif liste[1]==1:
frac = "$"+str(liste[0])+"\\pi$"
else:
frac = "$\\dfrac{"+str(liste[0])+"\\pi}{"+str(liste[1])+"}$"
return frac
def rad2tex_quiz(liste):
"""Prépare l'écriture de radians en latex."""
if liste[0]==0:
frac = "0"
elif liste[0]==liste[1]:
frac = "\\pi"
elif liste[0]==-liste[1]:
frac = "-\\pi"
elif liste[0]==1:
frac = "\\frac{\\pi}{"+str(liste[1])+"}"
elif liste[0]==-1:
frac = "\\frac{-\\pi}{"+str(liste[1])+"}"
elif liste[1]==-1: # Probablement inutile
frac = str(-liste[0])+"\\pi"
elif liste[1]==1:
frac = str(liste[0])+"\\pi"
else:
frac = "\\frac{"+str(liste[0])+"\\pi}{"+str(liste[1])+"}"
return frac
def mes_princ(liste, sim = True):
"""Calcule la mesure principale d'un angle en radians ( entre -pi et pi )."""
num = liste[0] % (2*liste[1])
if num > liste[1]:
num -= 2*liste[1]
if sim == True:
return simprad([num,liste[1]])
else:
return [num,liste[1]]
def mes_02pi(liste, sim = True):
"""Calcule la mesure d'un angle en radians dans l'intervalle [0,2pi]."""
num = liste[0] % (2*liste[1])
if sim == True:
return simprad([num,liste[1]])
else:
return [num,liste[1]]
def cercle_trigo(code=0,*args):
"""Dessine le cercle trigonométrique avec un nombre indéfini d'angles en degrés ou radians, en codant ou non les angles."""
figure = """\\psset{xunit=3cm,yunit=3cm,dotstyle=+}
\\begin{pspicture}(-1.4,-1.4)(1.4,1.4)
\\psframe(-1.4,-1.4)(1.4,1.4)
\\psaxes[linewidth=0.5pt,Dx=2,Dy=2]{->}(0,0)(-1.1,-1.1)(1.1,1.1)
\\pscircle[linecolor=gray](0,0){3}
\\definecolor{grisclair}{gray}{0.20}
\\colorlet{bleuclair}{blue!40!white}\n"""
idx = 0
if not code:
for a in range(11):
if (a+1)/6.0 not in [0.5,1,1.5]:
figure += "\\psline[linecolor=LightSkyBlue,linestyle=dashed](0,0)("+str(round(cos((a+1)*pi/6),2))+","+str(round(sin((a+1)*pi/6),2))+")\n"
for a in range(9):
if (a+1)/5.0 not in [0.5,1,1.5]:
figure += "\\psline[linecolor=LightSlateGray,linestyle=dashed](0,0)("+str(round(cos((a+1)*pi/5),2))+","+str(round(sin((a+1)*pi/5),2))+")\n"
for a in range(4):
figure += "\\psline[linecolor=LightGreen,linestyle=dashed](0,0)("+str(round(cos((2*a+1)*pi/4),2))+","+str(round(sin((2*a+1)*pi/4),2))+")\n"
for f in args:
if isinstance(f,list): # mesure en radians
rad = mes_princ(f, True)
else: # mesure en degrés
rad = mes_princ(deg2rad(f), True)
f = rad[0]*pi/rad[1] # Le dénominateur ne devrait pas être nul...
frac = rad2tex(rad)
figure += "\\psline[linecolor=red,linestyle=dashed](0,0)("+str(round(cos(f),2))+","+str(round(sin(f),2))+")\n"
if code:
figure += "\\rput("+str(round(1.25*cos(f),2))+","+str(round(1.25*sin(f),2))+"){"+frac+"}\n"
else:
figure += "\\rput("+str(round(1.25*cos(f),2))+","+str(round(1.25*sin(f),2))+"){$M_"+str(idx)+"$}\n"
idx += 1
figure += """\\uput[dl](0,0){$O$}
\uput[dr](1,0){$I$}
\uput[ul](0,1){$J$}"""
figure += "\n\\end{pspicture}"
return figure
def findrad(itv=1, neg=0, denom_simple=1):
"""Génère un angle en radians sous certaines conditions :
itv ( intervalle ): 0 ( quelconque ), 1 ( mesure principale ), 2 ( entre 0 et 2 pi )
neg : 0 ( positif ), 1 ( négatif )
denom_simple : 0 ( quelconque ), 1 ( simple, càd 1, 2, 3, 4, 5, ou 6 ), 2 ( diviseur de 180 )"""
global div180
if denom_simple==1:
denom = random.randint(2,6)
elif denom_simple == 0:
denom = random.randint(2,30)
else:
random.shuffle(div180)
random.shuffle(div180[0])
denom = div180[0][0]
if itv == 1:
sgn = (-1)**(random.randint(1,2))
num = sgn * random.randint(1,denom) # pas grave si -pi sort
elif itv == 2:
num = random.randint(1,2*denom)
else:
numliste = [random.randint(2*denom, 120),random.randint(-2*denom, -denom)]
random.shuffle(numliste)
num = numliste[0]
if (neg and (num > 0)) or ((not neg) and (num < 0)):
num = -num
return [num,denom] # FIX Simplifier ?
def cercle_trigonometrique():
"""Exercice de la fiche."""
exo = ["\\exercice"]
cor = ["\\exercice*"]
quiz = ["cloze"]
mes_deg = [] # Question 1
while len(mes_deg)<5:
tmp = random.randint(0,360) # FIX trop complexes parfois
if tmp not in mes_deg:
mes_deg.append(tmp)
mes_deg_tex = [u"$%s\\degres$" %(d) for d in mes_deg]
radq2 = [] # Question 2
while len(radq2)<5:
tmp = findrad(2,0,2) # Dénominateur est un diviseur de 180
if tmp not in radq2:
radq2.append(tmp)
radq3 = [] # Question 3
while len(radq3)<5:
while len(radq3)<4:
tmp = findrad(0,0,0)
if tmp not in radq3:
radq3.append(tmp)
tmp = findrad(0,1,0) # dernier négatif
if tmp not in radq3:
radq3.append(tmp)
radq4 = [] # Question 4
while len(radq4)<4:
tmp = mes_princ(findrad(0,0,1))
if tmp not in radq4:
radq4.append(tmp)
radq5 = [] # Question 5
radq5_princ = []
while len(radq5)<4:
while len(radq5)<2:
tmp = findrad(1,0,1)
tmp_princ = mes_princ(tmp)
if tmp_princ not in radq5_princ:
radq5.append(tmp)
radq5_princ.append(tmp_princ)
while len(radq5)<3:
tmp = findrad(1,1,1) # avant-dernier négatif
tmp_princ = mes_princ(tmp)
if tmp_princ not in radq5_princ:
radq5.append(tmp)
radq5_princ.append(tmp_princ)
tmp = findrad(0,0,1) # dernier non principal
tmp_princ = mes_princ(tmp)
if tmp_princ not in radq5_princ:
radq5.append(tmp)
mes_rad = radq2 + radq3 + radq4 + radq5
mes_rad_tex = [rad2tex(r)for r in mes_rad]
mes_rad_en_deg_tex = [rad2deg(r) for r in radq2] # <-- MIO
mes_deg_en_rad = [deg2rad(d) for d in mes_deg]
mes_deg_en_rad_tex = [rad2tex(r) for r in mes_deg_en_rad]
exo.append(u"\\begin{enumerate}")
exo.append(_(u"\\item Convertir les cinq mesures suivantes en radians : %s, %s, %s, %s et %s.") %(tuple(mes_deg_tex)))
exo.append(_(u"\\item Convertir les cinq mesures suivantes en degrés : %s, %s, %s, %s et %s~rad.") %(tuple(mes_rad_tex[0:5])))
exo.append(_(u"\\item Déterminer les mesures principales des angles suivants en radians : %s, %s, %s, %s et %s~rad.") %(tuple(mes_rad_tex[5:10])))
exo.append(_(u"\\item Des angles ont été placés sur le cercle trigonométrique ci-dessous, représentés en rouge par les points $M_0$, $M_1$, $M_2$ et $M_3$. Lire leurs mesures principales en radians"))
exo.append(_(u"( les lignes vertes, grises et bleues représentent des angles multiples de $\\dfrac{\\pi}{3}$, de $\\dfrac{\\pi}{4}$ et de $\\dfrac{\\pi}{5}$ ).\\par"))
exo.append(cercle_trigo(0,radq4[0],radq4[1],radq4[2],radq4[3]))
exo.append(_(u"\\item Placer les angles suivants sur le cercle trigonométrique : %s, %s, %s et %s~rad.\\par") %(tuple(mes_rad_tex[14:])))
exo.append(cercle_trigo())
exo.append(u"\\end{enumerate}\\par")
cor.append(u"\\begin{enumerate}")
cor.append(_(u"\\item Convertir les cinq mesures suivantes en radians : %s, %s, %s, %s et %s.\\par") %(tuple(mes_deg_tex)))
cor.append(_(u"La conversion est en fait une simple règle de proportionnalité : il faut multiplier par $\\dfrac{\\pi}{180}$.\\par"))
cor.append(_(u"Par exemple pour la première mesure, on obtient avec simplification : $")+str(mes_deg[0])+_("\\times\\dfrac{\\pi}{180}$ = ")+mes_deg_en_rad_tex[0]+"~rad.\\par")
cor.append(_(u"De même pour les autres mesures, on trouve alors respectivement : %s~rad, %s~rad, %s~rad, %s~rad et %s~rad.") %(tuple(mes_deg_en_rad_tex)))
cor.append(_(u"\\item Convertir les cinq mesures suivantes en degrés : %s, %s, %s, %s et %s~rad.\\par") %(tuple(mes_rad_tex[0:5])))
cor.append(_(u"On effectue alors la proportionnalité inverse : il faut multiplier par $\\dfrac{180}{\\pi}$.\\par"))
cor.append(_(u"Après simplification, voici les résultats : %s\\degres, %s\\degres, %s\\degres, %s\\degres et %s\\degres.") %(tuple([rad2deg(r) for r in radq2])))
cor.append(_(u"\\item Déterminer les mesures principales des angles suivants en radians : %s, %s, %s, %s et %s~rad.\\par") %(tuple(mes_rad_tex[5:10])))
rep = mes_princ(radq3[0])
rep_ns = mes_princ(radq3[0], False)
nb_mio = (radq3[0][0]-rep[0])/(2*radq3[0][1])
nb_mio_ns = (radq3[0][0]-rep_ns[0])/(2*radq3[0][1])
if nb_mio == 0:
nb_tours = 1
nb_tours_ns = 1
else:
nb_tours = nb_mio
nb_tours_ns = nb_mio_ns
cor.append(_(u"Une mesure d'angle en radians est définie modulo $2\\pi$, c'est-à-dire que l'ajout ou la suppression d'un tour ( qui vaut $2\\pi$ ou 360\\degres ) ne change pas un angle.\\par"))
cor.append(_(u"Concrètement, avec le premier angle de la question, on remarque que :\\par"))
#cor.append(rad2tex(radq3[0])[:-1]+"\\equiv"+rad2tex(rep)[1:-1]+"+"+rad2tex([2*nb_tours*rep[1],rep[1]])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+"+"+rad2tex([2*nb_tours,1])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+u"~(2\\pi)$.\\par")
cor.append(rad2tex(radq3[0])[:-1]+"\\equiv"+rad2tex(rep_ns)[1:-1]+"+"+rad2tex([2*nb_tours_ns*rep_ns[1],rep_ns[1]])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+"+"+rad2tex([2*nb_tours,1])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+u"~(2\\pi)$.\\par")
cor.append(_(u"De même pour les autres mesures, on trouve alors respectivement : %s~rad, %s~rad, %s~rad, %s~rad et %s~rad.") %(tuple([rad2tex(mes_princ(r)) for r in radq3])))
cor.append(_(u"\\item Des angles ont été placés sur le cercle trigonométrique ci-dessous, représentés en rouge par les points $M_0$, $M_1$, $M_2$ et $M_3$. Lire leurs mesures principales en radians"))
cor.append(_(u"( les lignes vertes, grises et bleues représentent des angles multiples de $\\dfrac{\\pi}{3}$, de $\\dfrac{\\pi}{4}$ et de $\\dfrac{\\pi}{5}$ ).\\par"))
cor.append(_(u"Les réponses sont directement données sur le cercle trigonométrique ci-dessous :\\par"))
cor.append(cercle_trigo(1,mes_princ(radq4[0]),mes_princ(radq4[1]),mes_princ(radq4[2]),mes_princ(radq4[3])))
cor.append(u"\\par")
cor.append(_(u"Les points $M_0$, $M_1$, $M_2$ et $M_3$ définissent alors respectivement les angles %s, %s, %s et %s~rad.") %(tuple(mes_rad_tex[10:14])))
cor.append(_(u"\\item Placer les angles suivants sur le cercle trigonométrique : %s, %s, %s et %s~rad.\\par") %(tuple(mes_rad_tex[14:])))
cor.append(_(u"Les réponses sont directement données sur le cercle trigonométrique ci-dessous :\\par"))
cor.append(cercle_trigo(1,radq5[0],radq5[1],radq5[2],radq5[3]))
#cor.append(cercle_trigo(1,(tuple(mes_rad_tex[14:]))
#cor.append(cercle_trigo(1,mes_rad_tex[14],mes_rad_tex[15],mes_rad_tex[16],mes_rad_tex[17]))
cor.append(u"\\par")
rep = mes_princ(radq5[3])
rep_ns = mes_princ(radq5[3], False)
nb_mio = (radq5[3][0]-rep[0])/(2*radq5[3][1])
nb_mio_ns = (radq5[3][0]-rep_ns[0])/(2*radq5[3][1])
if nb_mio == 0:
nb_tours = 1
nb_tours_ns = 1
else:
nb_tours = nb_mio
nb_tours_ns = nb_mio_ns
cor.append(_(u"Ajoutons une simple remarque pour la dernière mesure, qui n'est pas principale : il faut effectuer en premier lieu une simplification, comme à la question 3. On obtient alors :\\par"))
#cor.append(rad2tex(radq5[3])[:-1]+"\\equiv"+rad2tex(mes_princ(radq5[3]))[1:-1]+"~(2\\pi)$.")
cor.append(rad2tex(radq5[3])[:-1]+"\\equiv"+rad2tex(rep_ns)[1:-1]+"+"+rad2tex([2*nb_tours_ns*rep_ns[1],rep_ns[1]])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+"+"+rad2tex([2*nb_tours,1])[1:-1]+"\\equiv"+rad2tex(rep)[1:-1]+u"~(2\\pi)$.")
cor.append(u"\\end{enumerate}\\par")
quiz_nom = _(u"Cercle trigonométrique: aux radians")
quiz_exo_cor = _(u"Convertit aux radians et simplifie les cinq suivantes mesures d'angles:
\n")
quiz_exo_cor += _(u"Réponse: (Utilise la barre \"/\" pour écrire la fraction irréductible)
\n")
mes_deg_tex_quiz = [u"%s^{\\circ}" %(d) for d in mes_deg]
mes_deg_en_rad_quiz = []
for d in mes_deg:
if deg2rad(d)[1] == 1:
mes_deg_en_rad_quiz.append(str(deg2rad(d)[0]))
else:
mes_deg_en_rad_quiz.append(str(deg2rad(d)[0])+"/"+str(deg2rad(d)[1]))
quiz_exo_cor += (u"$$%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$
\n" %
(mes_deg_tex_quiz[0], "%", "%", mes_deg_en_rad_quiz[0], mes_deg_tex_quiz[1], "%", "%", mes_deg_en_rad_quiz[1]))
quiz_exo_cor += (u"$$%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$" %
(mes_deg_tex_quiz[2], "%", "%", mes_deg_en_rad_quiz[2], mes_deg_tex_quiz[3], "%", "%", mes_deg_en_rad_quiz[3],
mes_deg_tex_quiz[4], "%", "%", mes_deg_en_rad_quiz[4]))
quiz.append([quiz_nom, quiz_exo_cor, ""])
quiz_nom = _(u"Cercle trigonométrique: aux degrés")
quiz_exo_cor = _(u"Convertit aux degrés les cinq suivantes mesures d'angles:
\n")
quiz_exo_cor += _(u"Réponse:
\n")
mes_rad_tex_quiz = [rad2tex_quiz(r) for r in mes_rad]
quiz_exo_cor += (u"$$%s=$${1:NUMERICAL:=%s}$$^{\\circ}$$ ; $$\\,%s=$${1:NUMERICAL:=%s}$$^{\\circ}$$
\n" %
(mes_rad_tex_quiz[0], mes_rad_en_deg_tex[0], mes_rad_tex_quiz[1], mes_rad_en_deg_tex[1]))
quiz_exo_cor += (u"$$%s=$${1:NUMERICAL:=%s}$$^{\\circ}$$ ; $$\\,%s=$${1:NUMERICAL:=%s}$$^{\\circ}$$ ; $$\\,%s=$${1:NUMERICAL:=%s}$$^{\\circ}$$" %
(mes_rad_tex_quiz[2], mes_rad_en_deg_tex[2], mes_rad_tex_quiz[3], mes_rad_en_deg_tex[3],
mes_rad_tex_quiz[4], mes_rad_en_deg_tex[4]))
quiz.append([quiz_nom, quiz_exo_cor, ""])
quiz_nom = _(u"Círculo trigonométrico: equivalentes")
quiz_exo_cor = _(u"Détermine en radians, les mesures de ses angles équivalents entre $$0\\,$$ et $$\\,-\\pi$$:
\n")
quiz_exo_cor += _(u"Réponse: (Utilise la barre \"/\" pour écrire la fraction irréductible)
\n")
mes_sim_en_rad_quiz = []
for r in radq3:
if mes_princ(r, True)[1] == 1:
mes_sim_en_rad_quiz.append(str(mes_princ(r, True)[0]))
else:
mes_sim_en_rad_quiz.append(str(mes_princ(r, True)[0])+"/"+str(mes_princ(r, True)[1]))
quiz_exo_cor += (u"$$%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$
\n" %
(mes_rad_tex_quiz[5], "%", "%", mes_sim_en_rad_quiz[0], mes_rad_tex_quiz[6], "%", "%", mes_sim_en_rad_quiz[1]))
quiz_exo_cor += (u"$$%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$ ; $$\\,%s=$${1:SHORTANSWER:%s100%s%s}$$\\pi$$" %
(mes_rad_tex_quiz[7], "%", "%", mes_sim_en_rad_quiz[2], mes_rad_tex_quiz[8], "%", "%", mes_sim_en_rad_quiz[3],
mes_rad_tex_quiz[9], "%", "%", mes_sim_en_rad_quiz[4]))
quiz.append([quiz_nom, quiz_exo_cor, ""])
return exo, cor, quiz