Pour éviter les conflits avec Geoman pour ce poc. L'édition avec Geoman est exclusif par rapport au mode d'édition sans geoman.
L'accordéon à gauche représente les figures tactiques qui ont été classées par mode d'édition (à 2, 3, 4, N points et selon la signification contextuelle des points)
En fonction du travail qui a été fourni j'ai mis des tags sur le menu en accordéon:
- réactif : lorsqu'on commence à faire un tracé la génération de la forme suit le mouvement de la souris pour le dernier point.
- intuitif : pareil que réactif mais en essayant d'anticiper les points qui vont être saisis. Les intéractions qui ont été les plus étudiées.
- prioritaire : contient l'un des symboles marqués prioritaires. l'édition est au moins réactive, au mieux intuitive.
- si pas de tag : le cas n'a pas été étudié néanmoins l'édition reste testable. le tracé se boucle en 4 points (si demande moins de clics il faudra tout de même saisir 4 clics pour que la forme soit enregistrée).
TL;DR;
dans le menu accordéon
-
choisir LINE29 puis cliquer sur la figure à représenter
-
cliquer sur la carte 3 fois pour placer les 3 points caractéristiques.
-
à l'issue de la création, la figure tactique est convertie en géométrie compatible Geoman et importée par Geoman.
-
si on reclique sur la carte on recommence la création d'une nouvelle figure tactique
-
si on clique sur n'importe quel bouton de Geoman, on quitte le mode d'édition mil-sym pour passer en mode d'édition Geoman. si l'on souhaite repasser en mode d'édition mil-sym (voir en bas à droite) il suffit qu'aucun bouton de geoman ne soit séléctionné
GeoJSON généré
Pour la suite j'appelerai figure tactique l'élément généré par cette librairie.
Lorsqu'on crée une figure tactique voici le GeoJson généré.
Il contient généralement 3 entités:
- un
MultiLineString qui contient les ensembles de segments, ou lignes pour dessiner notre symbole
- un ou plusieurs
Point qui contient l'emplacement des libellés à afficher
- une entité vide de type
Polygon qui contient les métadonnées spécifiques à notre
graphique.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
// propriétés de styles qui pourront être surchargée ou
// utilisées
"label": "",
"strokeColor": "#000000",
"lineOpacity": 1,
"lineCap": 2,
"strokeWidth": 3,
"strokeWeight": 3
},
// méta donnée utiles
"style": {
"stroke": "#000000",
"line-opacity": 1,
"stroke-linecap": "square",
"stroke-width": 3
},
"geometry": {
"type": "MultiLineString",
"coordinates": [
[
// 1er segment
[36.86057405, 47.39898876],
[36.96153387, 47.25571054]
],
[
// 2e segment
[36.91105396, 47.32734965],
[36.72017681, 47.26427537]
],
]
}
},
{
"type": "Feature",
"properties": {
"label": "C",
"pointRadius": 0,
"fontColor": "#000000",
"fontSize": "12pt",
"fontFamily": "arial, sans-serif",
"fontWeight": "bold",
"labelAlign": "center",
"labelBaseline": "alphabetic",
"labelXOffset": 0,
"labelYOffset": 0,
"labelOutlineColor": "#FFFFFF",
"labelOutlineWidth": 4,
"rotation": -25.99401580396322,
"angle": -25.99401580396322
},
"geometry": { "type": "Point", "coordinates": [36.81457831, 47.29694342] }
},
{
"type": "Feature",
"geometry": { "type": "Polygon", "coordinates": [] },
"properties": {
"id": "ID",
"name": "Name",
"description": "description",
"symbolID": "130325000034050000000000000000",
"wasClipped": "false"
}
}
]
}
Compatibilité avec Geoman
Pour le moment limitée à cause du type de géométrie générée.
Ces limitations ne sont pas spécifiques à mil-sym-ts mais plutôt associées à Geoman. (je ne vois pas tellement comment une librairie pourrait représenter des figures tactiques de manière plus simple)
Pour le moment Geoman, n'accepte pas les MultiLineString on doit donc créer une feature par LineString. On se retrouve donc avec autant d'objets que de traits de crayon.

On pourrait cependant envisager que Geoman puisse intégrer le type MultiLineString.
Il y a des chances qu'une PR sur Geoman puisse les intéresser.
Reste le problème des points pour les champs texte qui seront obligatoirement dans une feature séparée.
Une solution ici aussi serait de grouper les features ayant une propriété en commun (ex: groupId) et que les modifications de type translation, rotation, mise à l'échelle tiennent compte du groupement des éléments dans Geoman.
Ici aussi une PR serait à envisager.
Compatibilité collaboratif.
Selon la specification GeoJson, une feature ne peut pas regrouper des éléments de type différent : un point avec une ligne. Or une figure tactique contient généralement un MultiLineString (qui a été dégroupé pour le moment pour être compatible Geoman) éventuellement un Polygon et des points pour chaque label.
2 solutions:
- on pourrait envisager de reconstituer le groupement via une
FeatureCollection juste pour la partie collaboratif.
- on considère chaque élément comme une entité séparée : chacun ayant un uuid propre et générant sont chunk. (pour certaines figures tactiques on peut se retrouver avec 10 chunks facilement)
Taille de la librairie
la taille de la librairie ne devrait pas être un facteur limitant dans la mesure où le code est chargé en local, mais tout de même.
La librairie a été bundlée avec Webpack en commonjs donc pas de possibilité de faire du tree-shake.
Exemple avec la capture où j'ai écrit un hello world de 15 lignes. npm run build, boum 7.5Mo.

En cause des fichiers de données json de 30_000 lignes qui sont packagés dans le js.
svgd.json / svge.json: d comme 2525d et e comme 2525e.

si on choisit d'utiliser la librairie, pour un besoin limité je pense que devrait forker la librairie et faire un build custom avec uniquement ce dont on a besoin.
- on migre
webpack vers tsdown pour une compatibilité esm.
- on vide les fichiers de données
2525d.
APP-6D vs MIL-STD-2525
la bibliothèque utilise le standard américain. MIL-STD-2525. 2 versions sont disponibles
2525D 15 caractères
2525E 30 caractères
2525E est très proche du standard OTAN APP-6D qui est utilisé pour milsymbol et en plus c'est la plus récente. On choisira donc tout le temps la version 2525E.
// APP-6D utilisé partout ailleurs dans le playground
export function generateSidc(sidc: Partial<Sidc>) {
const {
version = "10",
context = "0",
standardIdentity = "0",
symbolSet = "00",
status = "0",
hqtfd = "0",
symbolSetAmplifier = "00",
entity = "000000",
modifier1 = "00",
modifier2 = "00",
} = sidc;
return `${version}${context}${standardIdentity}${symbolSet}${status}${hqtfd}${symbolSetAmplifier}${entity}${modifier1}${modifier2}`;
}
// 2525E utilisé pour cet exemple
export function buildSymbolID(basicID: string) {
const version = 13;
const context = "0"; // 0-reality
const affiliation = "3"; // 3-friendly
const basicIdPrefix = basicID.substring(0, 2);
const status = "0"; // 0-present
const hqtfd = "0"; // 0-unknown
const amp = "00"; // 00-unknown
const basicIdSuffix = basicID.substring(2); // 6 chars
// extra --------
const s1Mod = "00";
const s2Mod = "00";
const lbS1 = "0";
const lbS2 = "0";
// 2525E has frame shape and 4 reserved positions
// 2525D has 5 reserved positions
const frame = version >= 13 ? "0" + "0000" : "00000";
const labels = "000";
const id = `${version}${context}${affiliation}${basicIdPrefix}${status}${hqtfd}${amp}${basicIdSuffix}${s1Mod}${s2Mod}${lbS1}${lbS2}${frame}${labels}`;
return id;
}