Editeur de courbes

Soyez le premier à donner votre avis sur cette source.

Vue 9 954 fois - Téléchargée 1 338 fois

Description

Cette application Java permet de créer, éditer et visualiser des courbes sur un graphe.

Les courbes peuvent être de 3 types :

- Cartésienne
- Paramétrique
- Polaire

L'équation de chaque courbe est définie par l'utilisateur. Elle se compose d'1 ou 2 fonctions suivant le type de l'équation.

Pour compiler les fonctions, j'ai utilisé JavaCC (Java Compiler Compiler) qui permet de générer un compilateur à partir d'une grammaire.

Grammaire simplifiée des fonctions :

variable (x ou t)
nombre
fonction de base (sin, cos, exp, pow, ...)
parenthèses
+, *, /, -
constantes usuelles : pi ou e

Les erreurs de syntaxe sont signalées.

D'une manière générale, la touche entrée permet de valider les champs. Ceci, afin de ne pas surcharger la présentation.

Les fonctions de base font appel, par introspection, aux fonctions définies dans le package fr.guehenneux.graphe.fonction.dictionnaire. On peut donc en ajouter autant qu'on veut.

Le sélecteur de couleurs n'est pas celui de Java, j'en ai refait un qui est moins évolué.

Le tracé des courbes n'est pas très rapide car les fonctions sont compilées à un haut niveau. Selon votre processeur, éviter les courbes contenant trop de points.

L'application tente d'appliquer par défaut le Look And Feel Nimbus, qui est vraiment pas mal bien qu'un peu encombrant.

Source / Exemple :


package fr.guehenneux.graphe.presentation.graphe;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.util.List;

import fr.guehenneux.graphe.Graphe;
import fr.guehenneux.graphe.courbe.Courbe;
import fr.guehenneux.utilitaire.swing.PanneauTampon;

/**

  • @author guehenneux
  • /
public class PanneauGraphe extends PanneauTampon { /**
  • UID genere le 15/06/2010
  • /
private static final long serialVersionUID = -5006186588671314234L; private static final int LARGEUR_MINIMUM = 400; private static final int LARGEUR_IDEALE = 400; private static final int HAUTEUR_MINIMUM = 300; private static final int HAUTEUR_IDEALE = 300; private static final Dimension DIMENSION_MINIMUM = new Dimension( LARGEUR_MINIMUM, HAUTEUR_MINIMUM); private static final Dimension DIMENSION_IDEALE = new Dimension( LARGEUR_IDEALE, HAUTEUR_IDEALE); private PanneauCoordonnees panneauCoordonnees; private Graphe graphe; /**
  • @param graphe
  • @param panneauCoordonnees
  • /
public PanneauGraphe(Graphe graphe, PanneauCoordonnees panneauCoordonnees) { super(false); this.graphe = graphe; this.panneauCoordonnees = panneauCoordonnees; setBackground(Color.WHITE); setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); setPreferredSize(DIMENSION_IDEALE); setMinimumSize(DIMENSION_MINIMUM); new EcouteurGraphe(this); } @Override public void dessiner() { /*
  • dessin des axes
  • /
Shape axeX = getAxeX(); Shape axeY = getAxeY(); graphique.setColor(Color.DARK_GRAY); graphique.draw(axeX); graphique.draw(axeY); /*
  • dessin des courbes
  • /
AffineTransform transformationAffine = getTransformationAffine(); List<Courbe> courbes = graphe.getCourbes(); Shape formeCourbe; for (Courbe courbe : courbes) { graphique.setColor(courbe.getCouleur()); formeCourbe = courbe.getForme(); formeCourbe = transformationAffine .createTransformedShape(formeCourbe); graphique.draw(formeCourbe); } } /**
  • @return la transformation affine permettant d'adapter les coordonnees du
  • graphe aux coordonnees de l'ecran
  • /
private final AffineTransform getTransformationAffine() { /*
  • on recupere la fenetre du graphe
  • /
double xMin = graphe.getXMin(); double xMax = graphe.getXMax(); double yMin = graphe.getYMin(); double yMax = graphe.getYMax(); /*
  • transformation affine du graphe
  • /
AffineTransform transformationAffine = AffineTransform .getScaleInstance(largeur / (xMax - xMin), hauteur / (yMin - yMax)); transformationAffine.translate(-xMin, -yMax); return transformationAffine; } /**
  • @return
  • /
private final Shape getAxeX() { /*
  • parametres de l'axe
  • /
double xMin = graphe.getXMin(); double xMax = graphe.getXMax(); double graduationX = graphe.getGraduationX(); /*
  • forme de l'axe
  • /
GeneralPath axeX = new GeneralPath(); /*
  • transormation affine pour passer des coordonnees du graphe aux
  • coordonnees de l'ecran
  • /
AffineTransform transformationAffine = getTransformationAffine(); /*
  • ligne de l'axe
  • /
Point2D minAxeGraphe = new Point2D.Double(xMin, 0); Point2D maxAxeGraphe = new Point2D.Double(xMax, 0); Point2D minAxeEcran = new Point2D.Double(); Point2D maxAxeEcran = new Point2D.Double(); transformationAffine.transform(minAxeGraphe, minAxeEcran); transformationAffine.transform(maxAxeGraphe, maxAxeEcran); axeX.append(new Line2D.Double(minAxeEcran, maxAxeEcran), false); /*
  • graduations de l'axe
  • /
Point2D pointGraduationGraphe; Point2D pointGraduationEcran; Line2D graduation; double x; /*
  • graduations positives
  • /
for (x = graduationX; x <= xMax; x += graduationX) { pointGraduationGraphe = new Point2D.Double(x, 0); pointGraduationEcran = new Point2D.Double(); transformationAffine.transform(pointGraduationGraphe, pointGraduationEcran); graduation = new Line2D.Double(pointGraduationEcran.getX(), pointGraduationEcran.getY(), pointGraduationEcran.getX(), pointGraduationEcran.getY() - 3); axeX.append(graduation, false); } /*
  • graduations negatives
  • /
for (x = -graduationX; x >= xMin; x -= graduationX) { pointGraduationGraphe = new Point2D.Double(x, 0); pointGraduationEcran = new Point2D.Double(); transformationAffine.transform(pointGraduationGraphe, pointGraduationEcran); graduation = new Line2D.Double(pointGraduationEcran.getX(), pointGraduationEcran.getY(), pointGraduationEcran.getX(), pointGraduationEcran.getY() - 3); axeX.append(graduation, false); } return axeX; } /**
  • @return
  • /
private final Shape getAxeY() { /*
  • parametres de l'axe
  • /
double yMin = graphe.getYMin(); double yMax = graphe.getYMax(); double graduationY = graphe.getGraduationY(); /*
  • forme de l'axe
  • /
GeneralPath axeY = new GeneralPath(); /*
  • transormation affine pour passer des coordonnees du graphe aux
  • coordonnees de l'ecran
  • /
AffineTransform transformationAffine = getTransformationAffine(); /*
  • ligne de l'axe
  • /
Point2D minAxeGraphe = new Point2D.Double(0, yMin); Point2D maxAxeGraphe = new Point2D.Double(0, yMax); Point2D minAxeEcran = new Point2D.Double(); Point2D maxAxeEcran = new Point2D.Double(); transformationAffine.transform(minAxeGraphe, minAxeEcran); transformationAffine.transform(maxAxeGraphe, maxAxeEcran); axeY.append(new Line2D.Double(minAxeEcran, maxAxeEcran), false); /*
  • graduations de l'axe
  • /
Point2D pointGraduationGraphe; Point2D pointGraduationEcran; Line2D graduation; double y; /*
  • graduations positives
  • /
for (y = graduationY; y <= yMax; y += graduationY) { pointGraduationGraphe = new Point2D.Double(0, y); pointGraduationEcran = new Point2D.Double(); transformationAffine.transform(pointGraduationGraphe, pointGraduationEcran); graduation = new Line2D.Double(pointGraduationEcran.getX(), pointGraduationEcran.getY(), pointGraduationEcran.getX() + 3, pointGraduationEcran .getY()); axeY.append(graduation, false); } /*
  • graduations negatives
  • /
for (y = -graduationY; y >= yMin; y -= graduationY) { pointGraduationGraphe = new Point2D.Double(0, y); pointGraduationEcran = new Point2D.Double(); transformationAffine.transform(pointGraduationGraphe, pointGraduationEcran); graduation = new Line2D.Double(pointGraduationEcran.getX(), pointGraduationEcran.getY(), pointGraduationEcran.getX() + 3, pointGraduationEcran .getY()); axeY.append(graduation, false); } return axeY; } /**
  • @param x0
  • @param y0
  • @param x1
  • @param y1
  • /
public final void grossir(int x0, int y0, int x1, int y1) { AffineTransform transformationAffine = getTransformationAffine(); Point2D coinCadre0 = new Point2D.Double(x0, y0); Point2D coinCadre1 = new Point2D.Double(x1, y1); Point2D coinGraphe0 = new Point2D.Double(); Point2D coinGraphe1 = new Point2D.Double(); try { transformationAffine.inverseTransform(coinCadre0, coinGraphe0); transformationAffine.inverseTransform(coinCadre1, coinGraphe1); double xMin = Math.min(coinGraphe0.getX(), coinGraphe1.getX()); double yMin = Math.min(coinGraphe0.getY(), coinGraphe1.getY()); double xMax = Math.max(coinGraphe0.getX(), coinGraphe1.getX()); double yMax = Math.max(coinGraphe0.getY(), coinGraphe1.getY()); graphe.setXMin(xMin); graphe.setYMin(yMin); graphe.setXMax(xMax); graphe.setYMax(yMax); graphe.actualiserFenetre(); } catch (NoninvertibleTransformException erreur) { } recalculerImage(); } /**
  • @param xEcran
  • @param yEcran
  • /
public final void actualiserCoordonneesCurseur(int xEcran, int yEcran) { Point2D curseurEcran = new Point2D.Double(xEcran, yEcran); Point2D curseurGraphe = new Point2D.Double(); AffineTransform transformationAffine = getTransformationAffine(); try { transformationAffine.inverseTransform(curseurEcran, curseurGraphe); panneauCoordonnees.setX(curseurGraphe.getX()); panneauCoordonnees.setY(curseurGraphe.getY()); } catch (NoninvertibleTransformException erreur) { } } }

Conclusion :


Application basique, mais à mon avis bien conçue. Elle peut être facilement enrichie :
multithreading, calcul de min, max locaux, intersections, bibliothèques de courbes...

Codes Sources

A voir également

Ajouter un commentaire Commentaires
excellent travail!..
Salut tout le monde
Merci beaucoup pour cette source
ça va beaucoup m'aider pour mon projet
T'es une sorte de génie lol

A plus ;)
Messages postés
519
Date d'inscription
mercredi 21 mars 2007
Statut
Membre
Dernière intervention
19 décembre 2016
25
Bonjour,

Dans le package utilitaire, beaucoup de classes ne sont pas utilisées, il n'est donc pas indispensable qu'elles soient compilées et intégrées au jar. En revanche, bien que les classes situées dans le package dictionnaire ne soient pas directement référencées, il faut forcer leur intégration dans le jar. En effet, elles sont instanciées par introspection en se basant sur le nom des fonctions saisies : cos, sin, sqrt...

En ce moment, je n'ai plus de temps libre, mais j'ai commencé à travailler sur une nouvelle version, incluant une meilleure gestion des erreurs et des saisies de l'utilisateur. Je la mettrai à jour dès que possible.

Pour le titre de la fenêtre c'est normal ; le fichier EditeurGraphe.java n'est pas à jour (celui du jar est plus récent).
Messages postés
3
Date d'inscription
mardi 31 octobre 2006
Statut
Membre
Dernière intervention
6 juillet 2010

Bonjour et merci pour tes conseils. Effectivement je compile sans erreur après avoir appliquer ce patch. J'ai généré le jar il se lance bien mais je ne peux tracer aucune équation et la fenêtre de l'application est titrée Fenêtre de test. J'ai comparé les jar et me suis aperçu qu'il y a des écarts significatifs BigFraction.class et FractionLong.class ne sont pas générés, alors que j'ai bien les classes.java. Je n'ai pas embarqué non plus le répertoire Dictionnaire. A ce stade, je pense que le problème est de mon côté. Bon je vais poursuivre les investigations et en tout cas je te remercie pour ton implication.
Messages postés
519
Date d'inscription
mercredi 21 mars 2007
Statut
Membre
Dernière intervention
19 décembre 2016
25
Et bien tu remplaces le contenu de la classe RenduListeCourbes par :

/**
*
* @author guehenneux
*
*/
public class RenduListeCourbes implements ListCellRenderer {

private static final DefaultListCellRenderer RENDU_DEFAUT = new DefaultListCellRenderer();

/**
* la largeur est donnee par la liste contenant la cellule
*/
private static final Dimension DIMENSION_OPTIMALE = new Dimension(0, 20);

private static RenduListeCourbes instance;

/**
*
* @return
*/
public static synchronized RenduListeCourbes getInstance() {

if (instance == null) {
instance = new RenduListeCourbes();
}

return instance;

}

/**
* constructeur prive pour appliquer le patron de conception Singleton
*/
private RenduListeCourbes() {

}

@Override
public Component getListCellRendererComponent(
JList courbes, Object courbe, int indexCourbe,
boolean courbeSelectionnee, boolean focus) {

JLabel cellule = (JLabel) RENDU_DEFAUT.getListCellRendererComponent(
courbes, courbe, indexCourbe, courbeSelectionnee, focus);

if (courbe != null) {

cellule.setForeground(((Courbe) courbe).getCouleur());
cellule.setPreferredSize(DIMENSION_OPTIMALE);

}

return cellule;

}

}

Ça devrait corriger au moins quelques erreurs. Si tu en as d'autres, dis-le moi. Il ne faut pas avoir peur d'installer le jdk 1.7, il fonctionne bien et la jvm est sensiblement plus rapide. Après si tu utilises ton PC pour le boulot c'est peut-être déconseillé.
Afficher les 17 commentaires

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.