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