Macro pour obtenir un stl avec des arrondis parfaits et piloter octoprint

Forum destiné aux questions et discussions en français
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
User avatar
2cv001
Posts: 484
Joined: Wed Jan 01, 2020 9:30 am

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by 2cv001 »

Je me suis toujours demandé comment il font pour avoir justement un mécanisme de traduction dans les programmes. Il doit y avoir mieux que de mettre tous les textes dans des variables avec des case...
Autre évolution possible pour le programme : mémoriser les choix de l'utilisateur pour pouvoir les remettre par défaut lors de l'ouverture suivante.
Avec comme question le format des données (existe il des fonctions pour sauver facilement une liste par exemple, sinon, je saurais toujours sauver ça dans un fichier texte) et du dossier où mettre le fichier en fonction des systèmes d'exploitation
Macro Sketch Constraint From Spreadsheet :
https://wiki.freecad.org/Macro_Sketch_C ... adsheet/fr
mario52
Veteran
Posts: 4692
Joined: Wed May 16, 2012 2:13 pm

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by mario52 »

Bonjour

ici un petit exemple de:

icône dans la macro et sauvegarde de paramètres dans les préférences de FreeCAD

deviation, doitLancerFichier, delaiMax sont sauvés quand on quitte la macro

Menu > Éditer paramètres > BaseApp/Preferences/Macros/2cv001/VSExportSTL

mes ajouts sont dans les balises "#### AJOUT"

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Macro qui permet de créer un fichier "stl" avec des arrondis parfaits
= sans facettes visibles.
Elle permet aussi de lancer des programmes de votre choix
Par exemple pour automatiser la cheine FreeCAD -> Slicer -> impression

Principe du lissage : elle modifie la propriété deviation des body avant
génération du stl puis replace les anciennes valeures
A la fin, elle propose de lancer le fichier stl qui s'ouvrira par exemple sous
cura si l'extension stl a été associé à cura dans votre système d'exploitation.

Lancement d'autres programmes ou commande :
Vous pouvez lui demander tout programme ou commande que vous pourriez taper 
dans un terminal. Pour cela, vous devez modifier ce qu'il y a dans la section
"paramètres pouvant être changés". 
Exemples d'applications : 
- Allumer l'imprimante et la lumière (nécessite par exemple une prise commandée)
- Connecter octoprint à l'imprimante
- Lancer la préchauffe du plateau
- Sauvegarder votre fichier FreeCAD et stl
....

Fonctionne sous windows. Testé ausi sous Linux 
"""
import FreeCAD as App
import Mesh
from PySide import QtGui, QtCore
import os, sys, subprocess
import time

#### AJOUT
__Title__    = "VSExportSTL"
__Author__   = "Mario52"
__Version__  = "0.0"
__Date__     = "2020/12/18" #YYYY/MMM/DD

__Comment__  = ""
__Web__      = ""
__Wiki__     = ""
__Icon__     = ""
__IconW__    = ""
__Help__     = ""
__Status__   = ""
__Requires__ = ""
__Communication__ = ""
#### AJOUT

#
#================================
# Paramètres pouvant être changés
#================================

# Gestion du lissage
#--------------------

# deviation : valeur par défaut qui s'affichera dans la boite de dialogue. 
# 0.5 par défaut dans FreeCad, 0.05 permet un lissage plus fort.
# 0.01 est parfait du point de vue lissage. 
# plus la valeur est faible et plus la qualité est bonne, 
# mais plus la taille du fichier stl est grande
# la valeur doit être comprise entre 0 et 1

#### AJOUT
global deviation
global doitLancerFichier  #; doitLancerFichier=True # si True, il sera proposer de lancer le fichier stl
global delaiMax           #; delaiMax=10  # si l'utilisateur entre un délai plus grand, il est rédut à delaiMax
##
deviation = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetFloat("deviation")

if deviation == 0.0:
    deviation = 0.01
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("deviation", deviation)
##
doitLancerFichier = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetBool("doitLancerFichier")
if doitLancerFichier == 0:
    doitLancerFichier == False
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetBool("doitLancerFichier", doitLancerFichier)
##
delaiMax = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetFloat("delaiMax")
if delaiMax > 10.0:
    delaiMax = 10.0
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("delaiMax", delaiMax)

FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetString("Version",__Version__ + " (" + __Date__ + ")")

## disponible: GetFloat, GetBool, GetString, GetUnsigned, GetInt ... # lire=Get
##           : SetFloat, SetBool, SetString, SetUnsigned, SetInt ... # ecrire=Set
#### AJOUT

# lancement automatique de programmes,
# Automatisation de la chaine de production
#------------------------------------------

#Pour lancer des programmes de votre choix
    #Typiquement par exemple un programme domotique, 
    #allumer votre imprimante ou/et une lumière.
#Utilisez la syntaxe suivante en ajoutant une ligne dans commandes=....:
#  [ ['commande à exécuter', 'param 1', param 2, ] ,'.extention','question à poser' ],
#
# 'commande à exécuter' : la commande que vous voulez exécuter. 
# 'parame 1, param 2,...' : si votre programme a besoin de paramètres. 
#  Ces paramètres ne serons pris en compte que si extention=''
#
# 'extention': si non vide alors le premier paramètre sera remplacé par le nom de 
#     votre fichier FreeCAD mais avec cette extension :
# 'question à poser' : la question à afficher dans la boite de dialogue

# A noter les doubles \ en remplacement de \ (car les caractères spéciaux
# doivent être précédés d'un \ en python). idem pour par exemple l'apostrophe
# les lignes 
#[ ['commande à exécuter','param 1','param 2'  ] ,'.extension','Question à poser'  ],
# doivent être insérées plus bas après commande=[
#
# Exemples de lancements possibles :

"""
syntaxe
[ ['commande à exécuter','paramètre 1','paramètre 2'  ] ,'.extension','Question à poser'  ],
[ ['calc.exe'                                         ] ,''    ,'Lancer la calculatrice ?'],
[ ['C:\\WINDOWS\\system32\\mspaint.exe','dessin.jpg'  ] ,''    ,'Lancer Paint ?'          ],
[ ['C:\\Program Files\\Ultimaker Cura 4.8.0\\Cura.exe'] ,'.stl','Lancer Cura ?'           ],
[ ['curl','http://pidomotique/connecte.php'           ] , ''   ,'Connecter l\'imprimante ?'],
[ ['C:\\Program Files\\Mozilla Firefox\\firefox.exe','https://octopi.local'],'','Lancer Octoprint ?'],
 pour linux:
[ [   'firefox','https://octopi.local'                ] , ''   ,'Lancer Octoprint ?'      ], 

Exemple de pilotage de l'imprimante via octoprint (si vous l'avez...) :
   mise en température du plateau
- Remplacez les XXX se trouvant après X-Api-Key: par votre clef API
(que l'on trouve dans les paramètres d'octoprint)
- Remplacez http://octopi.local par l'url avec laquelle vous accédez à octoprint
- Modifiez la valeur 050 dans "M140 S050" : S050 pour chauffer à 50° si vous souhaitez 60° : S060
- 6 lignes à recopier :
  [
      [  'curl','-H', 'Content-Type: application/json','-H', 'X-Api-Key: XXXXXXXXXXXXXXXXXXXXX', '-X', 'POST',
            '-d {"command":"M140 S050"}','http://octopi.local/api/printer/command'
      ]
            , '','Chauffer le plateau de l\'imprimante ?'
  ],

"""


commandes=[
# insérez ici vos lignes.
  [ ['calc.exe'                                         ] ,''    ,'Lancer la calculatrice ?',2],


         ]



#===============
#Initialisations
#===============
dictionnaireOrigineDeviation={}
mw = Gui.getMainWindow()
# Constant definitions
userCancelled= "Cancelled"
userOK= "OK"
userDeviation=str(deviation)

#### AJOUT
# icone dans une variable (fichier xpm sans le debut de l'entete copier uniquement ce qu'il y a entre les crochets { "....." }
executeIcon = [
"24 24 3 1",
" 	c None",
".	c #4E9A06",
"+	c #FFFFFF",
"                        ",
"                        ",
"                        ",
"                  .     ",
"                 .+.    ",
"                .+.+.   ",
"               .+...+.  ",
"              .+.....+. ",
"     .       .+.......+.",
"    .+.     .+.......+. ",
"   .+.+.   .+.......+.  ",
"  .+...+. .+.......+.   ",
" .+.....+.+.......+.    ",
".+.......+.......+.     ",
" .+.............+.      ",
"  .+...........+.       ",
"   .+.........+.        ",
"    .+.......+.         ",
"     .+.....+.          ",
"      .+...+.           ",
"       .+.+.            ",
"        .+.             ",
"         .              ",
"                        "]
#### AJOUT


# UI Class definitions

class BoiteDialogueSTLGuiClass(QtGui.QDialog):
    """"""
    def __init__(self):
        super(BoiteDialogueSTLGuiClass, self).__init__()
        self.initUI()

    def initUI(self):

#### AJOUT
        global doitLancerFichier  #; doitLancerFichier=True # si True, il sera proposer de lancer le fichier stl
    
        #############
        #self.path  = FreeCAD.ConfigGet("AppHomePath")
        #self.path  = FreeCAD.ConfigGet("UserAppData")
        #self.path  = "your path"
        param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")     # macro path
        self.path = param.GetString("MacroPath","") + "/"                        # macro path
        self.path = self.path.replace("\\","/")
#        print "Path for the icons : " , self.path
        #############
#### AJOUT

        hauteurBoiteDialogue=150 #hauteur initiale de la boite de dialogue.
        self.result = userCancelled
        self.tabCheckboxTextCommandes=[] # tab des checkbox commandes à lancer
        self.setWindowTitle("Entrez vos paramètres")
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)

        # checkboxes
        self.checkboxGenererSTL = QtGui.QCheckBox("Générer le STL", self)
        self.checkboxGenererSTL.clicked.connect(self.onCheckboxGenererSTL)
        self.checkboxGenererSTL.setCheckState(QtCore.Qt.Checked)# mise à checked
        self.checkboxGenererSTL.move(20,20)
        if doitLancerFichier :
            self.checkboxLancerSTL = QtGui.QCheckBox("Lancer le slicer", self)
            self.checkboxLancerSTL.clicked.connect(self.onCheckboxLancerSTL)
            self.checkboxLancerSTL.setCheckState(QtCore.Qt.Checked)
            self.checkboxLancerSTL.move(20,40)

        for i in range(len(commandes)) :
           #hauteurBoiteDialogue=hauteurBoiteDialogue+20
           textCommande=commandes[i][2]
           self.checkboxTextCommande = QtGui.QCheckBox(textCommande, self)
           # mémorisation de cette checbox dans un tableau :
           self.tabCheckboxTextCommandes.append(self.checkboxTextCommande)
           self.checkboxTextCommande.clicked.connect(self.onCheckboxGenererSTL)
           self.checkboxTextCommande.setCheckState(QtCore.Qt.Checked)# mise à checked
           self.checkboxTextCommande.move(20,80+20*i)
        # dimmensionnement boite de dialogue en fonction du nb de commandes à lancer : 
        hauteurBoiteDialogue=hauteurBoiteDialogue+20*len(commandes)
        self.setGeometry(   250, 250, 400, hauteurBoiteDialogue)

        # numeric input field
        self.label2 = QtGui.QLabel('Précision (param deviation) \nentre 0.01 et 1\n'+
             '0.01 pour une grande qualité', self)
        self.label2.move(150,20)
        self.precision = QtGui.QLineEdit(self)
        self.precision.setInputMask("9.99")
        self.precision.setText(userDeviation)
        self.precision.setFixedWidth(50)
        self.precision.setToolTip('Plus le chiffre est grand, plus la taille ' +
            'du fichier est grande \net meilleur est la précision.\n'+
            'Voir le paramètre deviation dans FreeCAD')
        self.precision.move(300, 20)

        # cancel button
        cancelButton = QtGui.QPushButton('Cancel', self)
        cancelButton.clicked.connect(self.onCancel)
#### AJOUT
        cancelButton.setIcon(QtGui.QIcon(self.path + "Macro_FCTreeView_09.png")) # icone dans un fichier
        cancelButton.setToolTip("Quit VSExportStl <img src=" + self.path + "Macro_FCTreeView_09.png />")# icone dans un toolTip
#### AJOUT
        cancelButton.setAutoDefault(False)
        cancelButton.move(150, hauteurBoiteDialogue-40)
        # OK button
        okButton = QtGui.QPushButton('OK', self)
        okButton.clicked.connect(self.onOk)
#### AJOUT
        okButton.setIcon(QtGui.QIcon(QtGui.QPixmap(executeIcon)))# execute icone dans une variable 
#### AJOUT
        okButton.setAutoDefault(True)
        okButton.move(260, hauteurBoiteDialogue-40)
        # now make the window visible
        self.show()
        #
    def onCheckboxGenererSTL(self):
        print('onCheckboxGenererSTL')

    def onCheckboxLancerSTL(self):
        print('onCheckboxLancerSTL')

    def onCancel(self):
#### AJOUT
        global deviation
        global doitLancerFichier
        global delaiMax

        deviation = float(self.precision.text())
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("deviation", deviation)
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetBool("doitLancerFichier", doitLancerFichier)
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("delaiMax", delaiMax)
#### AJOUT

        self.result         = userCancelled
        self.close()

    def onOk(self):
        self.result         = userOK
        self.close()

    

#===============
#Initialisations
#===============
dictionnaireOrigineDeviation={}
mw = Gui.getMainWindow()
# Constant definitions
userCancelled= "Cancelled"
userOK= "OK"

#===============
#Fonctions
#===============
def octopi(api,commande,urlOctopi,apiKey) :
    """
    Fonction qui renvoie le paramètre à passer à subprocess.Popen si on veut lancer
    une AI octopi. Non utilisez ici, mais ça peut servir

    Arguments : 
        api l'api à exécuter  ex : '/api/printer/command'
        commande : la commande de l'API en question ex: '{"command":"M140 S050"}'
        urlOctoprint : l'url de votre octopi ex : 'https://octopi.local'
        apiKey : la clef API que vous trouvez dans setting/API d'octoprint
    Returns :

    Example
       API lanant un gcode. Ici la chauffe du plateau de l'imprimante
       subprocess.Popen(
                          octopi(
                                '/api/printer/command',
                                '{"command":"M140 S050"}',
                                'https://octopi.local',
                                'XXXXKEYXAPIXXXXXXXX'))
                 ,close_fds=True)
    """
    commandeCurl=[
    'curl','-H', 'Content-Type: application/json','-H',
         'X-Api-Key: '+apiKey,
         '-X', 'POST',
        '-d '+commande,urlOctopi+api
    ]
    return commandeCurl


def nameFileStl(dictionnaireOrigineDeviation):
    """
    Fonction qui renvoie le nom de fichier compris chemin
    où sera enregistré le stl
    Le document contenant les objets du dictionaire doit être ouvert et
    sauvé

    Arguments : 
        dictionnaireOrigineDeviation  (dictionary) : 
            un dictionnaire dont les clefs sont des body. 
            le nom de fichier sera obtenu à partir du nom de fichier 
            du document contenant le premier objet (body) de ce
            dictionnaire

    Returns :
        '' si le document n'existe pas,
        sinon le nom du fichier où sera enregistré le stl

    Example
        nomFichierStl=nameFileStl(monDictionaireDeBody)
    """

    doc=list(dictionnaireOrigineDeviation.keys())[0].Document
    if doc is None:
        QtWidgets.QMessageBox.information(mw,'Attention',\
            "Vous n'avez pas de document ouvert")
        return ''
    if doc.FileName=='':
        QtWidgets.QMessageBox.information(mw,
             'Attention','Sauvez votre document avant de relancer la commande') 
        return ''
    return(os.path.splitext(doc.FileName)[0]+'.stl')

def memoriseObjEtDeviation(selection,deviationImpose):
    """
    Mémorise les Body qui sont contenus dans selection et leur
    propriété deviation et remplace cette dernière par la valeur 
    de deviationImpose
    Elle impose un recompute ultérieur par un touch.
    Recompute() doit être éventuellement lancé après

    Arguments :
        selection : une sélection d'objets
        deviationImpose (float) : valeur que l'on veut imposer à deviation

    Returns: 
        un dictionnaire contenant l'objet en key et la déviation en value
        Renvoie {} s'il n'y a pas d'objet adéquate dans la sélection

    Example:
        memoriseBodyEtDeviation(Gui.Selection.getSelection(),deviation)
    """
    dicoObjDeviation={}
    for objData in selection :
        if objData.isDerivedFrom('Part::Feature') \
          and not objData.isDerivedFrom('PartDesign::Feature')\
          and not objData.isDerivedFrom('Part::Part2DObject'):
            dicoObjDeviation[objData]=objData.ViewObject.Deviation
            objData.ViewObject.Deviation=deviationImpose 
           # pour imposer un recompute même si la déviation est plus petite
           # qu'avant :
            objData.touch()
            for o in objData.ViewObject.claimChildren():
                    o.touch()
    return dicoObjDeviation

def restitueDeviation(dicoOrigineDeviation):
    """
    Fonction qui remplace la propriété deviation dans les objets
    Elle impose un recompute par un touch. recompute() doit être
    lancé après

    Arguments:
        dicoOrigineDeviation un dictionnaire contenant l'objet en key 
        et la valeur à imposer dans la propriété déviation de l'objet
        en value

    Returns: Ne retourne rien

    Example:
        restitueDeviation(dicoOrigineDeviation)

    """
    for ob2 in dicoOrigineDeviation:
        ob2.ViewObject.Deviation=dicoOrigineDeviation[ob2]
        # pour imposer un recompute même si la déviation est plus petite
        # qu'avant :
        ob2.touch()
        for o in ob2.ViewObject.claimChildren():
            o.touch()

def openFile(fileName):
    """
    fonction qui lance un fichier en fonction du système d'exploitation
    vérifié pour l'instant uniquement sous windows

    Arguments:
        fileName (string) le nom du fichier à lancer

    Returns
        Ne retourne rien

    Example: 
        openFile(unfichier.stl)
        openFile(calc.exe)
    """
    if sys.platform == "win32":
        os.startfile(fileName)
    else:
        opener ="open" if sys.platform == "darwin" else "xdg-open"
        #subprocess.call([opener, fileName]) #le problème avec call est que freecad est bloqué en attendant que l'on sorte de l'application
        subprocess.Popen([opener, fileName],close_fds=True) 

def recalcul(dicoObjs):
    """
    lance un recompute pour chaque Document des objets du dico
    seulement si cela n'a pas déjà été fait
    Arguments:
        dicoObjs un dictionnaire contenant l'objet en key 

    Returns
        Ne retourne rien

    Example:
        recalcul(dicoMesObjets)
    """
    docDejaRecalcul=[]
    for obj in dicoObjs:
        if obj.Document not in docDejaRecalcul:
            print('recompute {}'.format(obj.Document.Name))
            obj.Document.recompute()
            docDejaRecalcul.append(obj.Document)

def lanceCommmandes(commandesAlancer,fileStlName,formBoiteDialogueSTL):
    """
    lance les commmandes
    Arguments:
        commandesAlancer sous la forme d'un tableau de tableaux
        (['commande à exécuter', 'paramètres','extention ,'question à poser'],
         ['commande à exécuter', 'paramètres','extention ,'question à poser'])

         'commande à exécuter' : la commande que vous voulez exécuter. 
         Par exemple 'monProgramme.exe' si besoin mettre aussi son chemin. 
         'parametres' : si votre programme a besoin de paramètres. Ne sera pris en compte que
             si extention=''#
         'extention': si non vide, le paramètre sera le nom de votre
              fichier FreeCAD mais avec votre extension :
          'question à poser' : la question à afficher dans la boite de dialogue

    Returns
        Ne retourne rien

    Example:
            lanceCommmandes(commandes,fileStlName) # lance les commandes que l'on a décrites dans commandes
    """


    for i in range(len(formBoiteDialogueSTL.tabCheckboxTextCommandes)) :
        if formBoiteDialogueSTL.tabCheckboxTextCommandes[i].isChecked() :
            commande=commandesAlancer[i]
            #print('{}'.format(commande))
            commandeEtParam=commande[0]
            extFileNameParamCommandeALancer=commande[1]
            textAutreCommandeALancer=commande[2]
            delai=0
            print('commande[3:4]----------' )           
            print(commande[3:4])
            try :
               if commande[3:4]!=[] : #si l'utilisateur a rentré un délai
                  delai=commande[3]
            except :
               print ('Délai non pris en compte car valeur numérique non valide'+
                      'pour la commande '+ textAutreCommandeALancer)
            if delai > delaiMax :
                delai=delaimax

            if extFileNameParamCommandeALancer!='':     
                if commandeEtParam[2:3]==[]  : # Il n'y a pas de paramètre.
                   # On ajoute un élément pour y mettre notre nom de fichier
                   # avec notre extension.
                   commandeEtParam.append('')
                commandeEtParam[1]=   os.path.splitext(fileStlName)[0]+  extFileNameParamCommandeALancer
            subprocess.Popen(commandeEtParam,close_fds=True)
            print ('------delai---------')
            print(commandeEtParam)
            print(delai)
            time.sleep(delai)# Pause de durée delai secondes   


def run(objs=Gui.Selection.getSelection(), dev=deviation):
    """
    fonction principale
    Arguments:
        doc : le document actif
        objs : les objets que l'on a au préalable sélectionnés
        dev : la valeur de la propriété déviation qui sera 
              imposée avant la génération du stl

    Returns
        Ne retourne rien

    Example:
        run()
    """


    """dev, reply = QtWidgets.QInputDialog.getDouble(mw, 'Option de précision',\
        'Entrée la déviation souhaitée. {} conseillé pour ne pas voir de facettes. '.format(dev),\
        dev, 0.00, 1.0, 2) # valeur par défaut, min, max et décimales.
    if not(reply):   # (Cancel)
        return
    """

    # Boite de dialogue de ce que l'on veut faire
    formBoiteDialogueSTL = BoiteDialogueSTLGuiClass()
    formBoiteDialogueSTL.exec_()
    if formBoiteDialogueSTL.result==userCancelled:
        return
    dev=float(formBoiteDialogueSTL.precision.text())

    # on mémorise les  body sélectionnés et leur déviation,
    # on fait un touch() de leur child pour prise en compte dans recompute :
    dictionnaireOrigineDeviation=memoriseObjEtDeviation(objs,dev)
    if len(dictionnaireOrigineDeviation)==0: # si on a trouvé aucun body
        QtWidgets.QMessageBox.information(mw, 'Attention',\
            'Sélectionnez un ou plusieurs body avant de lancer la macro')
        return
    # on récupère le nom du fichier où l'on devra enregistrer le stl
    fileStlName=nameFileStl(dictionnaireOrigineDeviation)
    if fileStlName == '' :
        return

    # l'export lui-même. On passe en paramètre les objets body qui 
    # sont dans dictionnaireOrigineDeviation
    if formBoiteDialogueSTL.checkboxGenererSTL.isChecked():
       Mesh.export(list(dictionnaireOrigineDeviation.keys()), fileStlName) 
       print('Export fait')
    # restitution de la propriété deviation d'origine pour les body :
    restitueDeviation(dictionnaireOrigineDeviation)
    recalcul(dictionnaireOrigineDeviation)

    if formBoiteDialogueSTL.checkboxLancerSTL.isChecked():
            #lance par exemple cura si cura a été associé aux fichiers *.stl
            openFile(fileStlName)
    """
    if doitLancerFichier:
        if QtWidgets.QMessageBox.Yes == QtWidgets.QMessageBox.question(mw, '',\
               'Lancer le fichier {}'.format(fileStlName) +
               " ?(nécessite l'association de l'extension stl à un programme)", \
                QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.No,\
                    QtWidgets.QMessageBox.No) : 
            #lance par exemple cura si cura a été associé aux fichiers *.stl
            openFile(fileStlName)
    """
    lanceCommmandes(commandes,fileStlName,formBoiteDialogueSTL) # lance les commandes que l'on a décrites dans commandes


if __name__ == '__main__':
    run()




mario
Maybe you need a special feature, go into Macros_recipes and Code_snippets, Topological_data_scripting.
My macros on Gist.github here complete macros Wiki and forum.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by openBrain »

2cv001 wrote: Thu Dec 17, 2020 6:57 pm Je me suis toujours demandé comment il font pour avoir justement un mécanisme de traduction dans les programmes. Il doit y avoir mieux que de mettre tous les textes dans des variables avec des case...
Ca dépend des applications, mais avec Qt il y a une classe QTranslator pour faire ça.
Autre évolution possible pour le programme : mémoriser les choix de l'utilisateur pour pouvoir les remettre par défaut lors de l'ouverture suivante.
Avec comme question le format des données (existe il des fonctions pour sauver facilement une liste par exemple, sinon, je saurais toujours sauver ça dans un fichier texte) et du dossier où mettre le fichier en fonction des systèmes d'exploitation
Mario t'a proposé une solution basé sur les paramètres de FreeCAD.
Il n'y a pas de solution "toute faite". Une autre solution c'est d'ajouter les fonctions "sauver" et "charger" à ta classe de dialogue et de coder toi-même l'export vers un fichier. Tu peux utiliser des format standard comme XML ou JSON.
User avatar
flachyjoe
Veteran
Posts: 1891
Joined: Sat Mar 31, 2012 12:00 pm
Location: Limoges, France

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by flachyjoe »

openBrain wrote: Fri Dec 18, 2020 3:56 pm Mario t'a proposé une solution basé sur les paramètres de FreeCAD.
Nb : on peut créer un fichier UI avec QTDesigner et le plugin spécial pour ajouter une page dans la boite de dialogue des préférences.

Code: Select all

FreeCADGui.addPreferencePage (os.path.join(chemin,"Fichier_pref.ui"), "Nom de la page")

Si ton code commence à être gros, il faut peut-être penser à en faire un Atelier. C'est plus facile d'en gérer le code mais peut-être un peu plus lourd pour l'utilisateur qui doit aller le chercher dans la boite déroulante.
- Flachy Joe -
Image
User avatar
2cv001
Posts: 484
Joined: Wed Jan 01, 2020 9:30 am

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by 2cv001 »

Merci pour vos réponses !
Je vais regarder cela, mais sans doute rien de concret d'ici plusieurs jours car j'ai de la famille qui arrivent pour les fêtes dès ce soir (mais en respectant les 6 maxi ! ). Bref, une petite pause :D
Mais j'irai quand même lire le forum :D
Macro Sketch Constraint From Spreadsheet :
https://wiki.freecad.org/Macro_Sketch_C ... adsheet/fr
User avatar
2cv001
Posts: 484
Joined: Wed Jan 01, 2020 9:30 am

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by 2cv001 »

mario52 wrote: Fri Dec 18, 2020 3:48 pm Bonjour

ici un petit exemple de:

icône dans la macro et sauvegarde de paramètres dans les préférences de FreeCAD

deviation, doitLancerFichier, delaiMax sont sauvés quand on quitte la macro

Menu > Éditer paramètres > BaseApp/Preferences/Macros/2cv001/VSExportSTL

mes ajouts sont dans les balises "#### AJOUT"

Code: Select all

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Macro qui permet de créer un fichier "stl" avec des arrondis parfaits
= sans facettes visibles.
Elle permet aussi de lancer des programmes de votre choix
Par exemple pour automatiser la cheine FreeCAD -> Slicer -> impression

Principe du lissage : elle modifie la propriété deviation des body avant
génération du stl puis replace les anciennes valeures
A la fin, elle propose de lancer le fichier stl qui s'ouvrira par exemple sous
cura si l'extension stl a été associé à cura dans votre système d'exploitation.

Lancement d'autres programmes ou commande :
Vous pouvez lui demander tout programme ou commande que vous pourriez taper 
dans un terminal. Pour cela, vous devez modifier ce qu'il y a dans la section
"paramètres pouvant être changés". 
Exemples d'applications : 
- Allumer l'imprimante et la lumière (nécessite par exemple une prise commandée)
- Connecter octoprint à l'imprimante
- Lancer la préchauffe du plateau
- Sauvegarder votre fichier FreeCAD et stl
....

Fonctionne sous windows. Testé ausi sous Linux 
"""
import FreeCAD as App
import Mesh
from PySide import QtGui, QtCore
import os, sys, subprocess
import time

#### AJOUT
__Title__    = "VSExportSTL"
__Author__   = "Mario52"
__Version__  = "0.0"
__Date__     = "2020/12/18" #YYYY/MMM/DD

__Comment__  = ""
__Web__      = ""
__Wiki__     = ""
__Icon__     = ""
__IconW__    = ""
__Help__     = ""
__Status__   = ""
__Requires__ = ""
__Communication__ = ""
#### AJOUT

#
#================================
# Paramètres pouvant être changés
#================================

# Gestion du lissage
#--------------------

# deviation : valeur par défaut qui s'affichera dans la boite de dialogue. 
# 0.5 par défaut dans FreeCad, 0.05 permet un lissage plus fort.
# 0.01 est parfait du point de vue lissage. 
# plus la valeur est faible et plus la qualité est bonne, 
# mais plus la taille du fichier stl est grande
# la valeur doit être comprise entre 0 et 1

#### AJOUT
global deviation
global doitLancerFichier  #; doitLancerFichier=True # si True, il sera proposer de lancer le fichier stl
global delaiMax           #; delaiMax=10  # si l'utilisateur entre un délai plus grand, il est rédut à delaiMax
##
deviation = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetFloat("deviation")

if deviation == 0.0:
    deviation = 0.01
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("deviation", deviation)
##
doitLancerFichier = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetBool("doitLancerFichier")
if doitLancerFichier == 0:
    doitLancerFichier == False
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetBool("doitLancerFichier", doitLancerFichier)
##
delaiMax = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).GetFloat("delaiMax")
if delaiMax > 10.0:
    delaiMax = 10.0
FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("delaiMax", delaiMax)

FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetString("Version",__Version__ + " (" + __Date__ + ")")

## disponible: GetFloat, GetBool, GetString, GetUnsigned, GetInt ... # lire=Get
##           : SetFloat, SetBool, SetString, SetUnsigned, SetInt ... # ecrire=Set
#### AJOUT

# lancement automatique de programmes,
# Automatisation de la chaine de production
#------------------------------------------

#Pour lancer des programmes de votre choix
    #Typiquement par exemple un programme domotique, 
    #allumer votre imprimante ou/et une lumière.
#Utilisez la syntaxe suivante en ajoutant une ligne dans commandes=....:
#  [ ['commande à exécuter', 'param 1', param 2, ] ,'.extention','question à poser' ],
#
# 'commande à exécuter' : la commande que vous voulez exécuter. 
# 'parame 1, param 2,...' : si votre programme a besoin de paramètres. 
#  Ces paramètres ne serons pris en compte que si extention=''
#
# 'extention': si non vide alors le premier paramètre sera remplacé par le nom de 
#     votre fichier FreeCAD mais avec cette extension :
# 'question à poser' : la question à afficher dans la boite de dialogue

# A noter les doubles \ en remplacement de \ (car les caractères spéciaux
# doivent être précédés d'un \ en python). idem pour par exemple l'apostrophe
# les lignes 
#[ ['commande à exécuter','param 1','param 2'  ] ,'.extension','Question à poser'  ],
# doivent être insérées plus bas après commande=[
#
# Exemples de lancements possibles :

"""
syntaxe
[ ['commande à exécuter','paramètre 1','paramètre 2'  ] ,'.extension','Question à poser'  ],
[ ['calc.exe'                                         ] ,''    ,'Lancer la calculatrice ?'],
[ ['C:\\WINDOWS\\system32\\mspaint.exe','dessin.jpg'  ] ,''    ,'Lancer Paint ?'          ],
[ ['C:\\Program Files\\Ultimaker Cura 4.8.0\\Cura.exe'] ,'.stl','Lancer Cura ?'           ],
[ ['curl','http://pidomotique/connecte.php'           ] , ''   ,'Connecter l\'imprimante ?'],
[ ['C:\\Program Files\\Mozilla Firefox\\firefox.exe','https://octopi.local'],'','Lancer Octoprint ?'],
 pour linux:
[ [   'firefox','https://octopi.local'                ] , ''   ,'Lancer Octoprint ?'      ], 

Exemple de pilotage de l'imprimante via octoprint (si vous l'avez...) :
   mise en température du plateau
- Remplacez les XXX se trouvant après X-Api-Key: par votre clef API
(que l'on trouve dans les paramètres d'octoprint)
- Remplacez http://octopi.local par l'url avec laquelle vous accédez à octoprint
- Modifiez la valeur 050 dans "M140 S050" : S050 pour chauffer à 50° si vous souhaitez 60° : S060
- 6 lignes à recopier :
  [
      [  'curl','-H', 'Content-Type: application/json','-H', 'X-Api-Key: XXXXXXXXXXXXXXXXXXXXX', '-X', 'POST',
            '-d {"command":"M140 S050"}','http://octopi.local/api/printer/command'
      ]
            , '','Chauffer le plateau de l\'imprimante ?'
  ],

"""


commandes=[
# insérez ici vos lignes.
  [ ['calc.exe'                                         ] ,''    ,'Lancer la calculatrice ?',2],


         ]



#===============
#Initialisations
#===============
dictionnaireOrigineDeviation={}
mw = Gui.getMainWindow()
# Constant definitions
userCancelled= "Cancelled"
userOK= "OK"
userDeviation=str(deviation)

#### AJOUT
# icone dans une variable (fichier xpm sans le debut de l'entete copier uniquement ce qu'il y a entre les crochets { "....." }
executeIcon = [
"24 24 3 1",
" 	c None",
".	c #4E9A06",
"+	c #FFFFFF",
"                        ",
"                        ",
"                        ",
"                  .     ",
"                 .+.    ",
"                .+.+.   ",
"               .+...+.  ",
"              .+.....+. ",
"     .       .+.......+.",
"    .+.     .+.......+. ",
"   .+.+.   .+.......+.  ",
"  .+...+. .+.......+.   ",
" .+.....+.+.......+.    ",
".+.......+.......+.     ",
" .+.............+.      ",
"  .+...........+.       ",
"   .+.........+.        ",
"    .+.......+.         ",
"     .+.....+.          ",
"      .+...+.           ",
"       .+.+.            ",
"        .+.             ",
"         .              ",
"                        "]
#### AJOUT


# UI Class definitions

class BoiteDialogueSTLGuiClass(QtGui.QDialog):
    """"""
    def __init__(self):
        super(BoiteDialogueSTLGuiClass, self).__init__()
        self.initUI()

    def initUI(self):

#### AJOUT
        global doitLancerFichier  #; doitLancerFichier=True # si True, il sera proposer de lancer le fichier stl
    
        #############
        #self.path  = FreeCAD.ConfigGet("AppHomePath")
        #self.path  = FreeCAD.ConfigGet("UserAppData")
        #self.path  = "your path"
        param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macro")     # macro path
        self.path = param.GetString("MacroPath","") + "/"                        # macro path
        self.path = self.path.replace("\\","/")
#        print "Path for the icons : " , self.path
        #############
#### AJOUT

        hauteurBoiteDialogue=150 #hauteur initiale de la boite de dialogue.
        self.result = userCancelled
        self.tabCheckboxTextCommandes=[] # tab des checkbox commandes à lancer
        self.setWindowTitle("Entrez vos paramètres")
        self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)

        # checkboxes
        self.checkboxGenererSTL = QtGui.QCheckBox("Générer le STL", self)
        self.checkboxGenererSTL.clicked.connect(self.onCheckboxGenererSTL)
        self.checkboxGenererSTL.setCheckState(QtCore.Qt.Checked)# mise à checked
        self.checkboxGenererSTL.move(20,20)
        if doitLancerFichier :
            self.checkboxLancerSTL = QtGui.QCheckBox("Lancer le slicer", self)
            self.checkboxLancerSTL.clicked.connect(self.onCheckboxLancerSTL)
            self.checkboxLancerSTL.setCheckState(QtCore.Qt.Checked)
            self.checkboxLancerSTL.move(20,40)

        for i in range(len(commandes)) :
           #hauteurBoiteDialogue=hauteurBoiteDialogue+20
           textCommande=commandes[i][2]
           self.checkboxTextCommande = QtGui.QCheckBox(textCommande, self)
           # mémorisation de cette checbox dans un tableau :
           self.tabCheckboxTextCommandes.append(self.checkboxTextCommande)
           self.checkboxTextCommande.clicked.connect(self.onCheckboxGenererSTL)
           self.checkboxTextCommande.setCheckState(QtCore.Qt.Checked)# mise à checked
           self.checkboxTextCommande.move(20,80+20*i)
        # dimmensionnement boite de dialogue en fonction du nb de commandes à lancer : 
        hauteurBoiteDialogue=hauteurBoiteDialogue+20*len(commandes)
        self.setGeometry(   250, 250, 400, hauteurBoiteDialogue)

        # numeric input field
        self.label2 = QtGui.QLabel('Précision (param deviation) \nentre 0.01 et 1\n'+
             '0.01 pour une grande qualité', self)
        self.label2.move(150,20)
        self.precision = QtGui.QLineEdit(self)
        self.precision.setInputMask("9.99")
        self.precision.setText(userDeviation)
        self.precision.setFixedWidth(50)
        self.precision.setToolTip('Plus le chiffre est grand, plus la taille ' +
            'du fichier est grande \net meilleur est la précision.\n'+
            'Voir le paramètre deviation dans FreeCAD')
        self.precision.move(300, 20)

        # cancel button
        cancelButton = QtGui.QPushButton('Cancel', self)
        cancelButton.clicked.connect(self.onCancel)
#### AJOUT
        cancelButton.setIcon(QtGui.QIcon(self.path + "Macro_FCTreeView_09.png")) # icone dans un fichier
        cancelButton.setToolTip("Quit VSExportStl <img src=" + self.path + "Macro_FCTreeView_09.png />")# icone dans un toolTip
#### AJOUT
        cancelButton.setAutoDefault(False)
        cancelButton.move(150, hauteurBoiteDialogue-40)
        # OK button
        okButton = QtGui.QPushButton('OK', self)
        okButton.clicked.connect(self.onOk)
#### AJOUT
        okButton.setIcon(QtGui.QIcon(QtGui.QPixmap(executeIcon)))# execute icone dans une variable 
#### AJOUT
        okButton.setAutoDefault(True)
        okButton.move(260, hauteurBoiteDialogue-40)
        # now make the window visible
        self.show()
        #
    def onCheckboxGenererSTL(self):
        print('onCheckboxGenererSTL')

    def onCheckboxLancerSTL(self):
        print('onCheckboxLancerSTL')

    def onCancel(self):
#### AJOUT
        global deviation
        global doitLancerFichier
        global delaiMax

        deviation = float(self.precision.text())
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("deviation", deviation)
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetBool("doitLancerFichier", doitLancerFichier)
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Macros/2cv001/" + __Title__).SetFloat("delaiMax", delaiMax)
#### AJOUT

        self.result         = userCancelled
        self.close()

    def onOk(self):
        self.result         = userOK
        self.close()

    

#===============
#Initialisations
#===============
dictionnaireOrigineDeviation={}
mw = Gui.getMainWindow()
# Constant definitions
userCancelled= "Cancelled"
userOK= "OK"

#===============
#Fonctions
#===============
def octopi(api,commande,urlOctopi,apiKey) :
    """
    Fonction qui renvoie le paramètre à passer à subprocess.Popen si on veut lancer
    une AI octopi. Non utilisez ici, mais ça peut servir

    Arguments : 
        api l'api à exécuter  ex : '/api/printer/command'
        commande : la commande de l'API en question ex: '{"command":"M140 S050"}'
        urlOctoprint : l'url de votre octopi ex : 'https://octopi.local'
        apiKey : la clef API que vous trouvez dans setting/API d'octoprint
    Returns :

    Example
       API lanant un gcode. Ici la chauffe du plateau de l'imprimante
       subprocess.Popen(
                          octopi(
                                '/api/printer/command',
                                '{"command":"M140 S050"}',
                                'https://octopi.local',
                                'XXXXKEYXAPIXXXXXXXX'))
                 ,close_fds=True)
    """
    commandeCurl=[
    'curl','-H', 'Content-Type: application/json','-H',
         'X-Api-Key: '+apiKey,
         '-X', 'POST',
        '-d '+commande,urlOctopi+api
    ]
    return commandeCurl


def nameFileStl(dictionnaireOrigineDeviation):
    """
    Fonction qui renvoie le nom de fichier compris chemin
    où sera enregistré le stl
    Le document contenant les objets du dictionaire doit être ouvert et
    sauvé

    Arguments : 
        dictionnaireOrigineDeviation  (dictionary) : 
            un dictionnaire dont les clefs sont des body. 
            le nom de fichier sera obtenu à partir du nom de fichier 
            du document contenant le premier objet (body) de ce
            dictionnaire

    Returns :
        '' si le document n'existe pas,
        sinon le nom du fichier où sera enregistré le stl

    Example
        nomFichierStl=nameFileStl(monDictionaireDeBody)
    """

    doc=list(dictionnaireOrigineDeviation.keys())[0].Document
    if doc is None:
        QtWidgets.QMessageBox.information(mw,'Attention',\
            "Vous n'avez pas de document ouvert")
        return ''
    if doc.FileName=='':
        QtWidgets.QMessageBox.information(mw,
             'Attention','Sauvez votre document avant de relancer la commande') 
        return ''
    return(os.path.splitext(doc.FileName)[0]+'.stl')

def memoriseObjEtDeviation(selection,deviationImpose):
    """
    Mémorise les Body qui sont contenus dans selection et leur
    propriété deviation et remplace cette dernière par la valeur 
    de deviationImpose
    Elle impose un recompute ultérieur par un touch.
    Recompute() doit être éventuellement lancé après

    Arguments :
        selection : une sélection d'objets
        deviationImpose (float) : valeur que l'on veut imposer à deviation

    Returns: 
        un dictionnaire contenant l'objet en key et la déviation en value
        Renvoie {} s'il n'y a pas d'objet adéquate dans la sélection

    Example:
        memoriseBodyEtDeviation(Gui.Selection.getSelection(),deviation)
    """
    dicoObjDeviation={}
    for objData in selection :
        if objData.isDerivedFrom('Part::Feature') \
          and not objData.isDerivedFrom('PartDesign::Feature')\
          and not objData.isDerivedFrom('Part::Part2DObject'):
            dicoObjDeviation[objData]=objData.ViewObject.Deviation
            objData.ViewObject.Deviation=deviationImpose 
           # pour imposer un recompute même si la déviation est plus petite
           # qu'avant :
            objData.touch()
            for o in objData.ViewObject.claimChildren():
                    o.touch()
    return dicoObjDeviation

def restitueDeviation(dicoOrigineDeviation):
    """
    Fonction qui remplace la propriété deviation dans les objets
    Elle impose un recompute par un touch. recompute() doit être
    lancé après

    Arguments:
        dicoOrigineDeviation un dictionnaire contenant l'objet en key 
        et la valeur à imposer dans la propriété déviation de l'objet
        en value

    Returns: Ne retourne rien

    Example:
        restitueDeviation(dicoOrigineDeviation)

    """
    for ob2 in dicoOrigineDeviation:
        ob2.ViewObject.Deviation=dicoOrigineDeviation[ob2]
        # pour imposer un recompute même si la déviation est plus petite
        # qu'avant :
        ob2.touch()
        for o in ob2.ViewObject.claimChildren():
            o.touch()

def openFile(fileName):
    """
    fonction qui lance un fichier en fonction du système d'exploitation
    vérifié pour l'instant uniquement sous windows

    Arguments:
        fileName (string) le nom du fichier à lancer

    Returns
        Ne retourne rien

    Example: 
        openFile(unfichier.stl)
        openFile(calc.exe)
    """
    if sys.platform == "win32":
        os.startfile(fileName)
    else:
        opener ="open" if sys.platform == "darwin" else "xdg-open"
        #subprocess.call([opener, fileName]) #le problème avec call est que freecad est bloqué en attendant que l'on sorte de l'application
        subprocess.Popen([opener, fileName],close_fds=True) 

def recalcul(dicoObjs):
    """
    lance un recompute pour chaque Document des objets du dico
    seulement si cela n'a pas déjà été fait
    Arguments:
        dicoObjs un dictionnaire contenant l'objet en key 

    Returns
        Ne retourne rien

    Example:
        recalcul(dicoMesObjets)
    """
    docDejaRecalcul=[]
    for obj in dicoObjs:
        if obj.Document not in docDejaRecalcul:
            print('recompute {}'.format(obj.Document.Name))
            obj.Document.recompute()
            docDejaRecalcul.append(obj.Document)

def lanceCommmandes(commandesAlancer,fileStlName,formBoiteDialogueSTL):
    """
    lance les commmandes
    Arguments:
        commandesAlancer sous la forme d'un tableau de tableaux
        (['commande à exécuter', 'paramètres','extention ,'question à poser'],
         ['commande à exécuter', 'paramètres','extention ,'question à poser'])

         'commande à exécuter' : la commande que vous voulez exécuter. 
         Par exemple 'monProgramme.exe' si besoin mettre aussi son chemin. 
         'parametres' : si votre programme a besoin de paramètres. Ne sera pris en compte que
             si extention=''#
         'extention': si non vide, le paramètre sera le nom de votre
              fichier FreeCAD mais avec votre extension :
          'question à poser' : la question à afficher dans la boite de dialogue

    Returns
        Ne retourne rien

    Example:
            lanceCommmandes(commandes,fileStlName) # lance les commandes que l'on a décrites dans commandes
    """


    for i in range(len(formBoiteDialogueSTL.tabCheckboxTextCommandes)) :
        if formBoiteDialogueSTL.tabCheckboxTextCommandes[i].isChecked() :
            commande=commandesAlancer[i]
            #print('{}'.format(commande))
            commandeEtParam=commande[0]
            extFileNameParamCommandeALancer=commande[1]
            textAutreCommandeALancer=commande[2]
            delai=0
            print('commande[3:4]----------' )           
            print(commande[3:4])
            try :
               if commande[3:4]!=[] : #si l'utilisateur a rentré un délai
                  delai=commande[3]
            except :
               print ('Délai non pris en compte car valeur numérique non valide'+
                      'pour la commande '+ textAutreCommandeALancer)
            if delai > delaiMax :
                delai=delaimax

            if extFileNameParamCommandeALancer!='':     
                if commandeEtParam[2:3]==[]  : # Il n'y a pas de paramètre.
                   # On ajoute un élément pour y mettre notre nom de fichier
                   # avec notre extension.
                   commandeEtParam.append('')
                commandeEtParam[1]=   os.path.splitext(fileStlName)[0]+  extFileNameParamCommandeALancer
            subprocess.Popen(commandeEtParam,close_fds=True)
            print ('------delai---------')
            print(commandeEtParam)
            print(delai)
            time.sleep(delai)# Pause de durée delai secondes   


def run(objs=Gui.Selection.getSelection(), dev=deviation):
    """
    fonction principale
    Arguments:
        doc : le document actif
        objs : les objets que l'on a au préalable sélectionnés
        dev : la valeur de la propriété déviation qui sera 
              imposée avant la génération du stl

    Returns
        Ne retourne rien

    Example:
        run()
    """


    """dev, reply = QtWidgets.QInputDialog.getDouble(mw, 'Option de précision',\
        'Entrée la déviation souhaitée. {} conseillé pour ne pas voir de facettes. '.format(dev),\
        dev, 0.00, 1.0, 2) # valeur par défaut, min, max et décimales.
    if not(reply):   # (Cancel)
        return
    """

    # Boite de dialogue de ce que l'on veut faire
    formBoiteDialogueSTL = BoiteDialogueSTLGuiClass()
    formBoiteDialogueSTL.exec_()
    if formBoiteDialogueSTL.result==userCancelled:
        return
    dev=float(formBoiteDialogueSTL.precision.text())

    # on mémorise les  body sélectionnés et leur déviation,
    # on fait un touch() de leur child pour prise en compte dans recompute :
    dictionnaireOrigineDeviation=memoriseObjEtDeviation(objs,dev)
    if len(dictionnaireOrigineDeviation)==0: # si on a trouvé aucun body
        QtWidgets.QMessageBox.information(mw, 'Attention',\
            'Sélectionnez un ou plusieurs body avant de lancer la macro')
        return
    # on récupère le nom du fichier où l'on devra enregistrer le stl
    fileStlName=nameFileStl(dictionnaireOrigineDeviation)
    if fileStlName == '' :
        return

    # l'export lui-même. On passe en paramètre les objets body qui 
    # sont dans dictionnaireOrigineDeviation
    if formBoiteDialogueSTL.checkboxGenererSTL.isChecked():
       Mesh.export(list(dictionnaireOrigineDeviation.keys()), fileStlName) 
       print('Export fait')
    # restitution de la propriété deviation d'origine pour les body :
    restitueDeviation(dictionnaireOrigineDeviation)
    recalcul(dictionnaireOrigineDeviation)

    if formBoiteDialogueSTL.checkboxLancerSTL.isChecked():
            #lance par exemple cura si cura a été associé aux fichiers *.stl
            openFile(fileStlName)
    """
    if doitLancerFichier:
        if QtWidgets.QMessageBox.Yes == QtWidgets.QMessageBox.question(mw, '',\
               'Lancer le fichier {}'.format(fileStlName) +
               " ?(nécessite l'association de l'extension stl à un programme)", \
                QtWidgets.QMessageBox.Yes|QtWidgets.QMessageBox.No,\
                    QtWidgets.QMessageBox.No) : 
            #lance par exemple cura si cura a été associé aux fichiers *.stl
            openFile(fileStlName)
    """
    lanceCommmandes(commandes,fileStlName,formBoiteDialogueSTL) # lance les commandes que l'on a décrites dans commandes


if __name__ == '__main__':
    run()




mario
Que de nouvelles possibilités pour moi !!
Entre les icones et surtout les paramètres, ça ouvre des horizons !
FreeCAD est vraiment un grand logiciel avec de grandes possibilités...
J'ai commencé à regarder et je crois que je comprends :D, je regarderai dans le détail dès que possible,dans plusieurs jours car comme je le disais mes enfants sont là pour Noël. :D et c'est prenant aussi ces choses là !
Macro Sketch Constraint From Spreadsheet :
https://wiki.freecad.org/Macro_Sketch_C ... adsheet/fr
User avatar
2cv001
Posts: 484
Joined: Wed Jan 01, 2020 9:30 am

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by 2cv001 »

flachyjoe wrote: Fri Dec 18, 2020 4:11 pm
openBrain wrote: Fri Dec 18, 2020 3:56 pm Mario t'a proposé une solution basé sur les paramètres de FreeCAD.
Nb : on peut créer un fichier UI avec QTDesigner et le plugin spécial pour ajouter une page dans la boite de dialogue des préférences.

Code: Select all

FreeCADGui.addPreferencePage (os.path.join(chemin,"Fichier_pref.ui"), "Nom de la page")

Si ton code commence à être gros, il faut peut-être penser à en faire un Atelier. C'est plus facile d'en gérer le code mais peut-être un peu plus lourd pour l'utilisateur qui doit aller le chercher dans la boite déroulante.
Là aussi, que de nouveautés pour moi. A regarder aussi avec attention; je ne savais même pas qu'une macro pouvait être inclue dans un atelier que l'on pouvait soit même créé sans passer par les instances officielles.
Merci pour ces horizons à découvrir !
Macro Sketch Constraint From Spreadsheet :
https://wiki.freecad.org/Macro_Sketch_C ... adsheet/fr
drum22
Posts: 315
Joined: Sun Mar 14, 2021 1:04 pm

Re: Macro pour obtenir un stl avec des arrondis parfait

Post by drum22 »

Forthman wrote: Sat Nov 14, 2020 1:44 pm Perso j'utilise toujours l'atelier Mesh Design pour exporter des STL
.../...
Bonjour,
dans le Gestionnaire de Addon, je ne trouve pas le "Mesh Design"... son equivalent : c est "Mesh Remodel" ou ca n a rien a voir ?

De la meme maniere, j avais vu un tuto avec un atelier "Gear", introuvable lui aussi ! :o
il y a bien un "FcGear" mais est ce pareil... qui est qui ?
Pourquoi dans certains cas, certains ateliers dits obsoletes restent (Drawing VS TechDraw) et que dans d autres je ne trouve nulle trace, comme ici, d un atelier utilise ?! (sans doute devenu obsolete) :?

Dans l idee, je veux bien jouer a Fantasia avec les installations/desinsatallations de AddOns...
Mais le retrait des Ateliers (qui ne plaisent pas) se fait il proprement ou a la longue, ca finit par polluer l ensemble de FreeCad ?

Merci de vos retours sur ces points
a++
En Angleterre, tout est permis, sauf ce qui est interdit. En Allemagne, tout est interdit, sauf ce qui est permis. En France, tout est permis, même ce qui est interdit. En U.R.S.S., tout est interdit, même ce qui est permis (Winston Churchill)
User avatar
Forthman
Veteran
Posts: 2668
Joined: Fri Apr 27, 2018 11:23 am
Location: Tarn-et-Garonne (82)

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by Forthman »

Mesh Design n'est pas en Addon, c'est un des ateliers déjà installé ;)

Pour installer l'atelier Gear c'est bien l'addon FcGear (jamais compris pourquoi il n'avait pas me même nom)

Les addons s'installent dans ton répertoire de configuration personnelle de freecad, donc ça ne pollue pas vraiment, au pire tu l'effaces
pour repartir avec un freecad propre :mrgreen:
drum22
Posts: 315
Joined: Sun Mar 14, 2021 1:04 pm

Re: Macro pour obtenir un stl avec des arrondis parfaits / Piloter octoprint

Post by drum22 »

Merci ForthMan !! ;)
:( Hou la la ! va falloir que je m'trouve un bon ophtalmo, moi !! :lol: :lol:
faut dire que les ateliers pas tries, c est pas trop commode !! mais on va faire avec... voila tout ! ;)

Comme ma machine n est pas trop puissante, je suis un peu obnubile par les install/desinstall que Windaube gere si mal et s auto-pollue ! :?
Donc, j avais bien peur que ce soit "meme motif, meme punition" avec les Add-Ons de FreeCad... quoi !
mais non ! ouf !

j'vais m essayer a "MeshDesign", ca tombe bien, j ai un couvercle 1/2 spherique !!
c est l occasion qui fait le larron !
En Angleterre, tout est permis, sauf ce qui est interdit. En Allemagne, tout est interdit, sauf ce qui est permis. En France, tout est permis, même ce qui est interdit. En U.R.S.S., tout est interdit, même ce qui est permis (Winston Churchill)
Post Reply