Sommaire
Faire un réseau de trous dans Catia V5 par l’utilisation d’un script CatVBa.
Définition du problème:
Percer un ensemble de trous sur une surface plane ou de révolution cela ne pose pas trop de problème mais lorsqu’il s’agit de les percer de façon normale à la surface c’est déjà plus difficile alors lorsque cette dernière est gauche et qu’il y a plus d’une centaine de perçages …. !
Voici l’objet à modéliser:
Il s’agit d’une tôle percée servant de filtre comme on peut en voir dans l’agro-alimentaire. Sa particularité est que la forme de base, bien que symétrique, présente une évolution de section.
Prenons le temps de la réflexion…
Que ce soit en solide (generative sheet metal design y compris) ou en surfacique, il faudra bien commencer par obtenir d’une manière ou d’une autre toutes les origines des trous et donner pour chacun d’entre eux la direction du perçage.
Bien sûr, on peut utiliser la copie optimisée pour nous éviter la répétition de certaines opérations. Mais il faut créer la copie optimisée et évidemment un grand nombre de fois cette manip de collage sans parler de la corvée de la désignation des nouveaux parents… Pffff ! Oublions cela pour cet article nous le traiterons dans un prochain article.
Stratégie:
Puisqu’il y a beaucoup d’éléments, il faut donc recourir à un automatisme pour le faire à notre place !
- Générer uniquement des éléments vivants (c’est à dire ayant des parents) paramétrables
- Générer des éléments isolés (donc morts) et bien positionnées
La première est très sérieuse car elle permet d’ajuster nombre de choses comme par exemple le diamètre des trous ou même leurs positions, toutefois cela a la fâcheuse tendance de surcharger l’arbre et augmenter les temps de mise à jour.
La deuxième perd tout l’intérêt de la dynamique des jeux de paramètres mais elle est plus légère et, si l’on possède le script, cela ne gène en rien le fait de pouvoir modifier les choses par la suite… Comprenez :
« Je jette tout et je relance la macro qui refera tous les perçages comme je le souhaite. Na ! ».
Dans cet exemple, nous allons donc partir sur la deuxième solution (les perçages « morts »), sachant que l’on peut écrire un programme dans lequel les éléments bien vivants seraient rangés dans des sets géométrique.
Préparons le modèle:
Il nous faut:
La surface de base et comme le modèle est symétrique nous ne modéliserons que la moitié de celle-ci. Nous ne la symétriserons qu’à la fin.
Créer deux esquisses portées par des plans parallèles et distants. Les deux esquisses sont ici de formes semblables à l’échelle près mais elles peuvent êtres quelconques.
Une surface multi-sections est tendue entre ces deux courbes (profils avec la même orientation) avec l’option Couplage en sommets puisque le nombre de segments est identique sur chaque profil.
Le set géométrique « Trous » contient le seul cylindre vivant du modèle.
Il est défini comme suit:
- Il est normal à la « surface sans trou » car dirigé par une droite normale à cette surface « Direction_trou »
- Son origine est un point sur courbe (fraction). Cette courbe est l’intersection de « surface sans trou » et d’un plan « plan_intersection » se déplaçant d’un support d’esquisse à l’autre en suivant un point sur courbe (fraction) se déplaçant le long de la droite « Guide_plan »
Notez bien, que les entités (les Features) ont été renommées. C’est très important pour la lisibilité et parce que le script s’appuiera sur les noms des entités et des sets géométriques.
Méthode:
J’ai envisagé la méthode suivante:
- Le set géométrique « Peau_initiale » porte la demie surface de base « Surface_sans_trou ».
- Le set géométrique « Trous » porte un seul cylindre surfacique dont la direction est toujours normale à « Surface_sans_trou » et que l’on peut déplacer à volonté, grâce au script, en jouant sur deux paramètres pilotant le point d’origine de ce cylindre.
- Lorsque le cylindre atteint une position souhaitée dans le script, une copie de celui-ci est faite dans le set géométrique « Ensemble_trous ». C’est un collage sans lien donnant une entité isolée portant un nom unique « Cylindre.n » avec n=le numéro du cylindre. Le programme boucle de façon à créer au bon endroit tous les cylindres (ici 90).
- Dans le set géométrique « Résultat » le script effectue l’assemblage des 90 cylindres sans tenir compte de la connexité puis effectue la coupe de « Surface_sans_trou » par cet ensemble de cylindre. Cela conduit au perçage de la face de départ qui est renommée aussi par le script comme « Peau_percée »
- Finition du modèle dans le corps de pièce avec épaississement de la peau puis symétrie.
Bien sûr, il y a toujours n façons de faire et celle-ci n’est pas forcément la plus efficace mais cela montre l’intérêt de l’automatisation sur une tâche répétitive.
Le programme en détail:
Le modèle est prêt à accueillir les nouveaux éléments générés par le programme.
Voyons le dans le détail:
Sub CATMain() '*****************************************************************************************'
' Programme CatVba pour la le pilotage de la Catpart "Essai_percage" et '
' la création de cylindres destinés à générer des rangées de trous dans '
' une surface quelconque'
'*****************************************************************************************'
'Déclarations de variables' Set DocCatia = CATIA.ActiveDocument 'DocCatia est le document actif'
Set PartActive = DocCatia.Part 'PartActive est le document actif de type part'
Set Ensemble_de_Parametres1 = PartActive.Parameters 'Ensemble_de_Parametres1 est une famille de tous les paramètres du document actif de type part'
Set ParamPosTrou = Ensemble_de_Parametres1.Item("Part1\Trous\Position_trou\Fraction") ' ParamPosTrou est le paramètre pilotant la position du trou'
Set selection1 = DocCatia.Selection 'selection1 est un ensemble de selection du doc actif'
selection1.Clear 'On vide le buffer de la selection1 '
Set selection2 = DocCatia.Selection 'selection2 est un ensemble de selection du doc actif'
selection2.Clear 'On vide le buffer de la selection2 '
Set EnvSurfacique = PartActive.HybridBodies 'EnvSurfacique représente la famille surfacique dans le doc actif'
'*****************************************************************************************'
'On va maintenant créer tous les cylindres par un balayage cartésien.'
'On en profite pour numéroter et ranger les cylindres dans un set géométrique.'
' '
'création de deux boucles imbriquées pour faire:'
' - avancer le plan par pas de 10% de la longueur de la pièce'
' - (à l intérieur) faire avancer le point sur la courbe d intersection par pas de 10% de la longueur de la courbe'
'******************************************************************************************'
Dim Fraction_pour_plan As Integer 'déclaration de variable de la première boucle (déplacement du plan)'
For Fraction_pour_plan = 1 To 9 Step 1 'boucle de 1 à 9 par pas de 1 (comprendre de 10 à 90% par 10%)'
Set FractLongCourbe_PourPlan = Ensemble_de_Parametres1.Item("Part1\Trous\Position_plan_sur_guideFraction") 'position du point sur la droite à l origine du plan (Position_plan_sur_guide dans le set géom "Trous") '
'On positionne le point donc le plan qui générera l intersection avec la peau'
FractLongCourbe_PourPlan.Value = Fraction_pour_plan / 10 'Valeur de 1 à 9 divisée par 10 car Catia veut une valeur entre 0 et 1'
PartActive.Update 'Mise à jour de la part important pour construire la suite'
Dim Fraction_pour_courbe As Integer 'déclaration de variable de la deuxième boucle (déplacement du point)'
For Fraction_pour_courbe = 1 To 10 Step 1 'boucle de 1 à 10 par pas de 1 (comprendre de 10 à 90% par 10%)'
ParamPosTrou.Value = Fraction_pour_courbe / 10 'Valeur de 1 à 10 divisée par 10 car Catia veut une valeur entre 0 et 1'
PartActive.Update 'Mise à jour de la part important pour construire la suite'
selection1.Clear 'On vide le buffer de la selection1 pour être sûr'
Set SetGeomTrous = EnvSurfacique.Item("Trous") 'Déclaration du set géométrique "Trous"'
Set EntitesSurf_SetTrous = SetGeomTrous.HybridShapes 'Déclaration: EntitesSurf_SetTrous sont les entitées surfacique de ce set géometrique "trous" '
Set SurfCylindre = EntitesSurf_SetTrous.Item("Cylindre") 'Déclaration: SurfCylindre est un cylindre surfacique des entitées surfacique de ce set géometrique "trous"'
selection1.Add SurfCylindre 'On l ajoute à la selection1'
selection1.Copy 'On la copie' selection2.Clear 'On vide le buffer de selection2, pour être sûr'
Set SetGeomEnsembleTrous = EnvSurfacique.Item("Ensemble_trous") 'On déclare SetGeomEnsembleTrous, le set géom "Ensemble_trous"'
selection2.Add SetGeomEnsembleTrous 'On selectionne le set géom "Ensemble_trous"'
selection2.PasteSpecial "CATPrtResultWithOutLink" 'Et on colle sans lien (donc isolé) le cylindre précédemment copié'
Set EntitesSurf_SetEnsembleTrous = SetGeomEnsembleTrous.HybridShapes 'On déclare les entitées surfaciques de ce set géométrique'
nb_elem = EntitesSurf_SetEnsembleTrous.Count 'On compte le nombre d entités surfaciques dans le set géom "Ensemble_trous"'
Set Elem = EntitesSurf_SetEnsembleTrous.Item(nb_elem) 'on déclare le dernier élément de la liste'
Elem.Name = "Cylindre." & nb_elem 'et on le renomme avec le numéro de sa position (exemple Cylindre.77)'
selection1.Clear 'On vide le buffer de la selection 1'
selection2.Clear 'On vide le buffer de la selection 2'
PartActive.Update 'On met à jour la part'
Next 'on ferme la boucle positionnant le cylindre'
Next 'on ferme la boucle positionnant l intersection'
'*************************************************************************************'
'A ce stade, on a créer tous les cylindres.'
'Il faut maintenant s en servir pour percer la peau.'
'Donc les grouper dans un assemblage pour ensuite faire une découpe'
'de la peau de base par cet assemblage de cylindres.'
'*************************************************************************************'
selection1.Clear 'On vide le buffer de la selection 1 pour la réutiliser'
selection1.Add SetGeomEnsembleTrous 'on selectionne le set géométrique "Ensemble_trous"'
nb_elem = EntitesSurf_SetEnsembleTrous.Count 'On dénombre toutes les entités surfaciques du set "Ensemble_trous" (tous les cylindres créés)'
selection1.Clear 'On vide la selection1'
'Jusque là les entités manipulées étaient déja existantes dans la part'
'Nous allons maintenant en créer grâce à "Factory" (Atelier) '
Dim Atelier_Surf As Factory ' "Atelier_Surf" est une variable du type Factory (atelier)'
Set Atelier_Surf = PartActive.HybridShapeFactory 'et "Atelier_Surf" est un atelier surfacique (HybridShapeFactory) de la part active'
'Préparation de l assemblage de tous les cylindres dans "Ensemble_de_perçages"'
'Il faut commencer par y mettre les deux premiers éléments puis ajouter le reste grâce à une boucle'
Set EntreeSurfacique1 = Ensemble_de_Parametres1.Item("Cylindre.1") 'Déclaration: première entrée pour l assemblage'
Set reference1 = PartActive.CreateReferenceFromObject(EntreeSurfacique1) 'Il faut passer par une référence'
Set Ensemble_de_Parametres2 = PartActive.Parameters 'Ensemble_de_Parametres2 est une famille de tous les paramètres du document actif de type part'
Set EntreeSurfacique2 = Ensemble_de_Parametres2.Item("Cylindre.2") 'Déclaration: Deuxième entrée pour l assemblage'
Set reference2 = PartActive.CreateReferenceFromObject(EntreeSurfacique2) 'Il faut passer par une référence'
Set Assemblage_surfacique1 = Atelier_Surf.AddNewJoin(reference1, reference2) 'On créé ici l assemblage avec les deux premiers éléments (cylindre.1 et cylindre.2)'
Set Ensemble_de_Parametres3 = PartActive.Parameters 'Ensemble_de_Parametres3 est une famille de tous les paramètres du document actif de type part'
'Avec une boucle commençant par 3 (le cylindre.3), on ajoute tous les autres cylindres à l assemblage'
For num_element = 3 To nb_elem Step 1 'boucle de 3 à nombre total de cylindres dans le set'
Set EntreeSurfacique3 = Ensemble_de_Parametres3.Item("Cylindre." & num_element) 'On désigne le cylindre à ajouter'
Set reference3 = PartActive.CreateReferenceFromObject(EntreeSurfacique3) 'On passe par une référence'
Assemblage_surfacique1.AddElement reference3 'on ajoute cette référence à l assemblage'
Next 'fin de la boucle. Tous les cylindres sont ajoutés à l assemblage'
'On définit maintenant la façon dont l assemblage doit se comporter'
Assemblage_surfacique1.SetConnex 0 'le plus important: on ne vérifie pas la connexité car les cylindres ne se touchent pas'
Assemblage_surfacique1.SetManifold 0
Assemblage_surfacique1.SetSimplify 0
Assemblage_surfacique1.SetSuppressMode 0
Assemblage_surfacique1.SetDeviation 0.001
Assemblage_surfacique1.SetAngularToleranceMode 0
Assemblage_surfacique1.SetAngularTolerance 0.5
Assemblage_surfacique1.SetFederationPropagation 0
Assemblage_surfacique1.Name = "Ensemble_de_perçages" 'On lui donne un nom au passage'
'L assemblage existe en mémoire vive mais n est pas encore visible dans l arbre'
'On l ajoute dans le bon set géométrique'
Set SetGeomResultat = EnvSurfacique.Item("Resultat") 'On déclare le Set géométrique résultat'
Set EntiteSurf_SetResultat = SetGeomResultat.HybridShapes 'On déclare toutes les entités surfaciques de ce set'
SetGeomResultat.AppendHybridShape Assemblage_surfacique1 'On y ajoute l assemblage (apparition dans l arbre)'
selection1.Clear 'On vide le buffer de la selection1'
Set FiltreAffichage1 = selection1.VisProperties 'Filtre_affichage associé à la selection1'
selection1.Add (SetGeomTrous) 'On ajoute le set géom "Trous" à la selection1'
selection1.Add (SetGeomEnsembleTrous) 'On ajoute le set géom "Ensemble_Trous" à la selection1'
selection1.Add (Assemblage_surfacique1) 'On ajoute "Assemblage_surfacique" à la selection1'
FiltreAffichage1.SetShow 1 'On cache la selection'
selection1.Clear 'on deselectionne' PartActive.Update 'Mise à jour de la part'
'On peut maintenant découper la peau de base'
'et créer la peau percée'
Set SetGeom_PeauInit = EnvSurfacique.Item("Peau_initiale") 'Déclaration du Set géom'
Set ElemSurf_SetPeauInit = SetGeom_PeauInit.HybridShapes 'Les elements surfaciques de "Peau_Initiale"'
Set PeauADecouper1 = ElemSurf_SetPeauInit.Item("Surface_sans_trou") 'On designe la peau qui sera découpée'
Set reference4 = PartActive.CreateReferenceFromObject(PeauADecouper1) 'on passe par une référence'
Set Assemblage_surfacique1 = EntiteSurf_SetResultat.Item("Ensemble_de_perçages") 'On désigne l ensemble des trous (cylindres) de perçage'
Set reference5 = PartActive.CreateReferenceFromObject(Assemblage_surfacique1) 'On passe par une référence'
Set hybridShapeSplit1 = Atelier_Surf.AddNewHybridSplit(reference4, reference5, 1) 'On crée la découpe de ref4 par ref5'
hybridShapeSplit1.Name = "Peau_percée" 'on renomme la découpe'
Atelier_Surf.GSMVisibility reference4, 0 ' "Surface_sans_trouCacher est caché'
SetGeomResultat.AppendHybridShape hybridShapeSplit1 'On ajouter la découpe au set géom "résultat"'
PartActive.InWorkObject = hybridShapeSplit1 'Définir l objet de travail comme étant la peau percée'
PartActive.Update 'Mise à jour de la part'
End Sub
Le script est suffisamment commenté pour comprendre l’enchaînement des actions.
Au lancement, la macro fait appel aux différentes entités présentes dans l’arbre en s’appuyant sur leurs noms. Il ne faut donc rien déplacer ou renommer.
Si tout ce passe bien, nous obtenons en quelques secondes 90 cylindres dans le set « Ensemble_trous » et un assemblage de ceux ci dans le set résultat ainsi que la découpe de la peau d’origine par ces cylindres.
On obtient ce résultat.
La peau d’origine est cachée ainsi que les sets « Trous » et « Ensemble de trous ».
Dans ceux-ci, le programme à construit les éléments suivants:
Chacun des cylindres, correctement positionné et orienté, sont affublés de leur numéro de création. Ils sont tous isolés (plus de parent).
L’assemblage des cylindres dans le set Résultat. L’option de vérification de la connexité est décochée.
Et la découpe souhaitée de la peau de départ par l’assemblage des cylindres.
Il ne reste plus qu’à finir la pièce par un épaississement et une symétrie à moins que vous ne vouliez changer un paramètre (Ø des trous, nombre de trous…).
Cela est possible. il faut alors détruire les 90 cylindres isolés ainsi que l’assemblage et la découpe puis modifier le cylindre de départ (dans le set « Trous ») ou modifier les boucles dans le script (pour ne pas avoir par exemple de trous dans le plan de symétrie).
Finition de la pièce
La suite est des plus simples puisqu’il suffit de passer dans l’atelier Part Design et de définir un corps de pièce comme objet de travail puis d’utiliser la fonction « Surface épaisse » avec en entrée la « peau_percée ».
En dernière opération une symétrie solide en référence au plan XZ et l’application d’un matériau.
Et voilà…
Le script à l’épreuve…
Moyennant des modifications mineures au niveau des boucles, nous voyons que le système de perçage est capable de s’adapter à n’importe quelle surface.
Le plan d’intersection suit le bord de la face en restant perpendiculaire à celui-ci. La catpart est modifiée de façon à intégrer cette nouvelle surface (le nom doit être conservé) et la droite guide doit être remplacée par un bord de la nouvelle face.
Démonstration en vidéo ci-dessous:
J’espère que cela vous a plu, alors n’hésitez pas à me laisser un commentaire ou simplement à partager cet article.
.
4 Responses
Super Tuto ! Ça marche très bien mais juste au cas ou, sur le code de la page il faut modifier 2 points :
– lignes 16&42 il faut rajouter les « \ » pour définir le chemin.(« Part1\Trous\Position_trou\Fraction »)
– lignes 81&132 : les concaténations à changer : & => &
Merci, super travail !
Bonjour Christophe,
Merci pour cette relecture.
Pour la syntaxe je ne l’avais pas vu.
C’est un copier/coller qui a fait disparaitre les « \ ».
Pour le « & », c’est une mauvaise interprétation pour le rendu du code sur le blog.
C’est corrigé.
Merci.
Bonjour,
Merci pour le Tutoriel intéressant.
Par contre, j’ai rencontré un problème lors de l’exécution du macro, bien que j’ai créé toutes les composantes nécessaires.
Le problème sur la ligne suivante :
Dim Fraction_pour_plan As Integer ‘déclaration de variable de la première boucle (déplacement du plan)’
Pourriez-vous me clarifier la source de ce problème ?
Je n’ai pas trouvé votre adresse e-mail, pour joindre une photo de mon écran.
Merci pour vous vivement par avance pour votre aide.
Bonjour,
Comme ça effectivement il est difficile de répondre.
Je vous envois un mail pour que vous puissiez m’en dire plus sur ce problème.