Séance du 19/12/17
This commit is contained in:
parent
d64133d970
commit
60644cddd0
15 changed files with 1403 additions and 33 deletions
21
compte_rendu/Makefile
Normal file
21
compte_rendu/Makefile
Normal file
|
@ -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
|
||||
|
155
compte_rendu/MyPack2.sty
Normal file
155
compte_rendu/MyPack2.sty
Normal file
|
@ -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
|
0
compte_rendu/compte_rendu.tex
Normal file
0
compte_rendu/compte_rendu.tex
Normal file
BIN
compte_rendu/gabriel_vs_delaunay.png
Normal file
BIN
compte_rendu/gabriel_vs_delaunay.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
compte_rendu/reseau_naif.png
Normal file
BIN
compte_rendu/reseau_naif.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
compte_rendu/reseau_naif_log.png
Normal file
BIN
compte_rendu/reseau_naif_log.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
compte_rendu/reseau_vs_reseauRapide.png
Normal file
BIN
compte_rendu/reseau_vs_reseauRapide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
compte_rendu/reseau_vs_reseauRapide_log.png
Normal file
BIN
compte_rendu/reseau_vs_reseauRapide_log.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
33
graph.py
33
graph.py
|
@ -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
|
316
graphe.py
Normal file
316
graphe.py
Normal file
|
@ -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
|
195
graphique.py
Normal file
195
graphique.py
Normal file
|
@ -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_()
|
||||
|
109
polygone.py
Normal file
109
polygone.py
Normal file
|
@ -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.)
|
136
tas.py
Normal file
136
tas.py
Normal file
|
@ -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())
|
||||
|
||||
|
172
test.py
Normal file
172
test.py
Normal file
|
@ -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()
|
299
triangulation.py
Normal file
299
triangulation.py
Normal file
|
@ -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 a new issue