PM et Déport

abscisse curviligne et déport

Cet exercice va porter sur une demande courante sur les forums d'assistance car elle n'existe pas en natif et certains métiers se servent de ces données.
Il va être question de trouver par rapport à une entité le déport qui est la distance de projection du point sur cette entité, la distance la plus courte étant la perpendiculaire sur l'entité issue du point concerné, et l'abscisse curviligne que je vais nommer PM comme Point Métrique.
Ce schéma vous présente chacun des intervenants :

 

L'entité peut être courbe ou pas, l'abscisse curviligne étant la distance développée suivant l'entité depuis le point d'origine de cette dernière.

On différencie la valeur de déport suivant qu'elle à droite ou à gauche de l'entité dans le sens de construction de l'entité, par convention le déport est positif à droite et négatif à gauche.
Les points situés AVANT ou APRÈS l'entité dans le sens de création peuvent être sélectionnées dans le jeu initial mais seront testés et ne seront pas traités pour extraction dans le fichier CSV. il ny a pas de PM négatif ou supérieur à la longueur de l'entité.
Et pour finir ces données seront enregistrées dans un fichier CSV qui présente l'avantage d'être un fichier ascii facilement gérable en AutoLisp mais tout de même lisible par Excel.

En préambule j'aimerais dire que cet exemple a été écrit suite à une demande récente (juin 2020),
il répond à cette demande mais devra être amélioré pour devenir plus robuste,
quand ce sera fait je mettrai cette page à jour.

Passons au pseudo-code :

Sélection de l'entité qui représente l'axe de référence, transformation en object vla, en trouver les points de départ et de fin  et la longueur de cette entité.
La longueur est nécessairement connue car si des points sont "après" la fin de l'entité ou "avant" ils ne doivent pas être pris en compte.
Ensuite on va sélectionner les blocs des points, ce sont dans l'exemple des points avec attributs dont le premier est le matricule du point.
Détermination du point projeté sur l'entité, obtention de la distance de ce point projeté depuis le début de l'entité, on tient là notre PM (abscisse curviligne)
Obtention de la distance du point à traiter jusqu'au point de PM (point projeté à l'instant) et on a la valeur de déport.
Il va falloir vérifier si le point est à droite ou a gauche de l'entité "axe", il existe plusieurs façon et naturellement j'ai écrit la mienne, j'ai choisi de calculer le point de début du segment sur lequel se trouve le point projeté (pour PM) en trouvant le numéro (entier) du paramètre extrait du paramètre (nombre réel) du point projeté.
Si le triangle "point début de segment"  "point de PM" et "point à traiter" a une superficie négative ces trois points sont dans le sens horaire, c'est de la géométrie analytique.
Ce sens de rotation nous indique si le point est à droite ou à gauche et si c'est à gauche on transforme en négatif la valeur du déport.
Pour la beauté de la chose j'ai choisi de dessiner un vecteur temporaire ( grdraw )  rouge pour un point à droite et vert pour un point à gauche.
Création d'un fichier texte portant le nom du dessin encours dans le répertoire du dessin en cours mais avec l'extension CSV.
Et pour finir affichage d'une case d'alerte ( alert ) annonçant le nombre de points écrits dans le fichier et servant d'annonce de fin du programme.
Dans le code qui suit j'ai inséré tous les commentaires que je pense nécessaires à la compréhension du traitement, dîtes-moi si c'est insuffisant...

 

Et maintenant le code à proprement parler :

( defun c:DA_Ent_PM_Deport ( / att axeval long jeupoints n pt ptpm pm ptav ecart fich )
( defun da:horaire ( a b c )
   ( * 
      ( - ( + ( + ( - ( - ( * ( car b ) ( cadr c ) ) ( * ( cadr b ) ( car c ) ) ) ( * ( car a ) ( cadr c ) ) )
      ( * ( cadr a ) ( car c ) ) ) ( * ( car a ) ( cadr b ) ) ) ( * ( cadr a ) ( car b ) ) )
0.5 )
) ;_ Fin de defun da:horaire calcul de la superficie du triangle formé par les trois points
 ; en arguments, si cette superficie est négative les points sont donc exprimés en sens horaire

( setq dec ; variable qui gère le nombre de décimales dans le fichier extrait
           compteur 0 ; variable qui compte les points traités pour affichage à la fin
)
( setq axe ( car ( entsel "\nChoix de l'entité d'axe...\n" ) ) ) ; choix de l'entité axe
( setq axevla ( vlax-ename->vla-object axe ) ) ; transformation en object vla
( setq long ( vlax-get-property axevla 'Length ) ) ; longueur de l'entité

( prompt "\nChoix des points à traiter" ) ; affichage d'un message en ligne de commande
;création d'un jeu de sélection avec filtre sur entités BLOC et NOM du BLOC
( setq jeupoints ( ssget ( list ( cons 0 "INSERT" ) ( cons 2 "tcpoint" ) ) ) )
; création du nom complet du fichier d'export depuis le nom du dessin en cours,
; même nomque le dessin même répertoire mais avec l'extension CSV

( setq nom ( strcat ( getvar "dwgprefix" ) ( getvar "dwgname" ) ) )
( setq nom ( strcat ( substr nom 1 ( - ( strlen nom ) 4 ) ) ".csv" ) )
; ouverture de ce fichier en écriture

( setq fich ( open nom "w" ) )
; écriture dans ce fichier de la ligne d'entête chaque champ est séparé par un point-virgule
; car c'est le format CSV qui permet de créer les colonnes dans Excel

( write-line ( strcat "Numéro;PM;Déport;X Point;Y Point;X PM;Y PM" ) fich )

( setq n -1 ) ; variable pour trouver une entité par sa position dans un jeu de sélection
( repeat ( sslength jeupoints ) ; répéter autant de fois que le jeu contient d'entités
; pt -> point d'insertion du bloc
; att -> valeur du premier attribut du bloc (entnext)
; ptpm -> point projeté perpendiculairement depuis le bloc sur l'entité
; pm -> distance (curviligne) depuis le début de l'entité
   ( setq pt ( cdr ( assoc 10 ( entget ( ssname jeupoints ( setq n ( 1+ n ) ) ) ) ) )
             att ( cdr ( assoc 1 ( entget ( entnext ( ssname jeupoints n ) ) ) ) )
             ptpm ( vlax-curve-getClosestPointTo axevla pt )
             pm ( vlax-curve-getDistAtPoint axevla ptpm )
   )
; SI pm est plus grand que zéro
; ET Pm plus petit que la longueur
; ET pm est différent de zéro à 0.0000001 près (fuzz)

   ( if ( and ( > pm 0 ) ( < pm long ) ( not ( equal ( - long pm ) 0 0.0000001 ) ) )
      ( progn ; car plusieurs instructions dans un IF
; ptav est le point au paramètre précédent le point projeté sur l'entité

         ( setq ptav  ( vlax-curve-getpointatparam axevla
                                ( fix ( vlax-curve-getParamAtDist axevla pm ) ) ) )
         
; si le résultat renvoyé par da:horaire est négatif 
          ( if ( not ( minusp ( da:horaire ptav ptpm pt ) ) )
             ( progn ; car plusieurs instructions dans un IF
                 ; faire passer la valeur "ecart" en négatif

                 ( setq ecart ( * -1 ( distance ptpm pt ) ) )
                 ; dessiner un "vecteur" de couleur verte depuis ptpm jusqu'à pt

                 ( grdraw ptpm pt 3 )
                 ; écrire la ligne contenant la concaténation (strcat) des valeurs dans le fichier "fich"

                 ( write-line ( strcat att ";" ( rtos pm 2 dec ) ";" ( rtos ecart 2 dec ) ";"
                                                  ( rtos ( car pt ) 2 dec ) ";" ( rtos ( cadr pt ) 2 dec ) ";"
                                                  ( rtos ( car ptpm ) 2 dec ) ";" ( rtos ( cadr ptpm ) 2 dec ) )
                                     fich )
                ; incrémenter le compteur de un car un point a été traité

                 ( setq compteur ( 1+ compteur ) )
          )
             ( progn
                 ( setq ecart ( distance ptpm pt ) )
                 ; dessiner un "vecteur" de couleur rouge depuis ptpm jusqu'à pt

                 ( grdraw ptpm pt 1 )
                 ( write-line ( strcat att ";" ( rtos pm 2 dec ) ";" ( rtos ecart 2 dec ) ";"
                                                  ( rtos ( car pt ) 2 dec ) ";" ( rtos ( cadr pt ) 2 dec ) ";"
                                                  ( rtos ( car ptpm ) 2 dec ) ";" ( rtos ( cadr ptpm ) 2 dec ) )
                                         fich )
                 ( setq compteur ( 1+ compteur ) )
           )
        )
     )
  ) 
)
; fermer le fichier car on n'a plus à écrire dedans
( close fich )
; afficher une case prévenant du nombre de points traités et du nom du fichier CSV
( alert ( strcat ( itoa compteur ) " Points écrits dans le fichier : " nom ) )
);;; fin du defun c:DA_Ent_PM_Deport

 

 

L'apparence des vecteurs à la fin du traitement est celle-ci :
Vous noterez que ce n'est que du vecteur, le moindre zoom, pan ou redess les fera disparaître, c'est le principe de ( grdraw ).

l'apparence du fichier de sortie ouvert dans Excel est celle-ci :

Il est aisé de travailler avec ces données, que ce soit pour faire de simples tris ou des calculs, on est dans Excel...

Ce programme a été testé
et fonctionne avec

Je reste à disposition par le formulaire CONTACT pour répondre aux questions ou recevoir vos critiques et idées d'améliorations...

Les améliorations à venir portent sur le choix des points avec possibilité d'avoir des entités "point" et pas que des blocs.
Si on travaille quand même avec des blocs il faudra vérifier l'attribut par son étiquette.
Il faudra aussi vérifier si le fichier de destination existe ou pas et s'il existe doit-on l'écraser.
Possibilité de créer un boîte de dialogue pour faciliter les choix si les options se multiplient...