26 mai 2026
C’est une excellente évolution pour ce projet, car elle est beaucoup plus simple qu’il n’y paraît. En réalité, votre interpréteur Logo ne dessine que des segments de droite. Un fichier SVG n’est finalement qu’un document XML contenant une liste de lignes.
L’idée générale est :
Programme Logo
↓
Interpréteur
↓
Move::doExecute()
↓
drawLine(...)
↓
SVG
Au lieu de dessiner dans une fenêtre SFML, on enregistre les segments dans un fichier.
Toute la logique graphique passe par :
Move::doExecute()qui calcule :
oldX
oldY
turtleX
turtleYpuis appelle :
drawLine(oldX, oldY, turtleX, turtleY, turtleColor);Le point clé est que :
Movene dépend pas de SFML.
Il demande simplement :
« Dessine un segment entre ces deux points ».
Aujourd’hui :
namespace turtle
{
void drawLine(...);
}fait :
lines.append(...)dans un :
sf::VertexArrayPour produire un SVG, il suffit de changer l’implémentation de :
drawLine()Créer :
struct Segment
{
double x1;
double y1;
double x2;
double y2;
unsigned char r;
unsigned char g;
unsigned char b;
};Puis :
std::vector<Segment> segments;dans Turtle.cpp.
Modifier :
void drawLine(...)pour faire :
Segment s;
s.x1 = x1;
s.y1 = y1;
s.x2 = x2;
s.y2 = y2;
s.r = color[0];
s.g = color[1];
s.b = color[2];
segments.push_back(s);À ce stade :
Créer :
void saveSvg(std::string const& filename)Par exemple :
#include <fstream>void saveSvg(std::string const& filename)
{
std::ofstream os(filename);
os << "<?xml version=\"1.0\"?>\n";
os << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
"width=\"1000\" height=\"1000\">\n";
...
}Pour chaque élément :
for(const auto& s : segments)écrire :
os
<< "<line "
<< "x1=\"" << s.x1 << "\" "
<< "y1=\"" << s.y1 << "\" "
<< "x2=\"" << s.x2 << "\" "
<< "y2=\"" << s.y2 << "\" "
<< "stroke=\"rgb("
<< int(s.r) << ","
<< int(s.g) << ","
<< int(s.b)
<< ")\" "
<< "stroke-width=\"1\" />\n";Ajouter :
os << "</svg>\n";Le fichier obtenu ressemblera à :
<svg xmlns="http://www.w3.org/2000/svg">
<line x1="0"
y1="0"
x2="100"
y2="0"
stroke="rgb(0,0,0)" />
<line x1="100"
y1="0"
x2="100"
y2="100"
stroke="rgb(0,0,0)" />
</svg>Attention :
dans votre moteur :
(0,0)
|
|
V
l’origine est au centre de la fenêtre SFML.
Dans SVG :
(0,0) ------------------>
|
|
|
V
l’origine est en haut à gauche.
Il faut donc transformer les coordonnées.
Par exemple :
double svgX(double x)
{
return x + 500;
}
double svgY(double y)
{
return 500 + y;
}pour centrer le dessin.
Puis :
x1 = svgX(s.x1);
y1 = svgY(s.y1);Dans main() :
Aujourd’hui :
while (...)
{
interpreter.nextStep();
}Lorsque le programme est terminé :
saveSvg("output.svg");Une évolution élégante consiste à séparer :
Interpréteur Logo
↓
Backend graphique
Créer une abstraction :
class DrawingBackend
{
public:
virtual ~DrawingBackend() = default;
virtual void drawLine(...) = 0;
};Puis :
class SfmlBackend : public DrawingBackendet
class SvgBackend : public DrawingBackendAinsi :
Logo
↓
Move
↓
DrawingBackend
↓
├── SFML
└── SVG
On peut alors choisir :
logo prog.logopour l’affichage interactif,
ou
logo prog.logo dessin.svgpour une génération SVG.
Pour un étudiant de deuxième année, je conseillerais :
struct Segment.std::vector<Segment> segments.drawLine() pour enregistrer les segments.saveSvg().saveSvg("output.svg") à la fin du
programme.Cela représente environ 100 lignes de code et ne
nécessite pratiquement aucune modification de l’interpréteur lui-même.
L’ensemble du travail est concentré dans Turtle.cpp et
quelques lignes dans main.cpp.