15 changed files with 1403 additions and 33 deletions
@ -0,0 +1,21 @@ |
|||||
|
.PHONY: |
||||
|
.SUFFIXES: |
||||
|
|
||||
|
COMP = mdbg |
||||
|
OUT = cours |
||||
|
TITLE = "Microéconomie" |
||||
|
PACKAGE = "{{MyPack2}}" |
||||
|
AUTHOR = "Hugo LEVY--FALK" |
||||
|
DOCUMENTCLASS = "article" |
||||
|
|
||||
|
all: |
||||
|
$(COMP) $(OUT).mdbg --title $(TITLE) --packages $(PACKAGE) --date \\today --documentclass $(DOCUMENTCLASS) --author $(AUTHOR) |
||||
|
lualatex --shell-escape $(OUT).tex |
||||
|
lualatex --shell-escape $(OUT).tex |
||||
|
rm $(OUT).aux $(OUT).log $(OUT).out $(OUT).toc |
||||
|
rm $(OUT).tex |
||||
|
|
||||
|
clean: |
||||
|
rm $(OUT).aux $(OUT).log $(OUT).out $(OUT).toc |
||||
|
rm $(OUT).tex |
||||
|
|
||||
@ -0,0 +1,155 @@ |
|||||
|
\NeedsTeXFormat{LaTeX2e} |
||||
|
\ProvidesPackage{MyPack2} |
||||
|
|
||||
|
%%%%%%%% INCLUSIONS GÉNÉRALES %%%%%%%%% |
||||
|
\RequirePackage{babel} |
||||
|
%\RequirePackage{titlesec} |
||||
|
\RequirePackage{color} |
||||
|
\RequirePackage[a4paper]{geometry} |
||||
|
\RequirePackage[font=small,format=plain,labelfont=bf,up, |
||||
|
textfont=normal,up, |
||||
|
justification=justified, |
||||
|
singlelinecheck=false]{caption} |
||||
|
\RequirePackage[justification=centering]{caption} |
||||
|
\RequirePackage{xcolor} % Required for specifying custom colours |
||||
|
\definecolor{grey}{rgb}{0.9,0.9,0.9} % Colour of the box surrounding the title |
||||
|
\RequirePackage[utf8]{inputenc} % Required for inputting international characters |
||||
|
|
||||
|
\RequirePackage[T1]{fontenc} |
||||
|
% \RequirePackage[sfdefault]{ClearSans} % Use the Clear Sans font (sans serif) |
||||
|
\RequirePackage{placeins} |
||||
|
\RequirePackage{listings} |
||||
|
\RequirePackage{graphicx} |
||||
|
\RequirePackage{amsfonts} |
||||
|
|
||||
|
|
||||
|
|
||||
|
\definecolor{bleu}{RGB}{0,100,143} |
||||
|
\definecolor{gris}{RGB}{130,130,140} |
||||
|
\definecolor{grisBleu}{RGB}{65,115,141} |
||||
|
|
||||
|
|
||||
|
|
||||
|
%%%%%%%% MATH %%%%%%%%% |
||||
|
\RequirePackage{stmaryrd} |
||||
|
\newcommand*\intervalleEntier[2]{\intervalle{\llbracket}{#1}{#2}{\rrbracket}} |
||||
|
\newcommand*\intervalle[4]{\left#1 #2 \, ; #3 \right#4} |
||||
|
\newcommand*\intervalleOO[2]{\intervalle{]}{#1}{#2}{[}} |
||||
|
\newcommand*\intervalleFF[2]{\intervalle{[}{#1}{#2}{]}} |
||||
|
\newcommand*\intervalleOF[2]{\intervalle{]}{#1}{#2}{]}} |
||||
|
\newcommand*\intervalleFO[2]{\intervalle{[}{#1}{#2}{[}} |
||||
|
|
||||
|
\let\ensembleNombre\mathbb |
||||
|
\newcommand*\N{\ensembleNombre{N}} |
||||
|
\newcommand*\Z{\ensembleNombre{Z}} |
||||
|
\newcommand*\Q{\ensembleNombre{Q}} |
||||
|
\newcommand*\R{\ensembleNombre{R}} |
||||
|
\newcommand*\C{\ensembleNombre{C}} |
||||
|
|
||||
|
\newcommand*\enstq[2]{\left\{#1,\; #2\right\}} |
||||
|
|
||||
|
%\newcommand*\int[1]{\left\lfloor #1\right\rfloor} |
||||
|
%\newcommand*\norme[1]{\left\lVert#1\right\rVert} |
||||
|
%\newcommand*\abs[1]{\left\lvert#1\right\rvert} |
||||
|
|
||||
|
\let\vecteur\overrightarrow |
||||
|
|
||||
|
\newcommand*\Sys[1]{\left\{ \begin{aligned} #1 \end{aligned} \right. \kern-\nulldelimiterspace} |
||||
|
|
||||
|
\newcommand*\application[5]{ |
||||
|
#1 \colon |
||||
|
\begin{alignedat}{2}  &\to \\ |
||||
|
 &\mapsto  |
||||
|
\end{alignedat} |
||||
|
} |
||||
|
\newcommand*\applicationSigne[3]{ |
||||
|
#1 \colon #2 \to #3 |
||||
|
} |
||||
|
|
||||
|
\newtheorem{defi}{Définition}[section] |
||||
|
\newtheorem{theo}{Théorème}[section] |
||||
|
\newtheorem{prop}{Proposition}[section] |
||||
|
\newtheorem{ex}{Exemple}[section] |
||||
|
|
||||
|
|
||||
|
%%%%%%%% SECTIONNEMENT %%%%%%%%% |
||||
|
|
||||
|
%\renewcommand{\thesection}{\Roman{section}} |
||||
|
%\renewcommand{\thesubsection}{\arabic{subsection}} |
||||
|
|
||||
|
\newcommand*\emptyPage{\newpage\null\thispagestyle{empty}\addtocounter{page}{-1}\newpage} |
||||
|
|
||||
|
%%%%%%%% INTIALISATION DE LA PAGE %%%%%%%%% |
||||
|
\RequirePackage{fancyhdr} |
||||
|
\newcommand\initPage[3]{ |
||||
|
\pagestyle{fancy} |
||||
|
\fancyhead{#1} |
||||
|
\lhead{#2} |
||||
|
\rhead{#3} |
||||
|
\rfoot{} |
||||
|
\lfoot{} |
||||
|
|
||||
|
%\titleformat*{\section}{\Large\bfseries\color{bleu}\Roman{section}} |
||||
|
%\titleformat*{\subsection}{\large\bfseries\color{grisBleu}} |
||||
|
%\titleformat*{\subsubsection}{\bfseries\color{gris}} |
||||
|
%\titlespacing*{\section}{-3em}{*1}{*1} |
||||
|
%\titlespacing*{\subsection}{-2em}{*1}{*1} |
||||
|
%\titlespacing*{\subsubsection}{-1em}{*1}{*1} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
%%%%%%%% TITRE %%%%%%%%M |
||||
|
\renewcommand{\maketitle}{ |
||||
|
\begin{titlepage} % Suppresses displaying the page number on the title page and the subsequent page counts as page 1 |
||||
|
%------------------------------------------------ |
||||
|
% Grey title box |
||||
|
%------------------------------------------------ |
||||
|
\topskip0pt |
||||
|
\vspace*{5cm} |
||||
|
\colorbox{grey}{ |
||||
|
\parbox[t]{0.93\textwidth}{ % Outer full width box |
||||
|
\parbox[t]{0.91\textwidth}{ % Inner box for inner right text margin |
||||
|
\raggedleft % Right align the text |
||||
|
\fontsize{72pt}{80pt}\selectfont % Title font size, the first argument is the font size and the second is the line spacing, adjust depending on title length |
||||
|
\vspace{1cm} % Space between the start of the title and the top of the grey box |
||||
|
|
||||
|
\@title |
||||
|
|
||||
|
\vspace{1cm} % Space between the end of the title and the bottom of the grey box |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
\vfill % Space between the title box and author information |
||||
|
|
||||
|
%------------------------------------------------ |
||||
|
% Author name and information |
||||
|
%------------------------------------------------ |
||||
|
|
||||
|
\parbox[t]{0.93\textwidth}{ % Box to inset this section slightly |
||||
|
\raggedleft % Right align the text |
||||
|
\large % Increase the font size |
||||
|
{\Large \@author}\\[4pt] % Extra space after name |
||||
|
|
||||
|
\hfill\rule{0.2\linewidth}{1pt}\\% Horizontal line, first argument width, second thickness |
||||
|
\@date |
||||
|
} |
||||
|
|
||||
|
\end{titlepage} |
||||
|
|
||||
|
\emptyPage |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
%%%%%%%% FIN DU DOCUMENT %%%%%%%%% |
||||
|
|
||||
|
\newcommand{\roadMap}{ |
||||
|
\clearpage |
||||
|
\listoffigures |
||||
|
\clearpage |
||||
|
\listoftables |
||||
|
} |
||||
|
|
||||
|
% Fin du package |
||||
|
\endinput |
||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 34 KiB |
@ -1,33 +0,0 @@ |
|||||
class Graph: |
|
||||
"""Implémente un graphe non orienté.""" |
|
||||
|
|
||||
def __init__(self, nom): |
|
||||
"""Initialise un graphe vide. |
|
||||
|
|
||||
:param nom: Nom du graphe |
|
||||
""" |
|
||||
self.nom = nom |
|
||||
|
|
||||
|
|
||||
class Sommet: |
|
||||
"""Implémente un sommet de graphe.""" |
|
||||
|
|
||||
def __init__(self, pos): |
|
||||
"""Initialise un sommet. |
|
||||
|
|
||||
:param pos: couple donnant la position du point. |
|
||||
""" |
|
||||
self.pos = pos |
|
||||
|
|
||||
|
|
||||
class Arete: |
|
||||
"""Implémente une arête de graphe.""" |
|
||||
|
|
||||
def __init__(self, longueur, v_moyenne): |
|
||||
"""Initialise une arête. |
|
||||
|
|
||||
:param longueur: longueur de l'arête. |
|
||||
:param v_moyenne: vitesse moyenne sur l'arête. |
|
||||
""" |
|
||||
self.longueur = longueur |
|
||||
self.v_moyenne = v_moyenne |
|
||||
@ -0,0 +1,316 @@ |
|||||
|
import random |
||||
|
import triangulation |
||||
|
|
||||
|
|
||||
|
class Graphe: |
||||
|
"""Implémente un graphe non orienté.""" |
||||
|
|
||||
|
def __init__(self, nom): |
||||
|
"""Initialise un graphe vide. |
||||
|
|
||||
|
:param nom: Nom du graphe |
||||
|
""" |
||||
|
self.nom = nom |
||||
|
self.sommets = [] |
||||
|
self.aretes = [] |
||||
|
|
||||
|
def renomme(self, nom): |
||||
|
"""Renome le graphe |
||||
|
|
||||
|
:param nom: Nouveau nom du graphe. |
||||
|
""" |
||||
|
self.nom = nom |
||||
|
|
||||
|
def ajouteSommet(self, x, y): |
||||
|
"""Ajoute le sommet s au graphe. |
||||
|
|
||||
|
:param x: abcisse du sommet. |
||||
|
:param y: ordonnée du sommet. |
||||
|
|
||||
|
:return: Le sommet créé. |
||||
|
""" |
||||
|
s = Sommet((x, y), len(self.sommets)) |
||||
|
self.sommets.append(s) |
||||
|
return s |
||||
|
|
||||
|
def connecte(self, s1, s2, longueur, v_moyenne): |
||||
|
"""Connecte les sommets s1 et s2. |
||||
|
|
||||
|
:param s1: premier sommet. |
||||
|
:param s2: deuxième sommet. |
||||
|
:param longueur: longueur de l'arrête. |
||||
|
:param v_moyenne: vitesse moyenne sur l'arrête. |
||||
|
|
||||
|
:return: L'arête créée. |
||||
|
""" |
||||
|
a = Arete(s1, s2, longueur, v_moyenne) |
||||
|
self.aretes.append(a) |
||||
|
return a |
||||
|
|
||||
|
def n(self): |
||||
|
"""Retourne le nombre de sommets du graphe.""" |
||||
|
return len(self.sommets) |
||||
|
|
||||
|
def m(self): |
||||
|
"""Retourne le nombre d'arrêtes du graphe.""" |
||||
|
return len(self.aretes) |
||||
|
|
||||
|
def __str__(self): |
||||
|
return "V({nom})=[\n{noeuds}\n]\nE({nom})=[\n{aretes}\n]\n".format( |
||||
|
nom=self.nom, |
||||
|
aretes='\n'.join([str(v) for v in self.aretes]), |
||||
|
noeuds='\n'.join([str(n) for n in self.sommets]) |
||||
|
) |
||||
|
|
||||
|
def trace(self, dest): |
||||
|
"""Affiche le graphe sur la destination. |
||||
|
|
||||
|
:param dest: instance de Afficheur. |
||||
|
""" |
||||
|
for s in self.sommets: |
||||
|
dest.changeCouleur(s.couleur) |
||||
|
dest.tracePoint((s.x(), s.y())) |
||||
|
dest.traceTexte((s.x(), s.y()), 'v'+str(s.num)) |
||||
|
|
||||
|
for a in self.aretes: |
||||
|
dest.changeCouleur(a.couleur) |
||||
|
dest.traceLigne((a.s1.x(), a.s1.y()), (a.s2.x(), a.s2.y())) |
||||
|
|
||||
|
def ajouteRoute(self, v1, v2, vmax): |
||||
|
"""Ajoute une route de distance euclidienne entre v1 et v2. |
||||
|
|
||||
|
:param v1: Premier sommet. |
||||
|
:param v2: Deuxième sommet. |
||||
|
:param vmax: vitesse maximale sur la route. |
||||
|
|
||||
|
:return: Route créée. |
||||
|
""" |
||||
|
return self.connecte(v1, v2, v1.distance(v2), vmax) |
||||
|
|
||||
|
def ajouteNationale(self, v1, v2): |
||||
|
"""Ajoute une nationale au graphe. (rouge et vmax = 90km/h). |
||||
|
|
||||
|
:param v1: Premier sommet. |
||||
|
:param v2: Deuxième sommet. |
||||
|
|
||||
|
:return: route créée. |
||||
|
""" |
||||
|
a = self.ajouteRoute(v1, v2, 90) |
||||
|
a.couleur = (1., 0., 0.) |
||||
|
return a |
||||
|
|
||||
|
def ajouteDepartementale(self, v1, v2): |
||||
|
"""Ajoute une départementale au graphe. (jaune et vmax = 60km/h). |
||||
|
|
||||
|
:param v1: Premier sommet. |
||||
|
:param v2: Deuxième sommet. |
||||
|
|
||||
|
:return: route créée. |
||||
|
""" |
||||
|
a = self.ajouteRoute(v1, v2, 60) |
||||
|
a.couleur = (1., 1., 0.) |
||||
|
return a |
||||
|
|
||||
|
|
||||
|
class Sommet: |
||||
|
"""Implémente un sommet de graphe.""" |
||||
|
|
||||
|
def __init__(self, pos, num, couleur=(0., 0., 0.)): |
||||
|
"""Initialise un sommet. |
||||
|
|
||||
|
:param pos: couple donnant la position du point. |
||||
|
:param num: numéro du sommet. |
||||
|
:param couleur: couleur du sommet. |
||||
|
""" |
||||
|
self.pos = pos |
||||
|
self.num = num |
||||
|
self.couleur = couleur |
||||
|
|
||||
|
def __str__(self): |
||||
|
return "v{} (x = {} km y = {} km)".format( |
||||
|
str(self.num), |
||||
|
str(self.x()), |
||||
|
str(self.y()) |
||||
|
) |
||||
|
|
||||
|
def distance(self, v): |
||||
|
"""Calcule la distance entre deux points. |
||||
|
|
||||
|
:param v: Point de calcul de la distance. |
||||
|
""" |
||||
|
return ((self.x()-v.x())**2 + (self.y()-v.y())**2)**(1/2) |
||||
|
|
||||
|
def x(self): |
||||
|
"""Retourne l'abcisse de x.""" |
||||
|
return self.pos[0] |
||||
|
|
||||
|
def y(self): |
||||
|
"""Retourne l'ordonnée de y.""" |
||||
|
return self.pos[1] |
||||
|
|
||||
|
|
||||
|
class Arete: |
||||
|
"""Implémente une arête de graphe.""" |
||||
|
|
||||
|
def __init__(self, s1, s2, longueur, v_moyenne, couleur=(0., 0., 0.)): |
||||
|
"""Initialise une arête. |
||||
|
|
||||
|
:param s1: sommet 1. |
||||
|
:param s2: sommet 2. |
||||
|
:param longueur: longueur de l'arête. |
||||
|
:param v_moyenne: vitesse moyenne sur l'arête. |
||||
|
:param couleur: couleur de l'arête. |
||||
|
""" |
||||
|
self.s1 = s1 |
||||
|
self.s2 = s2 |
||||
|
self.longueur = longueur |
||||
|
self.v_moyenne = v_moyenne |
||||
|
self.couleur = couleur |
||||
|
|
||||
|
def voisin(self, s): |
||||
|
"""Retourne le sommet voisin de s dans l'arête. |
||||
|
|
||||
|
:param s: Un sommet de l'arête. |
||||
|
""" |
||||
|
if s == self.s1: |
||||
|
return self.s2 |
||||
|
else: |
||||
|
return self.s1 |
||||
|
|
||||
|
def __str__(self): |
||||
|
return " v{v1}, v{v2} (long. = {lon} km vlim. = {v} km/h)".format( |
||||
|
v1=str(self.s1.num), |
||||
|
v2=str(self.s2.num), |
||||
|
lon=str(self.longueur), |
||||
|
v=str(self.v_moyenne) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
def pointsAleatoires(n, L): |
||||
|
"""Crée un graphe de n points aléatoires non reliés dans le carré centré en |
||||
|
0 de largeure L. |
||||
|
|
||||
|
:param n: nombre de points. |
||||
|
:param L: Côté du carré. |
||||
|
""" |
||||
|
g = Graphe("Graphe aléatoire") |
||||
|
for _ in range(n): |
||||
|
x, y = random.uniform(-L/2, L/2), random.uniform(-L/2, L/2) |
||||
|
g.ajouteSommet(x, y) |
||||
|
return g |
||||
|
|
||||
|
|
||||
|
def test_gabriel(g, v1, v2): |
||||
|
"""Teste si on peut connecter deux sommets selon le critère de Gabriel. |
||||
|
|
||||
|
:param g: Le graphe. |
||||
|
:param v1: Premier sommet. |
||||
|
:param v2: Deuxième sommet. |
||||
|
""" |
||||
|
milieu = Sommet(((v1.x()+v2.x())/2, (v1.y()+v2.y())/2), -1) |
||||
|
rayon = v1.distance(v2)/2 |
||||
|
ajoute = True |
||||
|
for v3 in g.sommets: |
||||
|
if v3 in [v1, v2]: |
||||
|
continue |
||||
|
elif v3.distance(milieu) < rayon: |
||||
|
ajoute = False |
||||
|
break |
||||
|
return ajoute |
||||
|
|
||||
|
|
||||
|
def gabriel(g, ignore_gvr=False): |
||||
|
"""Crée le graphe de Gabriel associé à g avec des routes démartementales. |
||||
|
|
||||
|
:param g: Un graphe sans arrêtes. |
||||
|
:param ignore_gvr: booléen indiquant si on ne doit pas ajouter une arrête |
||||
|
quand gvr en ajoute une. |
||||
|
""" |
||||
|
for v1 in g.sommets: |
||||
|
for v2 in g.sommets: |
||||
|
if v2 == v1: |
||||
|
continue |
||||
|
if test_gabriel(g, v1, v2): |
||||
|
if (ignore_gvr and not test_gvr(g, v1, v2)) or not ignore_gvr: |
||||
|
g.ajouteDepartementale(v1, v2) |
||||
|
|
||||
|
|
||||
|
def test_gvr(g, v1, v2): |
||||
|
"""Teste si on peut connecter deux sommets selon le critère GVR. |
||||
|
|
||||
|
:param g: Le graphe. |
||||
|
:param v1: Premier sommet. |
||||
|
:param v2: Deuxième sommet. |
||||
|
""" |
||||
|
rayon = v1.distance(v2) |
||||
|
ajoute = True |
||||
|
for v3 in g.sommets: |
||||
|
if v3 in [v1, v2]: |
||||
|
continue |
||||
|
elif v3.distance(v1) < rayon and v3.distance(v2) < rayon: |
||||
|
ajoute = False |
||||
|
break |
||||
|
return ajoute |
||||
|
|
||||
|
|
||||
|
def gvr(g): |
||||
|
"""Crée le graphe GVR associé à g avec des routes nationales. |
||||
|
|
||||
|
:param g: Un graphe sans arrêtes. |
||||
|
""" |
||||
|
for v1 in g.sommets: |
||||
|
for v2 in g.sommets: |
||||
|
if v2 == v1: |
||||
|
continue |
||||
|
if test_gvr(g, v1, v2): |
||||
|
g.ajouteNationale(v1, v2) |
||||
|
|
||||
|
|
||||
|
def reseau(g): |
||||
|
"""Construit une carte routière avec comme nationales les routes obtenues |
||||
|
par la méthode GVR et départementales celles de Gabriel. |
||||
|
|
||||
|
:param g: Un raphe sans arêtes. |
||||
|
""" |
||||
|
gabriel(g, ignore_gvr=True) |
||||
|
gvr(g) |
||||
|
|
||||
|
|
||||
|
def delaunay(g): |
||||
|
"""Crée une triangulation de Delaunay à partir d ' un nuage de point""" |
||||
|
t = triangulation.Triangulation(g) |
||||
|
# Définit une fonction destinée à être appelée |
||||
|
# pour toute paire (s1,s2) de sommets |
||||
|
# qui forme une arête dans la triangulation de Delaunay. |
||||
|
# v3 et v4 sont les troisièmes sommets des deux triangles |
||||
|
# ayant (s1,s2) comme côté. |
||||
|
|
||||
|
def selectionneAretes(graphe, v1, v2, v3, v4): |
||||
|
# Fait de chaque arête de la triangulation |
||||
|
# une nationale |
||||
|
graphe.ajouteNationale(v1, v2) |
||||
|
# Construit le graphe de retour, égal à la triangulation de Delaunay |
||||
|
g = t.construitGrapheDeSortie(selectionneAretes) |
||||
|
g.renomme("Delaunay(" + str(g.n()) + ")") |
||||
|
return g |
||||
|
|
||||
|
|
||||
|
def reseauRapide(g): |
||||
|
"""Crée une triangulation de Delaunay à partir d ' un nuage de point""" |
||||
|
t = triangulation.Triangulation(g) |
||||
|
# Définit une fonction destinée à être appelée |
||||
|
# pour toute paire (s1,s2) de sommets |
||||
|
# qui forme une arête dans la triangulation de Delaunay. |
||||
|
# v3 et v4 sont les troisièmes sommets des deux triangles |
||||
|
# ayant (s1,s2) comme côté. |
||||
|
|
||||
|
def selectionneAretes(graphe, v1, v2, v3, v4): |
||||
|
if test_gabriel(graphe, v1, v2): |
||||
|
if test_gvr(graphe, v1, v2): |
||||
|
graphe.ajouteNationale(v1, v2) |
||||
|
else: |
||||
|
graphe.ajouteDepartementale(v1, v2) |
||||
|
# Construit le graphe de retour, égal à la triangulation de Delaunay |
||||
|
g = t.construitGrapheDeSortie(selectionneAretes) |
||||
|
g.renomme("Delaunay(" + str(g.n()) + ")") |
||||
|
return g |
||||
@ -0,0 +1,195 @@ |
|||||
|
# coding: utf-8 |
||||
|
|
||||
|
import sys |
||||
|
import numpy as np |
||||
|
import math |
||||
|
import copy |
||||
|
import PySide.QtCore as qtcore |
||||
|
import PySide.QtGui as qtgui |
||||
|
import traceback |
||||
|
|
||||
|
class Afficheur(qtgui.QWidget): |
||||
|
afficheurs = [] |
||||
|
size = (800, 600) |
||||
|
coord = np.array((50, 50)) |
||||
|
decalage = np.array((40,40)) |
||||
|
|
||||
|
def __init__(self, sujet, centre, ech): |
||||
|
super(Afficheur, self).__init__() |
||||
|
if(not "trace" in dir(sujet)): |
||||
|
raise Exception('Méthode "trace" non définie dans la classe ' + str(sujet.__class__)) |
||||
|
|
||||
|
app = qtgui.QApplication.instance() |
||||
|
if not app: |
||||
|
app = qtgui.QApplication(sys.argv) |
||||
|
desktop = app.desktop() |
||||
|
screen = desktop.screenGeometry(desktop.screenNumber(self)) |
||||
|
|
||||
|
self.rayon = 4 |
||||
|
self.ech = ech |
||||
|
self.centre = np.array(centre) |
||||
|
self.crayon = None |
||||
|
self.sujet = sujet |
||||
|
self.setStyleSheet("background-color: gray") |
||||
|
self.center = np.array(Afficheur.size) / 2. |
||||
|
self.setGeometry(Afficheur.coord[0] + screen.x(), Afficheur.coord[1] + screen.y(), Afficheur.size[0], Afficheur.size[1]) |
||||
|
Afficheur.coord += Afficheur.decalage |
||||
|
self.setWindowTitle("Afficheur") |
||||
|
self.show() |
||||
|
|
||||
|
def __pointVersPixel(self, p): |
||||
|
p = np.array(p) |
||||
|
pixel = (p - self.centre) * self.ech |
||||
|
pixel[1] = -pixel[1] |
||||
|
pixel += self.center |
||||
|
return qtcore.QPoint(pixel[0],pixel[1]) |
||||
|
|
||||
|
def __pixelVersPoint(self, pixel): |
||||
|
p = np.array((pixel.x(), pixel.y())) - self.center |
||||
|
p[1] = -p[1] |
||||
|
p = p / self.ech + self.centre |
||||
|
return p |
||||
|
|
||||
|
def __pixelVersVecteur(self, pixel1, pixel2): |
||||
|
assert isinstance(pixel1, qtcore.QPoint) |
||||
|
assert isinstance(pixel2, qtcore.QPoint) |
||||
|
v = np.array((pixel2.x(), pixel2.y())) - np.array((pixel1.x(), pixel1.y())) |
||||
|
v[1] = -v[1] |
||||
|
v = v / self.ech |
||||
|
return v |
||||
|
|
||||
|
def tracePoint(self, p): |
||||
|
assert self.crayon != None |
||||
|
assert isinstance(p, tuple) or isinstance(p, np.ndarray) |
||||
|
assert isinstance(p[0], float) |
||||
|
assert isinstance(p[1], float) |
||||
|
pixel = self.__pointVersPixel(p) |
||||
|
self.crayon.drawEllipse(pixel, self.rayon, self.rayon) |
||||
|
|
||||
|
def traceLigne(self, p1, p2): |
||||
|
assert self.crayon != None |
||||
|
assert isinstance(p1, tuple) or isinstance(p1, np.ndarray) |
||||
|
assert isinstance(p1[0], float) |
||||
|
assert isinstance(p1[1], float) |
||||
|
assert isinstance(p2, tuple) or isinstance(p2, np.ndarray) |
||||
|
assert isinstance(p2[0], float) |
||||
|
assert isinstance(p2[1], float) |
||||
|
pixel1 = self.__pointVersPixel(p1) |
||||
|
pixel2 = self.__pointVersPixel(p2) |
||||
|
self.crayon.drawLine(pixel1, pixel2) |
||||
|
|
||||
|
def changeCouleur(self, couleur): |
||||
|
assert self.crayon != None |
||||
|
assert isinstance(couleur, tuple) |
||||
|
assert isinstance(couleur[0], float) |
||||
|
assert isinstance(couleur[1], float) |
||||
|
assert isinstance(couleur[2], float) |
||||
|
c = qtgui.QColor(couleur[0]*255, couleur[1]*255, couleur[2]*255) |
||||
|
self.crayon.setPen(c) |
||||
|
self.crayon.setBrush(c) |
||||
|
|
||||
|
def traceTexte(self, p, texte): |
||||
|
assert isinstance(p, tuple) or isinstance(p, np.ndarray) |
||||
|
assert isinstance(p[0], float) |
||||
|
assert isinstance(p[1], float) |
||||
|
assert isinstance(texte, str) |
||||
|
pixel = self.__pointVersPixel(p) |
||||
|
pixel += qtcore.QPoint(10,-10) |
||||
|
self.crayon.drawText(pixel, texte) |
||||
|
|
||||
|
def renomme(self, titre): |
||||
|
# assert isinstance(titre, str) |
||||
|
# titre = unicode(titre, 'utf-8') |
||||
|
self.setWindowTitle(titre) |
||||
|
|
||||
|
def mousePressEvent(self, QMouseEvent): |
||||
|
pos = QMouseEvent.pos() |
||||
|
self.clic = pos |
||||
|
pos = self.__pixelVersPoint(pos) |
||||
|
self.centre = self.centre |
||||
|
|
||||
|
def mouseMoveEvent(self, QMouseEvent): |
||||
|
pos = QMouseEvent.pos() |
||||
|
self.centre -= self.__pixelVersVecteur(self.clic, pos) |
||||
|
self.clic = pos |
||||
|
self.update() |
||||
|
|
||||
|
def mouseReleaseEvent(self, QMouseEvent): |
||||
|
pos = QMouseEvent.pos() |
||||
|
self.centre -= self.__pixelVersVecteur(self.clic, pos) |
||||
|
self.clic = pos |
||||
|
self.update() |
||||
|
|
||||
|
def wheelEvent(self, event): |
||||
|
pos = event.pos() |
||||
|
C = self.__pixelVersPoint(pos) |
||||
|
k1 = self.ech |
||||
|
k2 = k1 * math.exp(0.001 * event.delta()) |
||||
|
self.centre = (self.centre * k1 + C * (k2 -k1)) / k2 |
||||
|
self.ech = k2 |
||||
|
self.update() |
||||
|
|
||||
|
def paintEvent(self, event): |
||||
|
if(self.crayon != None): |
||||
|
return |
||||
|
self.crayon = qtgui.QPainter(self) |
||||
|
self.trace() |
||||
|
self.crayon = None |
||||
|
|
||||
|
def trace(self): |
||||
|
self.crayon.setFont(qtgui.QFont('Decorative', 10)) |
||||
|
if(self.sujet != None): |
||||
|
try: |
||||
|
self.sujet.trace(self) |
||||
|
except AttributeError: |
||||
|
self.close() |
||||
|
qtgui.QApplication.quit() |
||||
|
raise Exception('Méthode "trace" non définie dans la classe ' + str(self.sujet.__class__)) |
||||
|
except BaseException: |
||||
|
traceback.print_exc() |
||||
|
self.close() |
||||
|
qtgui.QApplication.quit() |
||||
|
L = 100.; |
||||
|
x = 20; y = 20; |
||||
|
self.crayon.setPen('white') |
||||
|
msg = '{0:.2f} km'.format(L / self.ech) |
||||
|
l = self.crayon.fontMetrics().boundingRect(msg).width() |
||||
|
self.crayon.drawText(x + (L-l)/2, y-2, msg); |
||||
|
self.crayon.drawLine(x, y, x + L, y); |
||||
|
self.crayon.drawLine(x, y - L/20, x, y + L/10); |
||||
|
self.crayon.drawLine(x + L, y - L/20, x + L, y + L/10); |
||||
|
|
||||
|
|
||||
|
def sauvegarde(self): |
||||
|
filename = qtgui.QFileDialog.getSaveFileName(self, 'Fichier PDF') |
||||
|
if filename: |
||||
|
printer = qtgui.QPrinter(qtgui.QPrinter.HighResolution) |
||||
|
printer.setPageSize(qtgui.QPrinter.A4) |
||||
|
printer.setColorMode(qtgui.QPrinter.Color) |
||||
|
printer.setOutputFormat(qtgui.QPrinter.PdfFormat) |
||||
|
printer.setOutputFileName(filename) |
||||
|
|
||||
|
self.crayon = qtgui.QPainter(printer) |
||||
|
self.trace() |
||||
|
self.crayon = None |
||||
|
|
||||
|
def affiche(sujet, centre, ech, blocage = True): |
||||
|
'''Affiche dans une fenêtre l'objet sujet qui doit avoir une méthode trace''' |
||||
|
assert isinstance(centre, tuple) |
||||
|
assert isinstance(ech, float) |
||||
|
sujet = copy.deepcopy(sujet) |
||||
|
app = qtgui.QApplication.instance() |
||||
|
if not app: |
||||
|
app = qtgui.QApplication(sys.argv) |
||||
|
a = Afficheur(sujet, centre, ech) |
||||
|
Afficheur.afficheurs.append(a) |
||||
|
if(blocage): |
||||
|
bloque() |
||||
|
return a |
||||
|
|
||||
|
def bloque(): |
||||
|
app = qtgui.QApplication.instance() |
||||
|
if not app: |
||||
|
app = qtgui.QApplication(sys.argv) |
||||
|
app.exec_() |
||||
|
|
||||
@ -0,0 +1,109 @@ |
|||||
|
# coding: utf-8 |
||||
|
# La ligne précédente est indispensable pour accpeter les accents dans le fichier |
||||
|
|
||||
|
# Importe les modules qui seront nécessaires |
||||
|
import math # Fonctions mathématiques : math.cos, math.sin, math.pi, etc |
||||
|
import random # Générateurs de nombres aléatoires |
||||
|
import numpy # Calcul numérique sur des vecteurs, matrices, etc |
||||
|
|
||||
|
# Importe le fichier graphique.py qui |
||||
|
import graphique |
||||
|
|
||||
|
class Sommet: |
||||
|
'''Classe représentant un sommet d'un polygone''' |
||||
|
|
||||
|
def __init__(self, theta, r): |
||||
|
'''Constructeur de la classe Sommet : (theta,r) sont les coordonnées polaires du sommet self''' |
||||
|
self.deplace(theta, r) |
||||
|
|
||||
|
def deplace(self, theta, r): |
||||
|
'''Déplace le sommet self: (theta,r) sont les nouvelles coordonnées polaires''' |
||||
|
|
||||
|
# Sauvegarde les coordonnées polaires dans des attributs de l'objet self |
||||
|
self.theta = theta |
||||
|
self.r = r |
||||
|
|
||||
|
# Calcule les coordonnées cartésiennes (pour l'affichage) |
||||
|
# On utilise la bibliothèque de calcul numérique numpy. |
||||
|
self.pos = numpy.array([math.cos(theta), math.sin(theta)]) * r |
||||
|
|
||||
|
def __str__(self): |
||||
|
'''Fonction spéciale de conversion en chaîne de caractères''' |
||||
|
|
||||
|
chaine = '({:0.2f},{:0.2f})'.format(self.pos[0], self.pos[1]) |
||||
|
return chaine |
||||
|
|
||||
|
class Polygone: |
||||
|
''' Classe représentant un polygone du plan''' |
||||
|
|
||||
|
def __init__(self, n, R): |
||||
|
'''Constructeur d'un objet Polygone : crée un polygone régulier |
||||
|
à n sommets placés sur le cercle de rayon R centré sur l'origine''' |
||||
|
|
||||
|
# Vérifie que les arguments ont le type attendu |
||||
|
assert isinstance(n, int) |
||||
|
assert isinstance(R, float) |
||||
|
|
||||
|
# Crée comme attribut de self une liste pour accueillir les sommets |
||||
|
self.sommets = [] |
||||
|
|
||||
|
# Crée un attribut pour stocker le nom du polygone |
||||
|
self.nom = str(n) + "-polygone régulier" |
||||
|
|
||||
|
# Remplie la liste des n sommets |
||||
|
alpha = 2. * math.pi / n |
||||
|
angle = math.pi / 2. |
||||
|
for _ in range(n): |
||||
|
self.sommets.append(Sommet(angle, R)) |
||||
|
angle += alpha |
||||
|
|
||||
|
def __str__(self): |
||||
|
'''Fonction spéciale de conversion en chaîne de caractères''' |
||||
|
chaine = self.nom + ' = (' |
||||
|
if(len(self.sommets) > 0): |
||||
|
chaine += str(self.sommets[0]) |
||||
|
for s in self.sommets[1:]: |
||||
|
chaine += ', ' + str(s) |
||||
|
chaine += ')' |
||||
|
return chaine |
||||
|
|
||||
|
def secoue(self, amplitudeAngulaire, amplitudeRadiale): |
||||
|
'''Fonction qui déplace aléatoirement chaque sommet selon une amplitude angulaire et radiale réglable''' |
||||
|
|
||||
|
# Modifie les coordonnées de chaque sommet à l'aide de la méthode deplace |
||||
|
for s in self.sommets: |
||||
|
s.deplace( |
||||
|
s.theta + (random.random() * 2. - 1.) * amplitudeAngulaire, |
||||
|
s.r * (1. + (random.random() * 2. - 1.) * amplitudeRadiale) |
||||
|
) |
||||
|
|
||||
|
# Change le nom du polygone |
||||
|
self.nom = str(len(self.sommets)) + "-polygone secoué" |
||||
|
|
||||
|
|
||||
|
def trace(self, afficheur): |
||||
|
'''Fonction de dessin''' |
||||
|
|
||||
|
assert isinstance(afficheur, graphique.Afficheur) |
||||
|
|
||||
|
afficheur.renomme(self.nom) |
||||
|
precedent = self.sommets[-1] |
||||
|
afficheur.changeCouleur((0.,0.,0.)) |
||||
|
|
||||
|
for suivant in self.sommets: |
||||
|
afficheur.traceLigne(precedent.pos, suivant.pos) |
||||
|
precedent = suivant |
||||
|
|
||||
|
afficheur.changeCouleur((1.,0.,0.)) |
||||
|
for sommet in self.sommets: |
||||
|
afficheur.tracePoint(sommet.pos) |
||||
|
|
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
triangle = Polygone(3, 10.) |
||||
|
print(triangle) |
||||
|
graphique.affiche(triangle, (0., 0.), 10., blocage = False) |
||||
|
|
||||
|
heptagone = Polygone(7, 10.) |
||||
|
heptagone.secoue(math.pi / 5, 0.1) |
||||
|
graphique.affiche(heptagone, (0., 0.), 10.) |
||||
@ -0,0 +1,136 @@ |
|||||
|
# coding: utf-8 |
||||
|
|
||||
|
class Tas: |
||||
|
class Element: |
||||
|
def __init__(self, valeur, priorite, index): |
||||
|
self.valeur = valeur |
||||
|
self.priorite = priorite |
||||
|
self.index = index |
||||
|
|
||||
|
def __str__(self): |
||||
|
return str(self.valeur) |
||||
|
|
||||
|
def __init__(self, fonctionPriorite): |
||||
|
self.L = [] |
||||
|
self.fonctionPriorite = fonctionPriorite |
||||
|
|
||||
|
def __str__(self): |
||||
|
s = "[" |
||||
|
for elt in self.L: |
||||
|
s += " " + str(elt) |
||||
|
s += "]" |
||||
|
return s |
||||
|
|
||||
|
def __parent(self, elt): |
||||
|
if(elt.index == 0): |
||||
|
return None |
||||
|
else: |
||||
|
return self.L[(elt.index-1) // 2] |
||||
|
|
||||
|
def __fils_gauche(self, elt): |
||||
|
i = 2 * elt.index + 1 |
||||
|
if(i < len(self.L)): |
||||
|
return self.L[i] |
||||
|
else: |
||||
|
return None |
||||
|
|
||||
|
def __fils_droit(self, elt): |
||||
|
i = 2 * elt.index + 2 |
||||
|
if(i < len(self.L)): |
||||
|
return self.L[i] |
||||
|
else: |
||||
|
return None |
||||
|
|
||||
|
def __deplace(self, elt, index): |
||||
|
assert isinstance(elt, Tas.Element) |
||||
|
ancien = elt.index |
||||
|
self.L[index] = elt |
||||
|
elt.index = index |
||||
|
return ancien |
||||
|
|
||||
|
def __promeut(self, elt): |
||||
|
while(True): |
||||
|
parent = self.__parent(elt) |
||||
|
if(parent == None): |
||||
|
break |
||||
|
if(parent.priorite >= elt.priorite): |
||||
|
break |
||||
|
elt.index = self.__deplace(parent, elt.index) |
||||
|
self.__deplace(elt, elt.index) |
||||
|
|
||||
|
def actualise(self, elt): |
||||
|
assert isinstance(elt, Tas.Element) |
||||
|
elt.priorite = self.fonctionPriorite(elt.valeur) |
||||
|
self.__promeut(elt) |
||||
|
|
||||
|
def ajoute(self, valeur): |
||||
|
elt = Tas.Element(valeur, self.fonctionPriorite(valeur), len(self.L)) |
||||
|
self.L.append(elt) |
||||
|
self.__promeut(elt) |
||||
|
return elt |
||||
|
|
||||
|
def empty(self): |
||||
|
return len(self.L) == 0 |
||||
|
|
||||
|
def pop(self): |
||||
|
n = len(self.L) |
||||
|
if(n == 0): |
||||
|
return None |
||||
|
|
||||
|
tete = self.L[0] |
||||
|
elt = self.L[n - 1] |
||||
|
elt.index = 0 |
||||
|
|
||||
|
while True: |
||||
|
filsGauche = self.__fils_gauche(elt) |
||||
|
filsDroit = self.__fils_droit(elt) |
||||
|
plusPrioritaire = elt |
||||
|
if(filsGauche != None and filsGauche.priorite > plusPrioritaire.priorite): |
||||
|
plusPrioritaire = filsGauche |
||||
|
if(filsDroit != None and filsDroit.priorite > plusPrioritaire.priorite): |
||||
|
plusPrioritaire = filsDroit |
||||
|
elt.index = self.__deplace(plusPrioritaire, elt.index) |
||||
|
if(plusPrioritaire is elt): |
||||
|
break |
||||
|
self.L.pop() |
||||
|
return tete.valeur |
||||
|
|
||||
|
######################################### |
||||
|
# Exemple d'utilisatio de la classe Tas # |
||||
|
# Tri de tâches par ordre chronologique # |
||||
|
######################################### |
||||
|
|
||||
|
class Tache: |
||||
|
'''Tache devant être effectuée avant une date limite''' |
||||
|
def __init__(self, jour, nom): |
||||
|
self.jour = jour |
||||
|
self.nom = nom |
||||
|
# Cet attribut servira à accueillir la clé du tas |
||||
|
self.cle = None |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.nom + " ({})".format(self.jour) |
||||
|
|
||||
|
if __name__ == "__main__": |
||||
|
|
||||
|
# Le niveau de priorité d'un événement x est -x.jour : on trie donc les événements par ordre chronologique |
||||
|
def calculePriorite(tache): |
||||
|
return -tache.jour |
||||
|
|
||||
|
# On crée un tas dont les éléments sont des événements triés par ordre chronologique |
||||
|
T = Tas(calculePriorite) |
||||
|
|
||||
|
# Ajoute des événements au tas |
||||
|
evts = [ Tache(5, "T1"), Tache(10, "T2"), Tache(5, "T3"), Tache(3, "T4")] |
||||
|
for evt in evts: |
||||
|
evt.cle = T.ajoute(evt) |
||||
|
|
||||
|
# Supposons que la tache 2 devienne soudain assez urgente |
||||
|
evts[1].jour = 4 |
||||
|
T.actualise(evts[1].cle) |
||||
|
|
||||
|
# Retirons dans l'ordre chronologie les éléments du tas |
||||
|
while(not T.empty()): |
||||
|
print(T.pop()) |
||||
|
|
||||
|
|
||||
@ -0,0 +1,172 @@ |
|||||
|
import graphe |
||||
|
import graphique |
||||
|
import copy |
||||
|
import numpy as np |
||||
|
import matplotlib.pyplot as pl |
||||
|
import time |
||||
|
|
||||
|
|
||||
|
def creerGrapheFigure1(): |
||||
|
""" Crée le graphe de la figure 1 """ |
||||
|
g = graphe.Graphe("Graphe de la figure 1") |
||||
|
s1 = g.ajouteSommet(1.0, 1.0) |
||||
|
s2 = g.ajouteSommet(2.0, 3.5) |
||||
|
s3 = g.ajouteSommet(2.5, 2.5) |
||||
|
s4 = g.ajouteSommet(5.0, 2.0) |
||||
|
s1.couleur = (1., 1., 0.) |
||||
|
s2.couleur = (0., 0., 1.) |
||||
|
s3.couleur = (1., 0., 0.) |
||||
|
s4.couleur = (1., 1., 0.) |
||||
|
a = g.connecte(s1, s2, 4.0, 90.) |
||||
|
a.couleur = (1., 1., 0.) |
||||
|
g.connecte(s1, s4, 5.2, 124.) |
||||
|
g.connecte(s2, s3, 2.0, 54.) |
||||
|
g.connecte(s2, s4, 5.0, 90.) |
||||
|
return g |
||||
|
|
||||
|
|
||||
|
def testQuestion1_2(): |
||||
|
"""' Teste que la création d ' un graphe ne plante pas |
||||
|
print ”Question 1.2 :""" |
||||
|
creerGrapheFigure1() |
||||
|
print("Ok. Pas de plantage") |
||||
|
|
||||
|
|
||||
|
def testQuestion1_3(): |
||||
|
""" Teste l ' affichage d ' un graphe dans la console""" |
||||
|
print("Question 1.3 :") |
||||
|
g = creerGrapheFigure1() |
||||
|
print(g) |
||||
|
|
||||
|
|
||||
|
def testQuestion1_4(): |
||||
|
""" Teste du dessin d'un graphe.""" |
||||
|
print("Question 1.4:") |
||||
|
graphique.affiche(creerGrapheFigure1(), (3., 2.), 100.) |
||||
|
|
||||
|
|
||||
|
def testQuestion2_2(): |
||||
|
"""Teste de génération aléatoire de graphe.""" |
||||
|
print("Question 2.2:") |
||||
|
graphique.affiche(graphe.pointsAleatoires(5, 30), (0, 0), 10.) |
||||
|
|
||||
|
|
||||
|
def testQuestion2_4(): |
||||
|
"""Teste de gabriel et gvr.""" |
||||
|
print("Question 2.4") |
||||
|
g = graphe.pointsAleatoires(30, 30) |
||||
|
g.renomme("Gabriel") |
||||
|
g1 = copy.deepcopy(g) |
||||
|
g1.renomme("GVR") |
||||
|
graphe.gabriel(g) |
||||
|
graphe.gvr(g1) |
||||
|
graphique.affiche(g, (0, 0), 10.) |
||||
|
graphique.affiche(g1, (0, 0), 10.) |
||||
|
|
||||
|
|
||||
|
def testQuestion2_5(): |
||||
|
"""Teste de la création de réseau.""" |
||||
|
g = graphe.pointsAleatoires(30, 30) |
||||
|
graphe.reseau(g) |
||||
|
graphique.affiche(g, (0, 0), 10.) |
||||
|
|
||||
|
|
||||
|
def chronometre(fonctionTest, fonctionPreparation, parametres): |
||||
|
''' Mesure le temps d ' exécution fonctionTest pour différentes valeurs d ' |
||||
|
un paramètres ''' |
||||
|
temps = [] |
||||
|
# Pour chaque valeur de paramètre |
||||
|
for p in parametres: |
||||
|
# Génère les entrées du test pour la valeur p |
||||
|
entrees = fonctionPreparation(p) |
||||
|
# Lance le test pour ces entrées |
||||
|
print("t({}) = ".format(p), end="", flush=True) |
||||
|
debut = time.time() |
||||
|
fonctionTest(entrees) |
||||
|
fin = time.time() |
||||
|
# Mesure le temps d ' exécution |
||||
|
t = (fin - debut) |
||||
|
print("{:.2f} s".format(t)) |
||||
|
temps.append(t) |
||||
|
return temps |
||||
|
|
||||
|
def testQuestion2_6(): |
||||
|
"""Mesure la performance de graphe.reseau""" |
||||
|
prepare = lambda p : graphe.pointsAleatoires(p, 10) |
||||
|
valeurs_n = np.arange(1, 200) |
||||
|
temps = chronometre(graphe.reseau, prepare, valeurs_n) |
||||
|
pl.close('all') |
||||
|
pl.title("Mesure du temps d'exécution de `reseau`.") |
||||
|
pl.plot(valeurs_n, temps) |
||||
|
pl.xlabel("n") |
||||
|
pl.ylabel("temps") |
||||
|
pl.show() |
||||
|
pl.title("Mesure du temps d'exécution de `reseau`.") |
||||
|
pl.loglog(valeurs_n, temps, label='temps de calcul') |
||||
|
pl.loglog(valeurs_n, (lambda x : x**3)(valeurs_n), label='$x\mapsto x^3$') |
||||
|
pl.legend(loc='best') |
||||
|
pl.xlabel("n") |
||||
|
pl.ylabel("temps") |
||||
|
pl.show() |
||||
|
|
||||
|
def testQuestion2_7(): |
||||
|
"""Compare la création de graphe de gabriel et ed delaunay.""" |
||||
|
prepare = lambda p : graphe.pointsAleatoires(p, 10) |
||||
|
valeurs_n = np.arange(1, 200) |
||||
|
temps1 = chronometre(graphe.gabriel, prepare, valeurs_n) |
||||
|
temps2 = chronometre(graphe.delaunay, prepare, valeurs_n) |
||||
|
pl.close('all') |
||||
|
pl.title("Comparaison du temps pour `delaunay` et `gabriel`") |
||||
|
pl.plot(valeurs_n, temps1, label='gabriel') |
||||
|
pl.plot(valeurs_n, temps2, label='delaunay') |
||||
|
pl.legend(loc='best') |
||||
|
pl.xlabel('n') |
||||
|
pl.ylabel('temps') |
||||
|
pl.show() |
||||
|
|
||||
|
def testQuestion2_8(): |
||||
|
"""Compare le reseau naif et non naif.""" |
||||
|
g = graphe.pointsAleatoires(30, 30) |
||||
|
g1 = copy.deepcopy(g) |
||||
|
g.renomme("Naïf") |
||||
|
g1.renomme("Non naïf") |
||||
|
|
||||
|
graphe.reseau(g) |
||||
|
graphe.reseauRapide(g1) |
||||
|
graphique.affiche(g, (0, 0), 10.) |
||||
|
graphique.affiche(g1, (0, 0), 10.) |
||||
|
|
||||
|
def testQuestion2_9(): |
||||
|
"""Compare le temps de création des deux méthodes de création de réseau""" |
||||
|
prepare = lambda p : graphe.pointsAleatoires(p, 10) |
||||
|
valeurs_n = list(map(lambda x: int(x), np.logspace(1, 3, 30))) |
||||
|
temps1 = chronometre(graphe.reseau, prepare, valeurs_n) |
||||
|
temps2 = chronometre(graphe.reseauRapide, prepare, valeurs_n) |
||||
|
pl.close('all') |
||||
|
pl.title("Comparaison du temps d'exécution de `reseau` et `reseauRapide`.") |
||||
|
pl.plot(valeurs_n, temps1, label='reseau') |
||||
|
pl.plot(valeurs_n, temps2, label='reseauRapide') |
||||
|
pl.legend(loc='best') |
||||
|
pl.xlabel("n") |
||||
|
pl.ylabel("temps") |
||||
|
pl.show() |
||||
|
pl.title("Comparaison du temps d'exécution de `reseau` et `reseauRapide`.") |
||||
|
pl.loglog(valeurs_n, temps1, label='reseau') |
||||
|
pl.loglog(valeurs_n, temps2, label='reseauRapide') |
||||
|
pl.legend(loc='best') |
||||
|
pl.xlabel("n") |
||||
|
pl.ylabel("temps") |
||||
|
pl.show() |
||||
|
|
||||
|
|
||||
|
|
||||
|
# testQuestion1_2() |
||||
|
# testQuestion1_3() |
||||
|
# testQuestion1_4() |
||||
|
# testQuestion2_2() |
||||
|
# testQuestion2_4() |
||||
|
# testQuestion2_5() |
||||
|
# testQuestion2_6() |
||||
|
# testQuestion2_7() |
||||
|
# testQuestion2_8() |
||||
|
testQuestion2_9() |
||||
@ -0,0 +1,299 @@ |
|||||
|
# coding: utf-8 |
||||
|
|
||||
|
import sys |
||||
|
import math |
||||
|
|
||||
|
|
||||
|
def distanceAuCarre(v1, v2): |
||||
|
dx = (v1.x() - v2.x()) |
||||
|
dy = (v1.y() - v2.y()) |
||||
|
return dx**2 + dy**2 |
||||
|
|
||||
|
|
||||
|
def conditionDeDelaunay(A, B, C, D): |
||||
|
dab2 = distanceAuCarre(A, B) |
||||
|
dad2 = distanceAuCarre(A, D) |
||||
|
dbc2 = distanceAuCarre(B, C) |
||||
|
dbd2 = distanceAuCarre(B, D) |
||||
|
dcd2 = distanceAuCarre(C, D) |
||||
|
cosa = (dab2 + dad2 - dbd2) / (2 * math.sqrt(dab2) * math.sqrt(dad2)) |
||||
|
cosc = (dbc2 + dcd2 - dbd2) / (2 * math.sqrt(dbc2) * math.sqrt(dcd2)) |
||||
|
sina2 = 1. - cosa * cosa |
||||
|
if(sina2 > 0.): |
||||
|
sina = math.sqrt(sina2) |
||||
|
else: |
||||
|
sina = 0. |
||||
|
sinc2 = 1. - cosc * cosc |
||||
|
if(sinc2 > 0.): |
||||
|
sinc = math.sqrt(sinc2) |
||||
|
else: |
||||
|
sinc = 0. |
||||
|
return sina * cosc + cosa * sinc >= 0 |
||||
|
|
||||
|
|
||||
|
class Triangulation: |
||||
|
|
||||
|
class QuadEdge: |
||||
|
'''Classe définissant un quad-edge : une arête connectée à deux faces et deux sommets''' |
||||
|
|
||||
|
def __init__(self, f1, f2, v1, v2): |
||||
|
self.f1 = f1 |
||||
|
self.f2 = f2 |
||||
|
self.v1 = v1 |
||||
|
self.v2 = v2 |
||||
|
|
||||
|
def __eq__(self, e): |
||||
|
'''Méthode qui teste si deux quad-edges ont même extrémités''' |
||||
|
if((self.v1 == e.v1) and (self.v2 == e.v2)): |
||||
|
return True |
||||
|
elif((self.v1 == e.v2) and (self.v2 == e.v1)): |
||||
|
return True |
||||
|
else: |
||||
|
return False |
||||
|
|
||||
|
def __str__(self): |
||||
|
return str(self.v1) + " - " + str(self.v2) |
||||
|
|
||||
|
def remplaceFace(self, ancienneFace, nouvelleFace): |
||||
|
'''Méthode qui remplace une face adjacente au quad-edge par une autre''' |
||||
|
if(self.f1 == ancienneFace): |
||||
|
self.f1 = nouvelleFace |
||||
|
else: |
||||
|
self.f2 = nouvelleFace |
||||
|
|
||||
|
def lanceAlgorithme(self): |
||||
|
# Construit la triangulation initiale. Complexité en O(n log(n)) |
||||
|
self.construitTriangulationInitiale() |
||||
|
|
||||
|
# Bascule les arêtes de la triangulation jusqu'à obtenir la triangulation de Delaunay |
||||
|
self.basculeAretes() |
||||
|
|
||||
|
# Efface les sommets à l'infini |
||||
|
for _ in range(3): |
||||
|
self.graphe.sommets.pop() |
||||
|
|
||||
|
def __init__(self, g): |
||||
|
'''Constructeur de la classe triangulation qui prend en entrée un nuage de points |
||||
|
et crée une triangulation de Delaunay''' |
||||
|
self.racine = None |
||||
|
self.quadEdges = [] |
||||
|
self.graphe = g |
||||
|
self.lanceAlgorithme() |
||||
|
|
||||
|
class Triangle: |
||||
|
def __init__(self, v1, v2, v3): |
||||
|
self.v1 = v1 |
||||
|
self.v2 = v2 |
||||
|
self.v3 = v3 |
||||
|
self.t12 = None |
||||
|
self.t13 = None |
||||
|
self.t23 = None |
||||
|
self.e12 = None |
||||
|
self.e13 = None |
||||
|
self.e23 = None |
||||
|
|
||||
|
def contient(self, v): |
||||
|
''' Méthode qui teste si un sommet est à l'intérieur d'un triangle''' |
||||
|
v1 = self.v1 |
||||
|
v2 = self.v2 |
||||
|
v3 = self.v3 |
||||
|
det = (v1.x() - v3.x()) * (v2.y() - v3.y()) - \ |
||||
|
(v1.y() - v3.y()) * (v2.x() - v3.x()) |
||||
|
c1 = ((v2.y() - v3.y()) * (v.x() - v3.x()) + |
||||
|
(v3.x() - v2.x()) * (v.y() - v3.y())) * det |
||||
|
c2 = ((v3.y() - v1.y()) * (v.x() - v3.x()) + |
||||
|
(v1.x() - v3.x()) * (v.y() - v3.y())) * det |
||||
|
return (c1 > 0) and (c2 > 0) and (c1 + c2 < det * det) |
||||
|
|
||||
|
def trouve(self, v): |
||||
|
'''Méthode récursive qui renvoie le triangle d'une triangulation qui contient un sommet. |
||||
|
Renvoie le triangle contenant v, None si v n'est pas dans la triangulation''' |
||||
|
|
||||
|
t12 = self.t12 |
||||
|
t13 = self.t13 |
||||
|
t23 = self.t23 |
||||
|
if(t12 == None): |
||||
|
return self |
||||
|
else: |
||||
|
if(t12.contient(v)): |
||||
|
return t12.trouve(v) |
||||
|
elif(t13.contient(v)): |
||||
|
return t13.trouve(v) |
||||
|
elif(t23.contient(v)): |
||||
|
return t23.trouve(v) |
||||
|
else: |
||||
|
return None |
||||
|
|
||||
|
def aPourSommet(self, v): |
||||
|
'''Méthode qui teste si un sommet est un sommet d'un triangle |
||||
|
Renvoie vrai si v est un sommet du triangle''' |
||||
|
return self.v1 == v or self.v2 == v or self.v3 == v |
||||
|
|
||||
|
def troisiemeSommet(self, a, b): |
||||
|
''' Renvoie le troisième sommet d'un triangle à partir des deux autres''' |
||||
|
|
||||
|
if(self.v1 != a and self.v1 != b): |
||||
|
return self.v1 |
||||
|
elif(self.v2 != a and self.v2 != b): |
||||
|
return self.v2 |
||||
|
else: |
||||
|
return self.v3 |
||||
|
|
||||
|
def remplaceSommet(self, ancienSommet, nouveauSommet): |
||||
|
''' Méthode qui substitue un sommet par un autre dans un triangle ''' |
||||
|
if(self.v1 == ancienSommet): |
||||
|
self.v1 = nouveauSommet |
||||
|
elif(self.v2 == ancienSommet): |
||||
|
self.v2 = nouveauSommet |
||||
|
elif(self.v3 == ancienSommet): |
||||
|
self.v3 = nouveauSommet |
||||
|
else: |
||||
|
raise Exception("Bad vertex" + ancienSommet) |
||||
|
|
||||
|
def retrouveArete(self, v1, v2): |
||||
|
'''Méthode qui renvoie le quad-edge d'un triangle ayant deux sommets pour extrêmités''' |
||||
|
e = Triangulation.QuadEdge(None, None, v1, v2) |
||||
|
if(self.e12 == e): |
||||
|
return self.e12 |
||||
|
elif(self.e13 == e): |
||||
|
return self.e13 |
||||
|
elif(self.e23 == e): |
||||
|
return self.e23 |
||||
|
else: |
||||
|
raise Exception("getEdge") |
||||
|
|
||||
|
def remplaceArete(self, ancienneArete, nouvelleArete): |
||||
|
'''Méthode qui substitue le quad-edge d'un triangle par un autre''' |
||||
|
if(self.e12 == ancienneArete): |
||||
|
self.e12 = nouvelleArete |
||||
|
elif(self.e13 == ancienneArete): |
||||
|
self.e13 = nouvelleArete |
||||
|
elif(self.e23 == ancienneArete): |
||||
|
self.e23 = nouvelleArete |
||||
|
else: |
||||
|
raise Exception("changeEdge") |
||||
|
|
||||
|
def construitTriangleInitial(self): |
||||
|
'''Méthode qui construit une triangulation initiale qui contient tous les sommets''' |
||||
|
xmin = sys.float_info.max |
||||
|
xmax = sys.float_info.min |
||||
|
ymin = sys.float_info.max |
||||
|
ymax = sys.float_info.min |
||||
|
|
||||
|
for v in self.graphe.sommets: |
||||
|
if(v.x() > xmax): |
||||
|
xmax = v.x() |
||||
|
if(v.x() < xmin): |
||||
|
xmin = v.x() |
||||
|
if(v.y() > ymax): |
||||
|
ymax = v.y() |
||||
|
if(v.y() < ymin): |
||||
|
ymin = v.y() |
||||
|
|
||||
|
largeur = xmax - xmin |
||||
|
hauteur = ymax - ymin |
||||
|
margex = 0.1 * largeur |
||||
|
margey = 0.1 * hauteur |
||||
|
|
||||
|
v1 = self.graphe.ajouteSommet( |
||||
|
xmin - largeur / 2 - margex, ymin - margey) |
||||
|
v2 = self.graphe.ajouteSommet( |
||||
|
xmax + largeur / 2 + margex, ymin - margey) |
||||
|
v3 = self.graphe.ajouteSommet( |
||||
|
(xmin + xmax) / 2, ymax + hauteur + margey) |
||||
|
|
||||
|
self.racine = Triangulation.Triangle(v1, v2, v3) |
||||
|
|
||||
|
e12 = Triangulation.QuadEdge(None, self.racine, v1, v2) |
||||
|
e13 = Triangulation.QuadEdge(None, self.racine, v1, v3) |
||||
|
e23 = Triangulation.QuadEdge(None, self.racine, v2, v3) |
||||
|
self.racine.e12 = e12 |
||||
|
self.racine.e13 = e13 |
||||
|
self.racine.e23 = e23 |
||||
|
|
||||
|
def supprimeAretes(self): |
||||
|
for s in self.graphe.sommets: |
||||
|
s.aretes.clear() |
||||
|
|
||||
|
def construitTriangulationInitiale(self): |
||||
|
self.quadEdges = [] |
||||
|
self.construitTriangleInitial() |
||||
|
|
||||
|
for v in self.graphe.sommets: |
||||
|
t = self.racine.trouve(v) |
||||
|
if(t != None): |
||||
|
t.t12 = Triangulation.Triangle(t.v1, t.v2, v) |
||||
|
t.t13 = Triangulation.Triangle(t.v1, t.v3, v) |
||||
|
t.t23 = Triangulation.Triangle(t.v2, t.v3, v) |
||||
|
|
||||
|
e1v = Triangulation.QuadEdge(t.t12, t.t13, t.v1, v) |
||||
|
e2v = Triangulation.QuadEdge(t.t12, t.t23, t.v2, v) |
||||
|
e3v = Triangulation.QuadEdge(t.t13, t.t23, t.v3, v) |
||||
|
self.quadEdges.append(e1v) |
||||
|
self.quadEdges.append(e2v) |
||||
|
self.quadEdges.append(e3v) |
||||
|
|
||||
|
t.t12.e12 = t.e12 |
||||
|
t.e12.remplaceFace(t, t.t12) |
||||
|
t.t12.e13 = e1v |
||||
|
t.t12.e23 = e2v |
||||
|
|
||||
|
t.t13.e12 = t.e13 |
||||
|
t.e13.remplaceFace(t, t.t13) |
||||
|
t.t13.e13 = e1v |
||||
|
t.t13.e23 = e3v |
||||
|
|
||||
|
t.t23.e12 = t.e23 |
||||
|
t.e23.remplaceFace(t, t.t23) |
||||
|
t.t23.e13 = e2v |
||||
|
t.t23.e23 = e3v |
||||
|
|
||||
|
def basculeAretes(self): |
||||
|
pile = [] |
||||
|
for qe in self.quadEdges: |
||||
|
pile.append(qe) |
||||
|
|
||||
|
while(len(pile) > 0): |
||||
|
e = pile.pop() |
||||
|
|
||||
|
f1 = e.f1 |
||||
|
f2 = e.f2 |
||||
|
if(f1 != None and f2 != None): |
||||
|
v1 = e.v1 |
||||
|
v2 = e.v2 |
||||
|
|
||||
|
v3 = f1.troisiemeSommet(v1, v2) |
||||
|
v4 = f2.troisiemeSommet(v1, v2) |
||||
|
|
||||
|
if(not conditionDeDelaunay(v3, v1, v4, v2)): |
||||
|
v1v3 = f1.retrouveArete(v1, v3) |
||||
|
v2v3 = f1.retrouveArete(v2, v3) |
||||
|
v1v4 = f2.retrouveArete(v1, v4) |
||||
|
v2v4 = f2.retrouveArete(v2, v4) |
||||
|
f1.remplaceArete(v2v3, v1v4) |
||||
|
f2.remplaceArete(v1v4, v2v3) |
||||
|
v2v3.remplaceFace(f1, f2) |
||||
|
v1v4.remplaceFace(f2, f1) |
||||
|
f1.remplaceSommet(v2, v4) |
||||
|
f2.remplaceSommet(v1, v3) |
||||
|
e.v1 = v3 |
||||
|
e.v2 = v4 |
||||
|
pile.append(v1v3) |
||||
|
pile.append(v2v3) |
||||
|
pile.append(v1v4) |
||||
|
pile.append(v2v4) |
||||
|
|
||||
|
def construitGrapheDeSortie(self, selectionneArete): |
||||
|
'''Méthode qui construit la triangulation de Delaunay à partir du nuage de points passé au constructeur''' |
||||
|
|
||||
|
# Sélectionne les arêtes |
||||
|
graphe = self.graphe |
||||
|
racine = self.racine |
||||
|
for qe in self.quadEdges: |
||||
|
v1 = qe.v1 |
||||
|
v2 = qe.v2 |
||||
|
if(not (racine.aPourSommet(v1) or racine.aPourSommet(v2))): |
||||
|
v3 = qe.f1.troisiemeSommet(v1, v2) |
||||
|
v4 = qe.f2.troisiemeSommet(v1, v2) |
||||
|
selectionneArete(graphe, v1, v2, v3, v4) |
||||
|
return self.graphe |
||||
Loading…
Reference in new issue