Thème |
---|
Créer un modèle TechDraw à l'aide d'une macro Python |
Niveau |
Des connaissances de base en Python et de structures SVG sont utiles. |
Temps d'exécution estimé |
(ne sait pas) |
Auteurs |
FBXL5 |
Version de FreeCAD |
0.21 et plus |
Fichiers exemples |
None |
Voir aussi |
Macro TemplateHelper |
Ce tutoriel décrit comment générer un modèle simple à utiliser avec l'atelier TechDraw à partir de quelques lignes de code Python.
N'importe quel éditeur de texte peut être utilisé pour coder. Mon choix se porte sur Atom, mais l'éditeur intégré de FreeCAD fonctionne bien aussi.
Les exemples de code suivants peuvent être copiés et collés dans un fichier texte vide, puis enregistrés sous le nom de votre choix en tant que fichier *.py ou *.FCMacro.
Un modèle fournit un arrière-plan pour les tâches de dessin et ses dimensions sont utilisées par les pilotes d'imprimante pour mettre le dessin à l'échelle correctement.
Les modèles sont des fichiers svg et une macro doit donc composer quelques lignes de code svg (qui est un sous-ensemble du code xml).
Remarque : lorsque FreeCAD a été migré de freecadweb.org à freecad.org, cette page a été mise à jour en conséquence et le code SVG résultant n'est plus compatible avec les versions de FreeCAD antérieures à la v0.21. Pour ces versions, vous devez changer manuellement freecad.org
en freecadweb.org
à la ligne de déclaration de l'espace des noms dans le code SVG résultant, sinon les textes éditables ne sont pas reconnus.
Le format SVG est un sous-ensemble du format XML. C'est pourquoi un fichier SVG, comme tout fichier XML, se compose de deux parties :
L'en-tête n'est qu'une ligne pour déclarer quelle version du langage XML un interpréteur doit utiliser pour traiter les instructions du corps.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
Le corps commence par une balise d'ouverture qui contient des informations sur les espaces de nom et sur la taille du modèle et l'endroit où le placer. Et il se termine par une balise de fermeture.
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:freecad="http://www.freecad.org/wiki/index.php?title=Svg_Namespace"
width="420mm"
height="297mm"
viewBox="0 0 420 297">
</svg>
Pour une page blanche de taille DIN A3 en orientation paysage, c'est tout.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:freecad="http://www.freecad.org/wiki/index.php?title=Svg_Namespace"
width="420mm"
height="297mm"
viewBox="0 0 420 297">
</svg>
Le codage commence par un cadre contenant une fonction principale distincte :
#! python
# -*- coding: utf-8 -*-
# (c) 2024 Your name LGPL
def main():
"""Here is where the magic happens"""
return
if __name__ == '__main__':
# This will be true only if the file is "executed"
# but not if imported as module
main()
Le processus de création d'un modèle consiste à :
La macro est composée de plusieurs fonctions qui sont appelées à partir de la section principale.
Des fonctions supplémentaires peuvent être insérées avant la fonction EndSvg et les appels nécessaires sont placés avant l'appel à EndSvg().
Nous devons surveiller le nombre d'espaces utilisés avec les opérations d'écriture pour une indentation correcte.
Avant que le code ne soit généré, un dossier est nécessaire pour stocker le nouveau fichier modèle, et un nom de fichier doit être défini.
L'utilisateur doit avoir sélectionné un dossier de modèle. Son chemin est alors enregistré dans les préférences de TechDraw.
Il n'est pas nécessaire de savoir où sont stockées les préférences, car FreeCAD dispose de commandes permettant d'adresser directement les paramètres nécessaires.
def pathToTemplate(template_name):
"""Link a given template name to the path of the template folder"""
#- Get the path to the template folder that is set in the FreeCAD parameters
parameter_path = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/TechDraw/Files")
template_path = parameter_path.GetString("TemplateDir")
#- Link template_path and template_name for any OS
path_to_file = os.path.join(template_path, template_name) # to join path segments OS neutral
return path_to_file
parameter_path reçoit le chemin vers le "dossier" dans le fichier de configuration où se trouve le paramètre "TemplateDir".
template_path reçoit le contenu de "TemplateDir" qui est le chemin vers le répertoire du modèle.
template_name reçoit le nom du modèle à créer.
Maintenant, le nom du modèle doit être associé au chemin du modèle d'une manière qui soit compatible avec les systèmes d'exploitation basés sur unix et Windows.
Ceci est fait avec la commande "os.path.join" et stocké dans le template_file. Pour activer cette commande, une instruction "import os" est nécessaire.
Cette opération crée un nouveau fichier modèle et enregistre la ligne d'en-tête xml.
def createSvgFile(file_path):
# Create a file and insert a header line (with t as the space saving variant of template)
t = open(file_path, "w") # w = write, overwrites existing files
t.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>")
t.close
Cette instruction ajoute le fichier modèle et crée la balise d'ouverture svg, y compris ses attributs.
Chaque instruction d'écriture contient une seule ligne de code svg se terminant par "\n", le marqueur pour CR/LF.
def startSvg(file_path, sheet_width, sheet_height):
# Create svg-tag including namespace and format definitions
t = open(file_path, "a", encoding="utf-8")
# a = append, new lines are added at the end of an existing file
# encoding="utf-8", helps with special characters if the Python interpreter is in ASCII mode
t.write("\n" + "\n")
t.write("<svg\n")
#- Namespace declarations
t.write(" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n")
t.write(" xmlns:freecad=\"http://www.freecad.org/wiki/index.php?title=Svg_Namespace\"\n")
#- Format definition
t.write(" width =\"" + sheet_width + "mm\"\n")
t.write(" height=\"" + sheet_height + "mm\"\n")
t.write(" viewBox=\"0 0 " + sheet_width + " " + sheet_height + "\">\n")
# identical values for width and height and Viewbox' width and height
# will synchronise mm and svg-units
t.close
Cette instruction ajoute ensuite le fichier modèle et crée la balise de fermeture svg, ce qui termine le code du modèle.
def endSvg(file_path):
# Create closing svg-tag
t = open(file_path, "a", encoding="utf-8")
t.write("</svg>")
t.close
La fonction main() appelle les fonctions et transmet certains paramètres.
def main():
"""This one creates an empty A3 template"""
#- Set the name of the template file and get its location
template_file = pathToTemplate("MyTemplate.svg") # Change the template name here
#- Here starts the compiling of the svg file
createSvgFile(template_file) # overwrites existing File
#- Set sheet format (DIN A3)
format_width = "420"
format_height = "297"
startSvg(template_file, format_width, format_height) # adds svg start tag
endSvg(template_file) # adds svg end tag
# At this point a new SVG-file is generated and saved
return
Dans cet exemple, format_width
et format_height
sont des dimensions codées en dur, les deux lignes inutiles marquent les points où d'autres moyens de récupération des données de format pourraient placer leur contenu.
Cette macro se compose de segments de code comme ci-dessus, prêts à être exécutés.
#! python
# -*- coding: utf-8 -*-
# (c) 2024 Your name LGPL
import os # to enable the use of os.path.join()
# - SVG creation -
def createSvgFile(file_path):
# Create a file and insert a header line (with t as the space saving variant of template)
t = open(file_path, "w") # w = write, overwrites existing files
t.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>")
t.close
def startSvg(file_path, sheet_width, sheet_height):
# Create svg-tag including namespace and format definitions
t = open(file_path, "a", encoding="utf-8")
# a = append, new lines are added at the end of an existing file
# encoding="utf-8", helps with special characters if the Python interpreter is in ASCII mode
t.write("\n" + "\n")
t.write("<svg\n")
#- Namespace declarations
t.write(" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n")
t.write(" xmlns:freecad=\"http://www.freecad.org/wiki/index.php?title=Svg_Namespace\"\n")
#- Format definition
t.write(" width =\"" + sheet_width + "mm\"\n")
t.write(" height=\"" + sheet_height + "mm\"\n")
t.write(" viewBox=\"0 0 " + sheet_width + " " + sheet_height + "\">\n")
# identical values for width and height and Viewbox' width and height
# will synchronise mm and svg-units
t.close
def endSvg(file_path):
# Create closing svg-tag
t = open(file_path, "a", encoding="utf-8")
t.write("</svg>")
t.close
def pathToTemplate(template_name):
"""Link a given template name to the path of the template folder"""
#- Get the path to the template folder that is set in the FreeCAD parameters
parameter_path = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/TechDraw/Files")
template_path = parameter_path.GetString("TemplateDir")
#- Link template_path and template_name for any OS
path_to_file = os.path.join(template_path, template_name) # to join path segments OS neutral
return path_to_file
def main():
"""This one creates an empty A3 template"""
#- Set the name of the template file and get its location
template_file = pathToTemplate("MyTemplate.svg") # Change the template name here
#- Here starts the compiling of the svg file
createSvgFile(template_file) # overwrites existing File
#- Set sheet format (DIN A3)
format_width = "420"
format_height = "297"
startSvg(template_file, format_width, format_height) # adds svg start tag
endSvg(template_file) # adds svg end tag
# At this point a new SVG-file is generated and saved
return
if __name__ == '__main__':
# This will be true only if the file is "executed"
# but not if imported as module
main()
Pour faire un dessin à partir d'une page blanche, nous avons besoin de :
Normalement, ces éléments graphiques sont utilisés de manière répétée et le code de génération est donc divisé en quatre fonctions :
Toutes les fonctions sont placées à l'intérieur de la macro ci-dessus avant la fonction main() et leurs appels de fonction sont insérés dans la fonction main() entre startSvg(...)
et endSvg(...)
.
Pour dessiner un rectangle, il suffit d'appeler la fonction svgRect et de lui transmettre les valeurs de largeur, de hauteur et de position du coin supérieur gauche. C'est plus lisible à cet endroit que si svg_line contenait toute la ligne de code svg.
def svgRect(width, height, x, y):
# Generates an svg-instruction to draw a rectangle with the given values
svg_line = (
"<rect width=\"" + width + "\" height=\"" + height + "\" x=\"" + x
+ "\" y=\"" + y + "\" />"
)
return svg_line
L'instruction svg est divisée pour rester dans la longueur des lignes recommandée par Python, il en résultera néanmoins une seule ligne svg.
Pour dessiner une ligne, il suffit d'appeler la fonction svgPath et de fournir les coordonnées du point de départ et du point d'arrivée d'une ligne.
Au lieu des coordonnées du point final, nous pouvons remettre une étiquette pour dessiner une ligne horizontale (h) ou verticale (v) suivie de la longueur de la ligne ou l'étiquette pour dessiner une ligne horizontale (H) ou verticale (V) suivie de l'ordonnée x ou y du point final.
Chaque chemin commence à l'origine et la première action est un mouvement avec le "stylo levé" (pas de dessin) vers le point de départ. Dans ce cas, le mouvement relatif et le mouvement absolu sont identiques et il n'est donc pas important que l'étiquette m (m-tag? ndlt) soit en majuscule ou en minuscule.
def svgPath(x1, y1, x2, y2):
# Generates an svg-instruction to draw a path element (line) with the given values
if x2 == "v" or x2 == "V" or x2 == "h" or x2 == "H":
svg_line = ("<path d=\"m " + x1 + "," + y1 + " " + x2 + " " + y2 + "\" />")
else:
svg_line = ("<path d=\"m " + x1 + "," + y1 + " l " + x2 + "," + y2 + "\" />")
return svg_line
Pour dessiner un morceau de texte, il suffit d'appeler la fonction svgText et de lui fournir les coordonnées du point d'ancrage du texte, la chaîne de texte elle-même et, éventuellement, un angle pour le texte pivoté. Pour faire pivoter un texte, une instruction de transformation doit être insérée dans chaque balise de texte séparément ; les centres de rotation sont fixés aux mêmes coordonnées que les points d'ancrage du texte.
(L'alignement du texte est contrôlé par la balise de groupe qui l'entoure ou aligné à gauche par défaut).
def svgText(x, y, str_value, str_angle="0"):
"""
Generates an svg-instruction to place a text element with the given values.
Optional str_angle enables vertical and arbitrarily rotated texts
"""
if str_angle == "0":
svg_line = ("<text x=\"" + x + "\" y=\"" + y + "\">" + str_value + "</text>")
else:
svg_line = (
"<text x=\"" + x + "\" y=\"" + y + "\" transform=\"rotate(" + str_angle
+ "," + x + "," + y + ")\">" + str_value + "</text>"
)
return svg_line
Pour dessiner un morceau de texte éditable, il suffit d'appeler la fonction ediText et de lui fournir un nom, les coordonnées du point d'ancrage du texte, la chaîne de texte elle-même, et éventuellement un angle pour le texte pivoté. Pour faire pivoter un texte, une instruction de transformation doit être insérée dans chaque balise de texte séparément ; les centres de rotation sont fixés aux mêmes coordonnées que les points d'ancrage du texte.
FreeCAD crée un objet dictionnaire avec chaque modèle inséré et chaque entrée possède un nom (clé) et une valeur.
(L'alignement du texte est contrôlé par la balise de groupe qui l'entoure ou aligné à gauche par défaut).
def ediText(entry_name, x, y, str_value, str_angle="0"):
"""
Generates an svg-instruction to place an editable text element with the given values.
Optional str_angle enables vertical and arbitrarily rotated editable texts
"""
if str_angle == "0":
svg_line = (
"<text freecad:editable=\"" + entry_name + "\" x=\"" + x + "\" y=\"" + y
+ "\"> <tspan>" + str_value + "</tspan> </text>"
)
else:
svg_line = (
"<text freecad:editable=\"" + entry_name + "\" x=\"" + x + "\" y=\"" + y
+ "\" transform=\"rotate(" + str_angle + "," + x + "," + y + ")\"> <tspan>"
+ str_value + "</tspan> </text>"
)
return svg_line
Ces fonctions commencent par du code pour ouvrir un fichier en mode append et pour écrire la balise d'ouverture de groupe.
Suit une section permettant de définir et de calculer des valeurs, ainsi que des instructions d'écriture appelant les fonctions susmentionnées afin de générer du code svg.
Et enfin la balise de fermeture de groupe suivie d'une instruction pour fermer le fichier.
def createFrame(file_path, sheet_width, sheet_height):
# Creates rectangles for sheet frame and drawing area
t = open(file_path, "a", encoding="utf-8")
t.write(" <g id=\"drawing-frame\"\n")
t.write(" style=\"fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round\">\n")
#- upper left corner of inner Frame, drawing area
frame_x = str(20)
frame_y = str(10)
#- frame dimensions
frame_width = str(int(sheet_width) - 20 - 10)
frame_height = str(int(sheet_height) - 10 - 10)
#- frame rectangle
t.write(" " + svgRect(frame_width, frame_height, frame_x, frame_y) + "\n")
#- upper left corner outer frame, sheet frame
frame_x = str(15)
frame_y = str(5)
#- frame dimensions
frame_width = str(int(sheet_width)-20)
frame_height = str(int(sheet_height)-10)
#- frame rectangle
t.write(" " + svgRect(frame_width, frame_height, frame_x, frame_y) + "\n")
t.write(" </g>\n\n")
t.close
Cette macro ajoute certains éléments graphiques de base nécessaires à l'élaboration de modèles appropriés, à savoir des éléments de ligne, des textes et des textes modifiables.
#! python
# -*- coding: utf-8 -*-
# (c) 2024 Your name LGPL
import os # to enable the use of os.path.join()
# - SVG creation -
def createSvgFile(file_path):
# Create a file and insert a header line (with t as the space saving variant of template)
t = open(file_path, "w") # w = write, overwrites existing files
t.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>")
t.close
def startSvg(file_path, sheet_width, sheet_height):
# Create svg-tag including namespace and format definitions
t = open(file_path, "a", encoding="utf-8")
# a = append, new lines are added at the end of an existing file
# encoding="utf-8", helps with special characters if the Python interpreter is in ASCII mode
t.write("\n" + "\n")
t.write("<svg\n")
#- Namespace declarations
t.write(" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\"\n")
t.write(" xmlns:freecad=\"http://www.freecad.org/wiki/index.php?title=Svg_Namespace\"\n")
#- Format definition
t.write(" width =\"" + sheet_width + "mm\"\n")
t.write(" height=\"" + sheet_height + "mm\"\n")
t.write(" viewBox=\"0 0 " + sheet_width + " " + sheet_height + "\">\n")
# identical values for width and height and Viewbox' width and height
# will synchronise mm and svg-units
t.close
def endSvg(file_path):
# Create closing svg-tag
t = open(file_path, "a", encoding="utf-8")
t.write("</svg>")
t.close
def svgRect(width, height, x, y):
# Ggenerates an svg-instruction to draw a rectangle with the given values
svg_line = (
"<rect width=\"" + width + "\" height=\"" + height + "\" x=\"" + x
+ "\" y=\"" + y + "\" />"
)
return svg_line
def svgPath(x1, y1, x2, y2):
# Generates an svg-instruction to draw a path element (line) with the given values
if x2 == "v" or x2 == "V" or x2 == "h" or x2 == "H":
svg_line = ("<path d=\"m " + x1 + "," + y1 + " " + x2 + " " + y2 + "\" />")
else:
svg_line = ("<path d=\"m " + x1 + "," + y1 + " l " + x2 + "," + y2 + "\" />")
return svg_line
def svgText(x, y, str_value, str_angle="0"):
"""
Generates an svg-instruction to place a text element with the given values.
Optional str_angle enables vertical and arbitrarily rotated texts
"""
if str_angle == "0":
svg_line = ("<text x=\"" + x + "\" y=\"" + y + "\">" + str_value + "</text>")
else:
svg_line = (
"<text x=\"" + x + "\" y=\"" + y + "\" transform=\"rotate(" + str_angle
+ "," + x + "," + y + ")\">" + str_value + "</text>"
)
return svg_line
def ediText(entry_name, x, y, str_value, str_angle="0"):
"""
Generates an svg-instruction to place an editable text element with the given values.
Optional str_angle enables vertical and arbitrarily rotated editable texts
"""
if str_angle == "0":
svg_line = (
"<text freecad:editable=\"" + entry_name + "\" x=\"" + x + "\" y=\"" + y
+ "\"> <tspan>" + str_value + "</tspan> </text>"
)
else:
svg_line = (
"<text freecad:editable=\"" + entry_name + "\" x=\"" + x + "\" y=\"" + y
+ "\" transform=\"rotate(" + str_angle + "," + x + "," + y + ")\"> <tspan>"
+ str_value + "</tspan> </text>"
)
return svg_line
def createFrame(file_path, sheet_width, sheet_height):
# Creates rectangles for sheet frame and drawing area
t = open(file_path, "a", encoding="utf-8")
t.write(" <g id=\"drawing-frame\"\n")
t.write(" style=\"fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round\">\n")
#- calculate upper left corner of inner Frame, drawing area
frame_x = str(20)
frame_y = str(10)
#- frame dimensions
frame_width = str(int(sheet_width) - 20 - 10)
frame_height = str(int(sheet_height) - 10 - 10)
#- frame rectangle
t.write(" " + svgRect(frame_width, frame_height, frame_x, frame_y) + "\n")
#- calculate upper left corner outer frame, sheet frame
frame_x = str(15)
frame_y = str(5)
#- frame dimensions
frame_width = str(int(sheet_width)-20)
frame_height = str(int(sheet_height)-10)
#- frame rectangle
t.write(" " + svgRect(frame_width, frame_height, frame_x, frame_y) + "\n")
t.write(" </g>\n\n")
t.close
def createTitleBlock(file_path, sheet_width, sheet_height):
"""Creates a title block and transfers it to the position according to the sheet dimensions"""
#- calculate title block origin (lower left corner), offset from page origin
tbX = str(int(sheet_width) - 10 - 180) # 180 according to DIN EN ISO 7200
tbY = str(int(sheet_height) - 10)
t = open(file_path, "a", encoding="utf-8")
#- group to transfer all included title block elements at once
t.write(" <g id=\"titleblock\"\n")
t.write(" transform=\"translate(" + tbX + "," + tbY + ")\">\n")
#- sub-group of title block line framework
t.write(" <g id=\"titleblock-frame\"\n")
t.write(" style=\"fill:none;stroke:#000000;stroke-width:0.35;\
stroke-linecap:miter;stroke-miterlimit:4\">\n")
t.write(" " + svgPath(" 0"," 0"," 0","-63") + "\n")
t.write(" " + svgPath(" 0","-63","180"," 0") + "\n")
t.write(" " + svgPath(" 0","-30","h","155") + "\n")
t.write(" " + svgPath("155"," 0","v","-63") + "\n")
t.write(" </g>\n")
#- sub-group of title block static texts (left-aligned by default)
t.write(" <g id=\"titleblock-text-non-editable\"\n")
t.write(" style=\"font-size:5.0;text-anchor:start;fill:#000000;\
font-family:osifont\">\n")
t.write(" " + svgText(" 4.5","-43.5 ","Some static text") + "\n")
t.write(" " + svgText(" 4.5","-13.5 ","More static text") + "\n")
t.write(" " + svgText("162.5","-3.5 ","Vertical static text","-90") + "\n")
t.write(" </g>\n")
t.write(" </g>\n\n")
t.close
def createEditableText(file_path, sheet_width, sheet_height):
"""Creates editable texts positioned according to the page origin"""
#- calculate offset to titleblock origin
edX = int(sheet_width) - 10 - 180 # 180 according to DIN EN ISO 7200
edY = int(sheet_height) - 10
t = open(file_path, "a", encoding="utf-8")
#- group editable texts using the same attributes
t.write(" <g id=\"titleblock-editable-texts\"\n")
t.write(" style=\"font-size:7.0;text-anchor:start;fill:#0000d0;\
font-family:osifont\">\n")
t.write(
" " + ediText("EdiText-1",str(edX + 60),str(edY - 43.5),"Some editable text") + "\n"
)
t.write(
" " + ediText("EdiText-2",str(edX + 60),str(edY - 13.5),"More editable text") + "\n"
)
t.write(
" " + ediText("EdiText-3",str(edX + 173),str(edY - 4.5),"90° editable text","-90")
+ "\n"
)
t.write(" </g>\n\n")
t.close
def pathToTemplate(template_name):
"""Link a given template name to the path of the template folder"""
#- Get the path to the template folder that is set in the FreeCAD parameters
parameter_path = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/TechDraw/Files")
template_path = parameter_path.GetString("TemplateDir")
#- Link template_path and template_name for any OS
path_to_file = os.path.join(template_path, template_name) # to join path segments OS neutral
return path_to_file
def main():
"""This one creates an A3 template with simple frame and title block"""
#- Set the name of the template file and get its location
template_file = pathToTemplate("MyTemplate.svg") # Change the template name here
#- Here starts the compiling of the svg file
createSvgFile(template_file) # overwrites existing File
#- Set sheet format (DIN A3)
format_width = "420"
format_height = "297"
startSvg(template_file, format_width, format_height) # adds svg start tag
createFrame(template_file, format_width, format_height)
createTitleBlock(template_file, format_width, format_height)
createEditableText(template_file, format_width, format_height)
endSvg(template_file) # adds svg end tag
# At this point a new SVG-file is generated and saved
return
if __name__ == '__main__':
# This will be true only if the file is "executed"
# but not if imported as module
main()
Et voici le code svg qui sort de cette macro :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:freecad="http://www.freecad.org/wiki/index.php?title=Svg_Namespace"
width ="420mm"
height="297mm"
viewBox="0 0 420 297">
<g id="drawing-frame"
style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:round">
<rect width="390" height="277" x="20" y="10" />
<rect width="400" height="287" x="15" y="5" />
</g>
<g id="titleblock"
transform="translate(230,287)">
<g id="titleblock-frame"
style="fill:none;stroke:#000000;stroke-width:0.35;stroke-linecap:miter;stroke-miterlimit:4">
<path d="m 0, 0 l 0,-63" />
<path d="m 0,-63 l 180, 0" />
<path d="m 0,-30 h 155" />
<path d="m 155, 0 v -63" />
</g>
<g id="titleblock-text-non-editable"
style="font-size:5.0;text-anchor:start;fill:#000000;font-family:osifont">
<text x=" 4.5" y="-43.5 ">Some static text</text>
<text x=" 4.5" y="-13.5 ">More static text</text>
<text x="162.5" y="-3.5 " transform="rotate(-90,162.5,-3.5 )">Vertical static text</text>
</g>
</g>
<g id="titleblock-editable-texts"
style="font-size:7.0;text-anchor:start;fill:#0000d0;font-family:osifont">
<text freecad:editable="EdiText-1" x="290" y="243.5"> <tspan>Some editable text</tspan> </text>
<text freecad:editable="EdiText-2" x="290" y="273.5"> <tspan>More editable text</tspan> </text>
<text freecad:editable="EdiText-3" x="403" y="282.5" transform="rotate(-90,403,282.5)"> <tspan>90° editable text</tspan> </text>
</g>
</svg>
Et ce à quoi il devrait ressembler une fois inséré (avec un bloc titre agrandi) :
La coloration en bleu des textes modifiables est un choix personnel qui permet de distinguer plus facilement les textes statiques des textes modifiables sur le dessin fini.