53
ECOLE POLYTECHNIQUE DE L’UNIVERSITE DE TOURS DEPARTEMENT INFORMATIQUE 64, Avenue Jean Portalis 37200 TOURS Rapport de stage de 4 ème année : Etude de la Windows Presentation Foundation (WPF) et réalisation d’un prototype de composant géographique chez Articque Maître de stage : Christophe LEBAS Responsable R&D chez Articque Etudiant : Vincent CHICHERIE DI4 Année 2008-2009

Stage Articque - Assemblasubversion.assembla.com/svn/rap_art/trunk/OldRapport/…  · Web viewA l’occasion des 20 ans d’Articque dans les locaux du département productique,

Embed Size (px)

Citation preview

ECOLE POLYTECHNIQUE DE L’UNIVERSITE DE TOURSDEPARTEMENT INFORMATIQUE64, Avenue Jean Portalis37200 TOURS

Rapport de stage de 4ème année :

Etude de la Windows Presentation Foundation (WPF) et réalisation d’un prototype de composant géographique chez

Articque

Maître de stage :Christophe LEBASResponsable R&D chez Articque

Etudiant :Vincent CHICHERIE

DI4 Année 2008-2009

Table des matières

Introduction......................................................................................................................5

Présentation d’Articque...................................................................................................6

Présentation de la mission..............................................................................................8

Travail effectué.................................................................................................................9

Découverte de la WPF....................................................................................................9

Introduction.................................................................................................................9

Le XAML...................................................................................................................10

Le moteur de composition de WPF...........................................................................12

Le Data Binding.........................................................................................................13

Le Data Templating...................................................................................................15

Les Styles..................................................................................................................15

Premier jet avec WPF...................................................................................................17

Améliorer les performances avec WPF........................................................................20

Récapitulatif performances.......................................................................................21

Améliorer les performances avec l’API Direct3D..........................................................23

Intégration du rendu Direct3D dans WPF.................................................................23

Intégration du code Direct3D dans un projet C#.......................................................24

Dessin de la carte avec Direct3D..............................................................................25

Réalisation du prototype d’afficheur de carte éditable..................................................27

Analyse du problème................................................................................................27

Réalisation d’un convertisseur de fichiers....................................................................33

Analyse du problème................................................................................................33

Réalisation du convertisseur et de son interface graphique.....................................34

Problèmes rencontrés...................................................................................................36

Problème de remplissage avec un Path...................................................................36

Problème de remplissage avec Direct3D..................................................................38

Conclusion......................................................................................................................39

Annexe A : Le cahier des charges simplifié du prototype.........................................40

Figure 1 Logo du groupe Articque......................................................................................6Figure 2 Résultat de l'exemple.........................................................................................11Figure 3 Exemple de réalisation possible grâce au moteur de composition de WPF......13Figure 4 Les différents modes de liaison.........................................................................13Figure 5 Exemple de zoom avec un Data Binding...........................................................14Figure 6 Exemple de style et de trigger...........................................................................16Figure 7 Résultat de la première approche : Data Templating des Entités......................19Figure 8 Occupation mémoire (en Ko).............................................................................21Figure 9 Temps d’attente avant affichage (en s)..............................................................22Figure 10 Temps d'attente avant affichage en fonction du nombre de polylines par groupe..............................................................................................................................22Figure 11 Illustration de D3DImage : la scène de la voiture est générée par un moteur Direct3D, et la rotation de l’image est faite par le moteur de composition de WPF.........24Figure 12 Rendu Direct3D de la carte infra communale..................................................26Figure 13 Possibilités de découpage de la géométrie pour le remplissage.....................28Figure 14 Possibilités de découpage de la géométrie pour les contours.........................29Figure 16 Diagramme UML de classes présentant les interfaces des packages............30Figure 15 Illustration de l'attribut NumEnsemble (de ShapeDVI) dans le cas d'une légende.............................................................................................................................31Figure 17 UML Diagramme de classes du convertisseur de formats..............................33Figure 18 UML Diagramme de classes de la structure de données commune...............34Figure 19 Interface graphique, en WPF bien sûr, pour le convertisseur..........................35Figure 20 Bug de remplissage.........................................................................................36Figure 21 Illustration de FillRule.......................................................................................37Figure 22 Bug de remplissage avec la primitive TriangleFan..........................................38

Introduction

L’objectif du stage de 4ème année est de découvrir des méthodes de travail en tant que développeur.

A l’occasion des 20 ans d’Articque dans les locaux du département productique, nous avons eu la chance, Christophe Mocquet et moi, de rencontrer Nicolas Béhier-Dévigne, un ancien élève de Polytech’Tours désormais développeur Web chez Articque. Rapidement, nous avons repris contact avec lui pour passer un entretien et nous avons été retenus tous les deux sur le même sujet.

Durant ce stage, nous avons travaillés ensemble la plupart du temps, chacun de nous mettant en œuvre des compétences complémentaires : Christophe s’est chargé principalement des modélisations UML et de l’analyse des résultats, pendant que moi je me concentrais sur l’implémentation.

Présentation d’Articque

Figure 1 Logo du groupe ArticqueSource : Articque

Fondée en 1989 par Georges-Antoine STRAUCH, Articque est le chef de file en Europe du Geographic Analysis System (GAS), combinaison de la cartographie et des statistiques permettant de visualiser mais aussi de nourrir et de piloter des bases de données stratégiques.

Articque offre ainsi aux entreprises une colonne vertébrale informatique aux informations de l’entreprise ou des collectivités facilement exploitables au travers de cartes tableau de bord.

On retrouve quatre métiers principaux dans ce groupe :

l’édition de logiciels : la société développe depuis plusieurs années toute une gamme de logiciels et de modules adaptés aux besoins de ses clients, comme par exemple, le logiciel Cartes & Données,

l’édition de composants : utile pour les programmeurs permettant d’intégrer des fonctionnalités de cartographie dynamique à des applications et sites web,

la conception d’application sur mesure : Articque crée pour ses clients des services Internet et Intranet où la cartographie statistique joue un rôle majeur,

la production de données : A partir de nombreux accords réalisés avec la recherche publique ou privée, la société a accès à un grand nombre de données qu’elle transforme et utilise pour les incorporer dans ses logiciels. C’est le cas

notamment des données électorales, des informations sur les communes françaises, etc.

Le logiciel phare d’Articque est Cartes & Données, leur solution bureautique de GAS, disponible gratuitement pour un usage personnel (fonctionnalités réduites) ou payante dans sa version professionnelle. Une déclinaison nommée « C&D Suite » propose C&D avec un ensemble d’outils cartographiques et de cartes, à acheter séparément dans l’édition standard.

Les cartes produites avec C&D peuvent être exploitées par C&D Web, pour être diffusées en ligne, mais ce produit se limite pour l’instant à la visualisation des cartes.

Enfin MapInXL est un plugin pour Microsoft Excel permettant de générer directement une carte dans la feuille de calcul Excel à partir de ses données (à destination du marché américain).

Ces logiciels sont utilisés par 5500 clients à travers le monde.

Le groupe Articque possède à l’heure actuelle 3 filiales :

1. Atmo’Expert qui est un bureau d’ingénierie des risques climatiques et des solutions durables.

2. GEOBS , une société de services spécialisée dans les SIG (Systèmes d’Information Géographiques) et dans la Géomatique. Les domaines d’application concernés sont multiples, les principaux sont les suivants : L’analyse et la gestion des risques, le géomarketing, l’environnement, l’aménagement du territoire, mobilité/transport, santé, urbanisme, etc…

3. Intercarto , spécialiste de la carte, sous toutes ses formes : cartes vectorielles pour les utilisateurs de SIG, cartes illustratives et graphiques pour tous et semi-manufacturées pour les professionnels de la communication et des médias.

Le groupe Articque est en plein essor, de nombreux changements structurels vont intervenir à partir de cette année, et le nombre d’employés (une trentaine actuellement) devrait doubler (selon M. STRAUCH) d’ici l’année prochaine à la même période.

Présentation de la mission

L’objectif de notre stage, tel que décrit sur notre convention, est de valider l’utilisation de la WPF pour la réalisation d’une série de composants .NET dédiés à la Cartographie.

Pour mieux comprendre l’intérêt de notre mission pour Articque, il est intéressant de se replacer dans le contexte.

Tout d’abord C&D est un logiciel qui commence à « dater », dans le sens où il a été conçu il y a longtemps et est passé entre les mains de nombreux développeurs. Il a été écrit en C++ et utilise de nombreuses bibliothèques différentes, et bien que le logiciel soit stable, il est difficilement maintenable et encore plus difficile à faire évoluer.

D’un autre côté il y a C&D Web qui utilise la technologie Flash, qui est un développement dissocié de C&D.

Articque est membre actif de la Communauté Française des Editeurs de Logiciels et s’est engagé aux côtés de Microsoft pour promouvoir les technologies .NET au sein de ses nouveaux développements.

Avec le Framework .NET 3.0 et l’introduction des technologies WPF et Silverlight, Microsoft propose de rapprocher fortement le développement d’applications bureautiques du développement d’applications web.

Articque à de toutes manières prévu de réécrire C&D en C#, mais il lui reste à choisir la technologie d’affichage la plus adaptée.

C’est à ce niveau que nous intervenons, avec tout d’abord la découverte de la WPF (inconnue à l’heure de notre stage de l’équipe de développeurs) en termes de possibilités d’affichage et de performances et enfin la réalisation d’un prototype de module d’affichage.

Travail effectué

Découverte de la WPF

Introduction

WPF (Windows Presentation Foundation) est la nouvelle technologie de Microsoft qui permet de développer des interfaces graphiques offrant une grande interactivité, notamment grâce à des animations, des effets visuels et l’utilisation de médias.

Ce système graphique permet de réaliser du graphisme 2D et 3D, du dessin vectoriel et bitmap, ainsi que de la vidéo et de l’audio.

WPF peut être utilisé pour développer des interfaces graphiques de logiciels, bien sûr, mais il existe également une version allégée pour le Web nommée Silverlight (anciennement WPF/Everywhere).

Pourquoi utiliser WPF ? Dans son livre, Thomas Lebrun expose en cinq points (que j’ai résumés ici), la réponse de Microsoft aux besoins et demandes que les développeurs lui ont remontés.

Le premier objectif de WPF est d’unifier les médias. Plutôt que d’utiliser GDI/WindowsForms/wxWidgets pour l’interface utilisateur, DirectX pour manipuler les médias, PDF, Word ou autre pour intégrer des documents, WPF unifie tout cela en offrant au développeur un ensemble de classes prédéterminé réalisant les fonctions les plus courantes.

Le deuxième objectif de WPF est de proposer un rendu vectoriel, obligatoire pour des problématiques d’accessibilité. Implémenter des systèmes de zoom devient un jeu d’enfant et il n’y a pas de perte de qualité d’affichage.

Le troisième objectif de WPF est de léguer à la carte graphique l’ensemble des calculs nécessaires pour afficher l’interface utilisateur, donc d’alléger le travail du processeur (dans le cas où la carte graphique est suffisamment récente).

Le quatrième objectif de WPF est de proposer un double modèle de programmation : déclaratif avec le langage XAML, et impératif avec le code .NET afin de mieux intégrer les designers dans le développement d’une application.

Le cinquième et dernier objectif est la simplicité de déploiement en proposant de créer des applications stand alone ou bien hébergées dans un navigateur web.

Source : WPF par la pratique – Thomas Lebrun - Eyrolles

Lors de cette découverte, nous nous sommes confrontés au nouveau langage associé à WPF : le XAML et à de nouveaux concepts ou évolutions de concepts existants déjà en .net (mais pour nous tout est nouveau puisque nous n’avons jamais travaillé en .NET).

Le XAML

Le XAML (« zammel ») est l’acronyme de eXtensible Application Markup Langage. Il s’agit d’un langage déclaratif destiné au designer (ou développeur) pour décrire une grande partie de l’interface graphique (voire toute l’interface). La partie logique de XAML s’écrit avec un langage impératif .NET dans un fichier dit « code-behind » définit comme étant une classe partielle.

Le code XAML est relié au code-behind en étant interprété avant la compilation, ce qui donne une seconde classe partielle en langage .NET.

Code XAML1 <Window x:Class="WpfApplication4.Window1"2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"4 Title="Window1" Height="300" Width="300">5 <Grid>6 <Button Click="Button_Click">cliques</Button>7 </Grid>8 </Window>Source : -

XAML est du XML, il ne contient donc qu’un seul élément racine (ici Window).

L’attribut x :Class donne le nom de la classe partielle dont ce fichier fait partie, et les attributs xmlns permette de définir les espaces de noms pour les balises.

La balise <Grid> par exemple est définie dans l’espace de nom « http://schemas.microsoft.com/winfx/2006/xaml/presentation » puisqu’elle n’est pas préfixée.

L’attribut x :Class appartient quant à lui à l’espace de noms « http://schemas.microsoft.com/winfx/2006/xaml » puisque préfixé par « x : »

Cet exemple de code XAML décrit une fenêtre contenant un conteneur Grid, qui contient un bouton. A ce bouton, nous avons associé un gestionnaire pour l’événement Click appelé « Button_Click ». La logique de ce gestionnaire est décrite dans la partie code-behind qui suit.

Code C#1 using {…}23 namespace WpfApplication44 {5 /// <summary>6 /// Logique d'interaction pour Window1.xaml7 /// </summary>8 public partial class Window1 : Window9 {10 public Window1()11 {12 InitializeComponent();13 }1415 private void Button_Click(object sender, RoutedEventArgs e)16 {17 MessageBox.Show("tu as cliqué");18 }19 }20 }Source : -

La fonction InitializeComponent() appelée à la construction est générée à partir du code XAML et sert à créer tous les objets déclarés en XAML.

On retrouve enfin dans ce fichier le gestionnaire « Button_Click » (ici qui affiche un simple message).

Figure 2 Résultat de l'exempleSource : -

Le moteur de composition de WPF

Le moteur de composition de WPF est grossièrement ce qui nous permet de mettre du contenu dans du contenu.

Code XAML1 <Window x:Class="WpfApplication4.Window1"2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"4 Title="Window1" Height="300" Width="351">5 <Grid> 6 <ListBox HorizontalAlignment="Left" >7 <ListBoxItem>un texte classique</ListBoxItem>8 <ListBoxItem>9 <Button>10 <StackPanel Orientation="Horizontal">11 <TextBlock>Un bouton contenant du texte</TextBlock>12 <CheckBox>une checkbox</CheckBox>13 <ComboBox>14 <ComboBoxItem>et une ComboxBox</ComboBoxItem>15 </ComboBox>16 </StackPanel>17 </Button> 18 </ListBoxItem>19 <ListBoxItem>20 <StackPanel Orientation="Horizontal">21 <Image Source="http://www.atmoexpert.com/images/logo-articque.png"/> 22 <TextBlock VerticalAlignment="Center">et une image provenant d'internet</TextBlock>23 </StackPanel>24 </ListBoxItem>25 </ListBox>26 </Grid>27 </Window>

Source : -

Figure 3 Exemple de réalisation possible grâce au moteur de composition de WPFSource : -

Les possibilités sont très nombreuses et la réalisation de contrôles personnalisés aisée. C’est d’ailleurs la raison pour laquelle on ne retrouve pas « en stock » tous les contrôles WindowsForms : Microsoft estime que n’importe quel autre contrôle que l’on pourrait avoir besoin est facilement réalisable par le programmeur (en fait pour réaliser un vrai contrôle personnalisé il faut réaliser un Control Template mais nous n’aborderont pas le sujet).

Le Data Binding

Ou liaison de données. Ceci est un concept qui existe depuis le début du Framework .NET qui met en relation des données métier et l’interface utilisateur. Lorsqu’une valeur de propriété change, les éléments graphiques changent aussi et vice-versa (par exemple une TextBox liée avec une propriété Nom).

Bien que ce ne soit pas une nouveauté introduite avec la WPF, le concept a quand même été amélioré avec cette dernière : il est désormais possible de lier les éléments graphiques à des objets .NET (y compris des objets ADO.NET, des services web…), des données XML ou encore d’autres éléments de l’interface graphique.

Figure 4 Les différents modes de liaisonSource : http://msdn.microsoft.com/fr-fr/library/ms752347.aspx

Avec ce schéma, un nouveau concept est introduit : la propriété dépendance ou dependency property, qui est un nouveau type de propriété introduit avec WPF. Sans entrer dans le détail, ces propriétés ont la particularité de pouvoir être animées, transformées, liées à l’interface graphique et notifier l’interface graphique lorsque la valeur de la propriété est modifiée.

Typiquement, on peut utiliser le Data Binding pour créer facilement un zoom.

Code XAML0 <Window x:Class="WpfApplication4.Window1"1 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"3 Title="Window1" Height="300" Width="351">4 <StackPanel>5 <Slider Name="sldZoom" Minimum="1" Maximum="50"/>6 <Button Width="100">7 <Button.LayoutTransform>8 <ScaleTransform ScaleX="{Binding ElementName=sldZoom, Path=Value}" ScaleY="{Binding ElementName=sldZoom, Path=Value}"/> 9 </Button.LayoutTransform>10 <Button.Content>11 <StackPanel Orientation="Horizontal">12 <TextBlock>Zoom X</TextBlock>13 <TextBlock Text="{Binding ElementName=sldZoom, Path=Value}"/>14 </StackPanel>15 </Button.Content>16 </Button> 17 </StackPanel>18 </Window>

Source : -

Figure 5 Exemple de zoom avec un Data BindingSource : -

Dans cet exemple on a créé un Slider « sldZoom » qui prend ses valeurs entre 1 et 50, et un Button quelconque auquel on a attaché une transformation de type ScaleTransform qui a ses propriétés de dépendance « ScaleX » et « ScaleY » liées à la propriété de dépendance « Value » de sldZoom.

Le Data Templating

Le Data Templating est une notion qui sert à associer une apparence visuelle à un objet métier.

C’est grâce à cela que l’on peut représenter très facilement une liste de points par un polygone.

Il est possible de définir des Triggers dans un Data Template, qui permettent par exemple de choisir un fond rose pour un contact féminin et un fond bleu pour un contact masculin dans une liste de contact.

Enfin, il est même possible d’utiliser un DataTemplateSelector pour choisir un DataTemplate pour un objet en fonction de n’importe quels paramètres.

Je ne détaillerai pas ici le Data Templating puisqu’il s’agit de la technique utilisée pour notre première approche du problème, que je présenterai plus loin.

Les Styles

Les Styles en WPF peuvent être vus comme un CSS pour une page web.

En effet, si l’on veut que tous les textes de nos boutons soient à droite et en gras, il faut définir ces propriétés dans chaque bouton.

Avec un style, on peut centraliser tout cela, et appliquer le style aux objets de notre choix.

Code XAML0 <Window.Resources>1 <Style TargetType="Button">2 <Setter Property="HorizontalContentAlignment" Value="Right"/>3 <Setter Property="FontWeight" Value="Bold"/>4 </Style>5 </Window.Resources>

Source : -

Avec ce style défini dans les ressources d’un objet parent, tous les Button enfants auront leur contenu aligné à droite et leur texte en gras (sauf si on redéfini ces propriétés directement sur le bouton).

On notera qu’il est possible d’associer une clef à un style et choisir à quels objets en particulier on veut l’associer (via la propriété « style »).

Enfin il est possible aussi d’utiliser des déclencheurs avec les styles, voici un exemple :

Code XAML0 <Window x:Class="WpfApplication4.Window1"1 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"3 Title="Window1" Height="300" Width="351">4 <Window.Resources>5 <Style TargetType="Button">6 <Setter Property="HorizontalContentAlignment" Value="Right"/>7 <Setter Property="FontWeight" Value="Bold"/>8 <Style.Triggers>9 <Trigger Property="HorizontalContentAlignment" Value="Left">10 <Setter Property="Foreground" Value="Red"/>11 </Trigger>12 </Style.Triggers>13 </Style>14 </Window.Resources>15 <StackPanel>16 <Button HorizontalContentAlignment="Left">Bouton 1</Button>17 <Button>Bouton 2</Button>18 <Button>Bouton 3</Button> 19 </StackPanel>20 </Window>Source : -

Ce code donne à l’exécution :

Figure 6 Exemple de style et de triggerSource : -

On remarque que le style déclaré dans les ressources s’applique bien à tous les boutons. Pour ce qui est du Bouton 1, on a défini explicitement son alignement à gauche, ce qui est prioritaire sur le style, en revanche, on n’a rien défini pour ce qui est de l’épaisseur du texte, c’est donc le style qui est appliqué et le bouton est bien en gras.

Le Bouton 1 est également le seul bouton à déclencher le trigger (la condition du trigger est d’avoir l’alignement horizontal à gauche), et c’est donc pour cela que le texte apparait en rouge.

Premier jet avec WPF

Partant des quelques notions présentées ci-dessus, nous nous sommes lancés dans la production rapide d’une application WPF qui affiche une carte contenue dans un fichier VXF, avec des symboles (de simples cercles) positionnés sur le centre géométrique des entités.

La grande simplicité de codage proposée par C# et WPF nous a permis de réaliser un premier affichage interactif en un peu moins d’une semaine.

Nous avions à disposition un parseur VXF écrit en C#. Ce parseur nous retourne une liste d’objets « Entity », sous-classés en objets EntPoint et EntPolyline (représentant respectivement des points et des polylines).

Cette liste d’Entités, nous l’avons liée (avec un Data Binding) à un contrôle WPF générique acceptant des collections d’objets : un ItemsControl.

Nous avons ensuite créé deux Data Templates : un pour représenter un objet EntPolyline et un autre pour représenter un objet EntPoint.

L’EntPoint sera représenté par une ellipse, tandis que l’EntPolyline sera représenté par… une polyline. Voici ci-dessous le DataTemplate de l’EntPolyline défini dans les ressources de la fenêtre:

Code XAML1 <DataTemplate x:Key="EntPolyLineTemplate"> 2 <Polyline Points="{Binding Points}" Stroke="Bl" StrokeThickness="1">3 <Polyline.ToolTip>4 <!--Décrire ici la tooltip-->5 </Polyline.ToolTip>6 <Polyline.Style>7 <Style TargetType="Polyline"> 8 <Setter Property="Fill" Value="Azure"/>9 </Style>10 </Polyline.Style>11 </Polyline> 12 </DataTemplate>

Source : -

On voit dans le code XAML ci-dessus que la propriété Points de notre objet graphique Polyline est « Bindée » sur l’attribut Points de son contexte de données, qui sera ici l’objet que le Data Template représentera, donc de l’EntPolyline.

Le problème avec un ItemsControl est qu’il n’est possible de n’affecter qu’un seul Data Template à la propriété ItemTemplate. La solution est de créer un objet héritant de DataTemplateSelector, surchargeant sa méthode SelectTemplate et de l’affecter à la propriété ItemTemplateSelector de l’ItemsControl.

Code C#1 DataTemplate SelectTemplate(object item, DependencyObject container)Source : -

La méthode SelectTemplate est appelée pour chaque objet de l’ItemsControl. Une référence sur l’objet en question est passée à la fonction pour nous permettre d’accéder aux informations que l’on souhaite et qui nous permettra de déterminer quel Data Template renvoyer pour l’appliquer à l’objet. La classe mère Entity contenant une propriété Code, nous pouvons simplement tester si Code est égal au code correspondant à un EntPoint ou un EntPolyline et retourner le DataTemplate adéquat.

Restait à définir pour l’ItemsControl le type de Panel sur lequel on veut que les éléments soient affichés. Nous avons choisi un Canvas qui permet de positionner les objets de manière absolue.

Et enfin, on a défini le positionnement des éléments à l’aide d’un style (Offset X, Offset Y, et ZIndex sont des propriétés de notre classe Entity) :

Code XAML1 <ItemsControl.ItemContainerStyle>2 <Style>3 <Setter Property="Canvas.Left" Value="{Binding OffsetX}"/>4 <Setter Property="Canvas.Top" Value="{Binding OffsetY}"/>5 <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}"/> 6 </Style>7 </ItemsControl.ItemContainerStyle>

Source : -

Voici l’affichage que l’on a pu obtenir :

Figure 7 Résultat de la première approche : Data Templating des EntitésSource : -

Malheureusement tout n’est pas parfait, et c’est le temps d’attente avant l’affichage de la carte de France infra communale qui pose problème (l’exemple ci-dessus est la France Départementale et n’est pas concernée par ce problème). De même, le zoom et le défilement sont peu réactifs lorsque toutes les entités sont visibles.

Bien que la carte de France infra communale ne soit en pratique que très rarement utilisée par les clients, les performances de notre application ne sont que de peu supérieures à Flash.

Améliorer les performances avec WPF

La première piste à explorer pour accélérer le temps de chargement et la rapidité d’affichage est de changer de méthode de dessin.

WPF propose en effet différentes méthodes de dessins proposant différents niveaux de services, une souplesse plus ou moins accrue, et donc différents niveaux de performances.

Pour rappel, nous avons utilisé dans notre première approche la méthode du Data Templating pour dessiner notre carte : nous associons à un ItemsControl notre liste d’objets Entity qui seront dessinés spécifiquement en fonction de leur propriété Code (qui indique si l’entité est en fait un point ou un polyline etc…)

Ce mécanisme offre une grande souplesse et nous a permis d’obtenir rapidement un résultat visuel et interactif convaincant, en dépit des performances : sur la carte fr_infracommunale.vxf qui comporte 50000 entités, il faut attendre pas loin de 30s avant de la voir apparaître.

Nous avons étudié et testé plusieurs méthodes de dessins proposées par WPF pour afficher notre carte.

Récapitulatif performances

Cette partie a été réalisée par Christophe pendant que j’étais chargé d’explorer la piste Direct3D (voir section suivante). Les résultats qu’il a obtenus sont importants puisqu’ils nous ont permis de choisir une technique d’affichage pour le prototype que nous réaliseront.

Les graphiques suivants concernent la carte France IRIS, qui contient 50636 polylines et qui totalise 2 663 007 points (la plus grosse carte mise à notre disposition, il faut d’ailleurs garder à l’esprit que travailler sur des cartes aussi détaillées est peu courant).

Figure 8 Occupation mémoire (en Ko)Source : Christophe

Figure 9 Temps d’attente avant affichage (en s)Source : Christophe

D’une manière générale, les meilleures performances sont obtenues par la méthode dite « groupe » (Il s’agit en fait de découper la géométrie de la carte en objets StreamGeometry et de les afficher à l’aide d’objets Paths).

Figure 10 Temps d'attente avant affichage en fonction du nombre de polylines par groupeSource : Christophe

Quand on regarde plus en détail la méthode de dessin « groupe » et que l’on fait varier le nombre de polylines par groupes (et par conséquent le nombre de groupes), le temps d’attente minimum est atteint avec 500 polylines par groupes (soit pour la carte France Iris, 100 groupes).

Christophe a d’ailleurs fait ressortir que le critère le plus déterminant est bel et bien le nombre de groupes, plutôt que le nombre de polylines par groupes.

Améliorer les performances avec l’API Direct3D

Une des raisons selon moi de la relative lenteur d’affichage en WPF est l’activation imposée de l’anti-aliasing. L’anti-aliasing est un traitement graphique qui permet d’éliminer l’effet d’escalier sur le contour de la géométrie, et dans notre cas la géométrie est très complexe.

De tels traitements permettent aux fonctions de dessin de WPF de générer des images de très bonne qualité, au sacrifice des performances.

Les API tels que Direct3D ou OpenGL nous permettent de travailler à bas niveau avec la carte graphique. Nous allons nous attacher à afficher la carte sans anti aliasing, mais surtout nous auront directement le contrôle sur la carte graphique (on ne sait pas trop comment WPF la gère).

Intégration du rendu Direct3D dans WPF

Depuis le SP1 pour le .net Framework 3.0/3.5, une nouvelle classe de System.Windows.Interop a fait son apparition : la classe D3DImage qui hérite de ImageSource.

Comme son nom l’indique, cette classe permet d’afficher une surface Direct3D générée par l’utilisateur, et le fait qu’elle hérite d’ImageSource, nous permet de l’afficher à l’aide d’un objet Image, ImageBrush ou ImageDrawing et sera donc manipulable comme d’une image classique en WPF.

Figure 11 Illustration de D3DImage : la scène de la voiture est générée par un moteur Direct3D, et la rotation de l’image est faite par le moteur de composition de WPF

Source : http://www.microsoft.com/france/vision/mstechdays09/Webcast.aspx?eID=1883c554-bd6f-465f-8603-16c162572345

Cette nouveauté rend caduque la méthode de l’overlay présentée à cette adresse :

Source : http://blogs.msdn.com/pantal/archive/2007/07/31/managed-directx-interop-with-wpf-part-2.aspx

Code C#d3dimage.SetBackBuffer(D3DResourceType resourceType, IntPtr ComPointer);

Source : -

Intégration du code Direct3D dans un projet C#

Les deux principales façons d’intégrer du code DirectX dans un projet C# à l’heure actuelle sont :

1) Développer avec DirectX en C++ et l’intégrer au code C# sous forme d’un DLLImport.

2) Utiliser un wrapper DirectX en C# :a) MDX (Managed DirectX), la solution officielle de Microsoft. Le problème est que

MDX n’est plus développé par Microsoft depuis Avril 2006, le support se limite donc à DirectX 9 et les quelques bugs qu’il comporte resteront non corrigés.

b) SlimDX, une solution open source, dont le développement est actif et dont l’objectif est justement de reprendre le flambeau de MDX.

c) Framework XNA de Microsoft, ce Framework est destiné à la production de jeux vidéos compatibles PC/Xbox360/Zune, c’est le seul remplaçant de MDX proposé par Microsoft.

J’ai retenu la solution SlimDX, utiliser un wrapper est certes un peu moins performant (pour des scènes vraiment compliquées) mais l’intégration au projet est bien meilleure : on peut accéder directement aux objets C# (les données géométriques sont lues et chargées dans des objets C#) ; avec un DLLImport il nous aurait fallu passer les objets en paramètres en passant par des pointeurs physiques, ce qui est moins simple et plus dangereux.

L’utilisation de SlimDX ressemble énormément à celle de MDX qui est très largement documentée sur Internet, il est donc possible de démarrer très rapidement et c’est précisément ce qu’il me fallait pour faire un test.

Dessin de la carte avec Direct3D

La première chose à faire est de définir une structure point (appelé vertex dans le jargon 3D) compréhensible pour Direct3D :

Code C#1 [StructLayout(LayoutKind.Sequential)]2 private struct VertexTransformedColored3 {4 public Vector4 Position;5 public int Color;6 }7 private static readonly VertexFormat vfVertexTransformedColored = VertexFormat.Diffuse | VertexFormat.PositionRhw;Source : -

On remarque que l’attribut couleur est directement donné dans la structure du vertex.

L’affichage se fera en deux temps : tout d’abord le fond sera dessiné à partir d’une liste de vertex V1 avec des primitives TriangleStrip puis les contours à partir d’une liste de vertex V2 avec des LineStrip.

Les coordonnées des points de V1 et de V2 sont les mêmes mais leur attribut de couleur est différent (on veut le fond en vert et les contours en noir), c’est pourquoi il est nécessaire d’utiliser deux listes de vertex (une solution serait d’utiliser un Material, et de seulement changer le Material avant de dessiner une seconde fois la même liste de points).

Figure 12 Rendu Direct3D de la carte infra communaleSource : -

Les performances sont ici très correctes, la carte est redessinée 25 fois par secondes, avec transparence, on est donc très loin devant WPF.

On notera que le dessin des primitives géométriques est aussi rapide avec que sans index (le dessin avec index devrait être plus rapide si l’on repérait les points communs à plusieurs entités géométriques…).

Pour plus de détails sur le dessin de primitives indexées je vous invite à visiter l’excellent article de Jon Steed :

Source : http://blogs.msdn.com/jsteed/articles/185681.aspx

Le problème avec Direct3D est que l’on perd beaucoup en facilité de développement, et surtout, à l’heure actuelle ceci ne peut pas fonctionner à travers le Web. On rappelle qu’un des intérêts qu’à Articque à choisir WPF est sa facilité de portage vers Silverlight.

Réalisation du prototype d’afficheur de carte éditable

Si jusqu’à présent nous n’avons pas utilisé de méthode de travail particulière pour programmer nos exemples, ici nous devons réaliser des bases suffisamment solides pour être reprises par les développeurs d’Articque.

Aucun cahier des charges ne nous a été fourni, cela est pourtant bien utile pour pouvoir réaliser l’étendue du travail à réaliser et surtout pour nous fixer des limites. En effet, travailler avec C#/WPF est très agréable, on obtient rapidement un résultat, mais il est très facile de se laisser aller dans des détails assez chronophages.

Le cahier des charges est donc à notre charge, j’en ai réalisé un avec Christophe, simplifié (en annexe).

La date de remise de ce rapport est imminente bien qu’il reste encore deux semaines de stage. Nous sommes à l’heure actuelle en train de faire l’analyse du problème. La partie qui suit décrit notre analyse du problème à l’heure actuelle mais n’est probablement pas définitive.

Analyse du problème

Il ressort de nos précédents essais que la méthode de dessin la plus performante pour afficher de nombreux polygones (ce qui est le cas quand on veut afficher les contours d’un fond de carte et, dans une moindre mesure, le remplissage de fond de carte en fonction de données) est d’utiliser des objets StreamGeometry et de « compiler » plusieurs polygones dans un seul objet Path.

L’objet StreamGeometry ne contient pour ainsi dire que des informations purement géométriques, les informations de contour, de couleur, et plus généralement tout ce qui relève de l’affichage sont à la charge de l’objet Path.

De ce fait, on obtient la contrainte suivante : toute la géométrie présente dans un Path sera affichée de la même manière.

En considérant 3 entités géographiques dont une (la 01) composée de 2 polylines, j’ai cherché les différentes façons de générer la géométrie pour le remplissage et les contours.

Figure 13 Possibilités de découpage de la géométrie pour le remplissage

Source : -

remplissage

id=01Id=01

Id=02

Id=03

Actuellement dans C&D la représentation remplissagePrend un fond de carte en entrée ainsi que des données

Le contour dépend des données pour tout le fond de carteles contraintes sont d’avoir toute la géométrie ayant un même Id dans la même Shapeet une unique couleur par Shape

1er découpage possible:-Path1 : Liste Entités={01} Groupé : Oui-Path2 : Liste Entités={02} Groupé : Non-Path3 : Liste Entités={03} Groupé : Non

2ème découpage possible:-Path1 : Liste Entités={01,03} Groupé : Oui-Path2 : Liste Entités={02} Groupé : Non

Figure 14 Possibilités de découpage de la géométrie pour les contoursSource : -

Le problème de la compilation des polylines dans un seul objet est qu’elles ne seront pas accessibles individuellement lorsqu’on passera en mode édition.

Ce problème est pour le moment au centre de notre modélisation, où nous considérons une classe Degroupeur interne à la classe Composant Edition qui obtiendra les représentations individuelles des polygones des Paths (ou ShapeGUI dans le diagramme qui suit) composés (qui contiennent donc plusieurs polygones).

Cette distinction est, dans notre modélisation, à la charge du programmeur dans la fonction GenererCouches(Entités :List<EntiteGeo>, ModeEdition :bool) : Si ModeEdition est à Vrai, alors il lui faudrait fournir un polygone par ShapeGUI, s’il est à Faux, alors il doit essayer de mettre le plus de géométrie possible dans un seul ShapeGUI pour optimiser les performances.

id=01Id=01

Id=02

contours

Id=03

Actuellement dans C&D la représentation contourNe prend qu’un fond de carte en entrée

Le contour est unique pour tout le fond de cartela seule contrainte est d’avoir toute la géométrie

ayant un même Id dans la même Shape

1er découpage possible:-Path1 : Liste Entités={01} Groupé : Oui-Path2 : Liste Entités ={02} Groupé : Non-Path3 : Liste Entités ={03} Groupé : Non

2ème découpage possible:-Path1 : Liste Entités ={01,02} Groupé : Oui-Path2 : Liste Entités ={03} Groupé : Non

3ème découpage possible:-Path1 : Liste Entités ={01,03} Groupé : Oui-Path2 : Liste Entités ={02} Groupé : Non

4ème découpage possible:-Path1 : Liste Entités ={01,02,03} Groupé : Oui

Figure 15 Diagramme UML de classes présentant les interfaces des packagesSource : -

Nous avons modélisé avec les interfaces dans le package Représentation les fonctionnalités attendues des classes ShapeGUI et Couche.

On notera que le package Données Géo n’est pas de notre ressort, et qu’il manque de toute manière les données associées aux Entités géographiques. C’est normal, nous avons fait au plus simple concernant les données d’entrée pour nous concentrer uniquement sur notre module.

Nous avons également pensé au problème du déplacement groupé des objets graphiques, nous proposons pour le moment un tableau d’entiers (ou une liste ordonnée).

Figure 16 Illustration de l'attribut NumEnsemble (de ShapeDVI) dans le cas d'une légendeSource : -

L’attribut NumEnsemble:Integer[]Il servira à définir un ensemble ainsi que des sous-ensembles de Shapes à déplacer en même temps. Pour cela on associe un tableau de numéros d’ensembles, avec en premier numéro celui deL’ensemble dont il est le « maître ».

Type de produitsType 1Type 2

ShapeCadre : NumEnsemble =[1]ShapeTitre : NumEnsemble =[2,1]

ShapeRondVert : NumEnsemble =[3,1]ShapeRondRouge : NumEnsemble =[4,1]

ShapeType2 : NumEnsemble =[4,1]ShapeType1 : NumEnsemble =[3,1]

Le déplacement de ShapeCadre (1) entraine le déplacement de toutes les Shapes quicontiennent (1) dans leur tableau : toutes les Shapes.Le déplacement de ShapeRondVert entraine uniquement le déplacement de ShapeType1et vice-versa.

Expérimentations sur les événements avec WPF

Parallèlement à l’analyse du prototype, j’ai pris le temps de vérifier en pratique la faisabilité de certains aspects de notre modélisation.

Ici j’ai repris un de nos exemples d’affichage auquel j’ai simplement ajouté une classe correspondant à ModificateurShape dans notre UML. Les instances de cette dernière sont crées et liées aux Shapes dynamiquement par le Canvas.

Pour ce faire, j’ai dû m’attarder un peu sur l’étude des événements en WPF :

Source : http://msdn.microsoft.com/fr-fr/magazine/cc785480.aspx

Le canvas, en récupérant l’événement MouseDown peut en vérifier la source :

S’il s’agit d’une Shape alors on l’ajoute à la sélection : on crée un objet ModificateurShape que l’on lie à cette dernière. Cet objet est ajouté à la collection d’objets « ModificateurShape » du canvas.

S’il s’agit de lui-même, alors c’est qu’on a cliqué dans une zone vide, et dans ce cas on désélectionne les Shapes (et on vide la collection d’objets « ModificateurShape » du canvas).

Figure 17 Expérimentation du déplacement des Shapes (familiarisation avec les évenements)Source : -

Réalisation d’un convertisseur de fichiers

Dans le cadre d’un petit travail annexe (convertir le format WKT vers le format VXF), l’idée à été émise de créer une librairie de conversion un peu plus générique, qui permettrait de convertir un format de fichier géographique d’entrée X vers un format de sortie Y.

Analyse du problème

De ce besoin que nous venons d’exprimer, nous avons réalisé le diagramme de classes suivant :

Figure 18 UML Diagramme de classes du convertisseur de formatsSource : -

Un objet Converter se charge de lire à l’aide d’un objet Reader adapté le fichier d’entrée, et d’écrire le fichier de sortie à l’aide d’un Writer adapté.

Dans le cas de notre problème initial, le Reader est un WKTReader et le Writer un VXFWriter.

De ce diagramme il faut aussi comprendre que pour supporter complètement un format de fichier, il faut seulement écrire son Reader et son Writer : il était bien entendu hors de question de réaliser n*n-1 fonctions du style WKTtoVXF() et VXFtoWTK().

Nous avons dû mettre au point une structure de données géographiques commune entre les formats pour réaliser naturellement la conversion d’un format vers un autre :

Figure 19 UML Diagramme de classes de la structure de données communeSource : -

Une telle structure résulte du constat que d’un format géographique à un autre, tous ne contiennent que des « Entités » dont les plus récurrentes sont des points, des polylines et polygones.

Ainsi un objet Reader devra juste être capable de remplir cette structure de données, alors que le Writer devra juste être capable de la lire et de n’utiliser que ce qu’il a besoin dans cette structure.

Réalisation du convertisseur et de son interface graphique

Une fois tout le squelette des classes réalisé en C#, et le travail initial étant de convertir le WKT vers du VXF, j’ai donc naturellement commencé par implémenter l’objet WKTReader.

Le WKT est un format texte compréhensible pour l’humain, l’extraction des informations est grandement facilitée à l’aide des expressions régulières de .net, la lecture de ce format s’effectue sans encombre.

Reste à faire le VXFWriter qui lui est un format binaire. Cependant par soucis de livrer une solution au problème initial rapidement, j’ai commencé par implémenter un NUMWriter.

Le format NUM est la version texte du format VXF, écrire et vérifier un fichier texte m’a semblé plus rapide que pour un format binaire et par ailleurs, un convertisseur NUM vers VXF existe déjà.

Figure 20 Interface graphique, en WPF bien sûr, pour le convertisseurSource : -

L’interface graphique est plutôt sommaire mais est fonctionnelle, et propose deux petits raffinements, le premier étant la couleur des champs de texte qui vire au vert lorsque l’URI entrée est valide et au rouge sinon ; le second est le choix automatique du format (dans les listes défilantes) en fonction de l’extension du fichier choisi (ce choix est bien entendu modifiable par l’utilisateur).

Problèmes rencontrés

Problème de remplissage avec un Path

Figure 21 Bug de remplissage

Source : -

Deux entités ne sont pas coloriées. Ce bug apparaît lorsqu’on dessine un Path constitué d’un StreamGeometry lui-même composé de plusieurs Figures et qu’elles se trouvent imbriquées les unes dans les autres.

Dès qu’on ne dessine qu’une Figure par Path le bug disparaît.

En recherchant dans la MSDN, nous trouvons la propriété StreamGeometry.FillRule prenant deux valeurs :

1. FillRule.EvenOdd2. FillRule.NonZero

Figure 22 Illustration de FillRule

Source : http://msdn.microsoft.com/en-us/library/system.windows.media.streamgeometry.fillrule.aspx

Malheureusement dans notre cas, cette propriété n’a pas eu l’effet escompté, et le problème n’est pas résolu à ce jour.

Problème de remplissage avec Direct3D

Figure 23 Bug de remplissage avec la primitive TriangleFan

Source : -

Ce bug est dû à l’utilisation d’une primitive TriangleFan pour effectuer le remplissage de la couleur.

Pour remplir un polygone concave quelconque avec les primitives de Direct3D, il faut le décomposer en polygones convexes.

Pour cela il existe des algorithmes de décomposition, dont le plus simple est connu sous le nom d’EarClipping.

Source : http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf

Une autre solution mettant en œuvre une technique de rendu en 2 passes peut également être envisagée (ici la méthode est expliquée pour OpenGL):

Source : http://glprogramming.com/red/chapter14.html#name13

Je n’ai pas mis en œuvre les techniques précitées, puisque mon encadrant a décidé de mettre la piste de l’affichage avec Direct3D de côté.

Conclusion

A l’heure où j’écris ces lignes, le stage n’est pas encore fini mais l’heure de rendre ce rapport approche…

Jusqu’à présent le stage s’est très bien déroulé, dans l’entreprise il y a une très bonne ambiance de travail, les gens sont disponibles et sereins.

L’étude de la WPF est très intéressante, je ne pense pas me tromper en disant qu’il s’agit de la meilleure technologie à l’heure actuelle pour réaliser des applications stand alone (et Web avec Silverlight) dites « enrichies », sous MS Windows en tous cas.

Malgré quelques recherches fastidieuses (personne dans l’équipe de développement n’est formé sur WPF), l’utilisation de WPF est intuitive et nous obtenons très rapidement des résultats intéressants aussi bien visuellement que fonctionnellement.

Il est par ailleurs prévu que je fasse avec Christophe Mocquet une « formation » sur WPF pour les développeurs d’Articque, probablement durant la dernière semaine avant de partir.

Enfin je remercie toute l’équipe d’Articque pour leur accueil.

Annexe A : Le cahier des charges simplifié du prototype

Présentation du documentPrésentation du clientArticque S.A. spécialisée dans la géostatistique

Conventions et terminologie utilisées dans le documentPrototype : implémentation du modèle UML en C#/WPF. Il est composé de deux parties (indépendantes ?) : la partie présentation et la partie mise en page

Partie présentation : affiche différentes couches contenants différents symboles ou entités géographiques.

Entité géographique : Ensemble de polylines/polygones pouvant être réduit à 1.

Partie mise en page : Permet de désolidariser les éléments de la carte affichée en partie présentation.

Fichier VXF : Les fichiers VXF contiennent une base de données cartographique contenant des points, polylines, polygones et images avec leurs attributs.

Présentation du produitPrésentation générale du problèmeRéaliser le prototype d’un contrôle de visualisation de cartes en WPF ainsi que le module de mise en page.

Donc en fait : un diagramme de classes UML, et un début d’implémentation en C# WPF (le prototype) qui servira à valider le modèle UML

Domaine d’application, marché et objectifsGéostatistique / Cartographie

Quels seront les utilisateurs du prototype et leur lienDéveloppeurs d’Articque qui le reprendront pour l’étudier et éventuellement l’intégrer dans la future version de Cartes&Données.

Quel est le besoin logicielPour la partie présentation : Afficher une grande quantité d’entités géographiques représentant un fond de carte (chargé à partir d’un fichier VXF) et de symboles superposés, organisées ou non. Possibilité de zoom et défilement sur la carte.

Pour la partie mise en page : Afficher tous les éléments présents sur la carte de la partie présentation, en ayant la possibilité de les déplacer indépendamment les uns des autres.

Quelles seront les conditions de mise en fonctionnement du logicielPour pouvoir utiliser le module d’affichage, il faut un fichier VXF et des représentations qui lui sont associées.

Rapport de stage de 4ème année :

Etude de la Windows Presentation Foundation (WPF) et réalisation d’un prototype de composant géographique chez

Articque

Résumé

Ce document relate le travail que j’ai réalisé pendant mon stage de 4ème année dans le centre de recherche et développement d’Articque. Cela commence par l’étude de la WPF (Windows Presentation Foundation), nouvelle technologie de développement d’interfaces graphiques, et la validation de son utilisation pour la réalisation d’un composant d’affichage cartographique. Ensuite vient l’étude de l’intégration d’une scène 3D temps réel au sein d’une application WPF, et l’affichage d’une carte complexe avec Direct3D. J’ai accessoirement réalisé un prototype de convertisseur de formats de fichiers géographique et, encore en cours de réalisation (stage pas encore fini), le prototype de composant d’affichage cartographique.

Mots-clés

WPF, Articque, géostatistique, composant cartographique, Direct3D

Abstract

This document describes the work that I realized during my 4th year internship in the research and development department of Articque. It starts with the study of the WPF (Windows Presentation Foundation), a new technology for developing graphical interfaces, and validation of its use for the realization of a component of map display. Then comes the study of integrating a real-time 3D scene within a WPF application, and display of a complex map with Direct3D. I have incidentally produced a prototype converter of geographic file formats, and still in progress (the internship is not yet finished), the prototype consisting of map display.

Keywords

WPF, Articque, geostatistics, cartographic component, Direct3D

Maitre de Stage :Christophe LebasResponsable R&D

Etudiant :Vincent ChicherieDI4 Année 2008-2009