Scripts: Difference between revisions

From FreeCAD Documentation
Line 176: Line 176:




Esiste sempre un punto di criticità, è riguarda il '''riferimento di costruzione''', cioè il punto il base al quale è costruiyo l'oggetto.
Esiste sempre un punto di criticità, è riguarda il '''riferimento di costruzione''', cioè il punto il base al quale è costruito l'oggetto, questa tabella, copiata da [[Placement/it|Posizionamento]]:



{| class="wikitable" border="1"
!Geometria!!Riferimento di Costruzione
|- align="left"
|Part::Box ||vertice sinistro (minimo x), frontale (minimo y), in basso (minimo z)
|- align="left"
|Part::Sphere||centro della sfera (centro del suo contenitore cubico)
|- align="left"
|Part::Cylinder||centro della faccia di base
|- align="left"
|Part::Cone||centro della faccia di base (o superiore se il raggio della faccia di base vale 0)
|- align="left"
|Part::Torus||centro del toro
|- align="left"
|Caratteristiche dervate da Sketch||la caratteristica eredita la posizione dello schizzo sottostante. Lo schizzo inizia sempre con Position = (0,0,0).
|}


Queste informazioni sono da tenere ben presente quando volete usare una rotazione.

Facciamo qualche esempio, cancellate tutte le righe dopo il metodo '''base_cyl''' ed inserite queste righe


<nowiki>
<nowiki>


def sfera(nome, rad):
obj = DOC.addObject("Part::Sphere", nome)
obj.Radius = rad
DOC.recompute()


return obj


def mfuse_obj(nome, objs):
obj = DOC.addObject("Part::MultiFuse", nome)
obj.Shapes = objs
obj.Refine = True
DOC.recompute()

return obj


def aeroplano():

lung_fus = 30
diam_fus = 5
ap_alare = lung_fus * 1.75
larg_ali = 7.5
spess_ali = 1.5
alt_imp = diam_fus * 3.0
pos_ali = (lung_fus*0.70)
off_ali = (pos_ali - (larg_ali * 0.5))

obj1 = base_cyl('primo cilindro', 360, diam_fus, lung_fus)

obj2 = cubo('ali', ap_alare, spess_ali, larg_ali, True, off_ali)

obj3 = sfera("naso", diam_fus)
obj3.Placement = FreeCAD.Placement(Vector(0,0,lung_fus), FreeCAD.Rotation(0,0,0), Vector(0,0,0))

obj4 = cubo('impennaggio', spess_ali, alt_imp, larg_ali, False, 0)
obj4.Placement = FreeCAD.Placement(Vector(0,alt_imp * -1,0), FreeCAD.Rotation(0,0,0), Vector(0,0,0))

objs = (obj1, obj2, obj3, obj4)

obj = mfuse_obj("Forma esempio", objs)
obj.Placement = FreeCAD.Placement(Vector(0,0,0), FreeCAD.Rotation(0,0,0), Vector(0,0,0))
obj.Placement = FreeCAD.Placement(Vector(0,0,0), FreeCAD.Rotation(0,0,-90), Vector(0,0,pos_ali))

DOC.recompute()

return obj


aeroplano()

setview()


</nowiki>
</nowiki>


[[File:Aereo.png|thumb|l'aereo di esempio]]


Analizziamo il codice:


* Abbiamo definito un metodo per creare una sfera, abbiamo usado la definizione più semplice, definendo solo il raggio.
* Abbiamo introdotto una seconda forma per l''''Unione''' quella multipla, niente di speciale, notate solo che alla proprietà '''Shapes''' abbiamo passato una '''tupla'''
* Abbiamo definito una forma complessa, in modo '''"parametrico"''', cioè definendo alcuni parametri e mettendo delle formule che calcolano in modo automatico molti dei valori da passare alla geometria finale.
* Abbiamo usato prima di ritornare l'oggetto un posizionamento usando la poprietà rotation e il Vettore finale del grupo che definisce il '''centro di rotazione'''





Revision as of 15:49, 2 March 2020

Introduzione allo Scripting

Per Scripting intendiamo l'uso dell'interprete Python interno di FreeCAD per generare oggetti, FreeCAD può essere usato come "ottimo" sostituto di OpenSCAD, anche perché possiede un vero e proprio interprete Python, con il pieno supporto per tutti i costrutti di un linguaggio di programmazione, quasi tutto quello che si può realizzare con l'interfaccia grafica è possibile realizzarlo attraverso un programma Python.

Le informazioni sullo scripting sono però sparse nella documentazione di FreeCAD, non c'è una uniformità di "scritture" e alcune cose sono spiegate in maniera complicata per chi comincia.


Primo assaggio

Purtroppo non esiste un modo per attivare l'editor di Python interno, però c'è un trucco, FreeCAD apre un file con estensione .py nell'editor interno di Python, niente di più semplice che creare un file con il vostro editor di testo preferito, poi aprirlo con FreeCAD.

Il modo più semplice è quello di battere queste poche righe:

"""script.py

   Primo script per FreeCAD

"""

Salvarlo e caricarlo in FreeCAD.


Il minimo indispensabile per lavorare in modo proficuo con FreeCAD è scrivere queste righe, che potete tranquillamente usare come modello:

"""nome del file.py

   Descrizione di quello che fa lo script

"""


import FreeCAD
from FreeCAD import Base, Vector
import Part
from math import pi, sin, cos

DOC = FreeCAD.activeDocument()
DOC_NAME = "Pippo"

def clear_doc():
    """
    Clear the active document deleting all the objects
    """
    for obj in DOC.Objects:
        DOC.removeObject(obj.Name)

def setview():
    """Rearrange View"""
    FreeCAD.Gui.SendMsgToActiveView("ViewFit")
    FreeCAD.Gui.activeDocument().activeView().viewAxometric()


if DOC is None:
    FreeCAD.newDocument(DOC_NAME)
    FreeCAD.setActiveDocument(DOC_NAME)
    DOC = FreeCAD.activeDocument()

else:

    clear_doc()

# EPS= tolerance to uset to cut the parts
EPS = 0.10
EPS_C = EPS * -0.5



Alcuni trucchi sono incorporati in questo codice:


  • import FreeCAD Questo serve per importare FreeCAD all'interno dell'interprete Python, può sembrare superfluo, ma non lo è
  • from FreeCAD import Base, Vector Base e Vector sono molto usati, vi risparmiano molto test da battere se non fate dovete scrivere ad esempio FreeCAD.Vector ogni volta che usate un Vettore


Partiamo con un piccolo script che fa poco, ma illustra la potenza di questo approccio.


def cubo(nome, lung, larg, alt):
    obj_b = DOC.addObject("Part::Box", nome)
    obj_b.Length = lung
    obj_b.Width = larg
    obj_b.Height = alt

    DOC.recompute()

    return obj_b

obj = cubo("cubo_di_prova", 5, 5, 5)

setview()



Mettetelo dopo il primo codice e premete la freccia della Barra di strumenti Macro

e vedrete che si apre un nuovo file chiamato Pippo e si visualizza un cubo nella Vista 3D,

Cubo di prova

Qualcosa in più

Niente di eccezionale, quanto ci si può aspettare da un cubo, la stessa cosa possiamo fare con un cilindro, aggiugenete queste linee dopo il metodo che crea il cubo e prima della riga obj = cubo(...

def base_cyl(nome, ang, rad, alt ):
    obj = DOC.addObject("Part::Cylinder", nome)
    obj.Angle = ang
    obj.Radius = rad
    obj.Height = alt
    
    DOC.recompute()

    return obj   



Anche qui nulla di eccezionale, notiamo alcune nella costruzione del codice:

  • L'assenza dei riferimenti usuali in molta documentazione ad App., è pienamente voluto, in futuro si potrà riusare il codice per accedere a FreeCAD dall'esterno di FreeCAD, e sarà necessario importare FreeCAD come un normale modulo Python, con alcune accortezze. La scelta è volut anche nel solco degli standard di Python per cui è meglio sapere sempre da dove arrivano le cose, ovviamente App è poco significativo.
  • La definizione all'inizio di una "costante" DOC, per contenere FreeCAD.activeDocument(), ovviamente il nome "costante" è solo considerando dal punto di vista semantico il nostro "documento attivo", da qui l'uso della convenzione del nome "TUTTO MAIUSCOLO" per le "costanti".
  • ogni metodo ritorna un geometriao, questo diventerà importante fra poco.
  • la creazione della geometria non comporta la proprietà Placement, se si utilizzano geometrie semplici per creare geometrie più complesse, la gestione della proprietà Placement è una cosa delicata.

Ora dobbiamo pur farci qualcosa con questi oggetti, be introduciamo le operazioni booleane, un esempio di metodo che compie un'operazione di Unione è questo:

def fuse_obj(nome, obj_0, obj_1):
    obj = DOC.addObject("Part::Fuse", nome)
    obj.Base = obj_0
    obj.Tool = obj_1
    obj.Refine = True
    DOC.recompute()

    return obj


anche qui nulla di eccezionale, notate però l'uso di molta uniformità nel codice, aiuta molto quando si vuole fare copia e incolla nella creazioni complesse.

Inseriamo dopo il metodo base_cyl le righe sopra e modifichiamo quelle sotto in modo da leggere:


# definizione oggetti

obj = cubo("cubo_di_prova", 5, 5, 5)

obj1 = base_cyl('primo cilindro', 360,2,10)

fuse_obj("Fusione", obj, obj1)

Lanciamo con il tasto freccia della barra strumenti macro e otteniamo:

cubo e cilindro

Posizionamento

Il concetto è relativamente complesso, vedere Tutorial aeroplano per una trattazione più sistematica.

Possiamo aver bisogno di posizionare una geometria in una posizione relativa ad un'altra geometria, cosa abbastanza frequente, l'uso più comune è usare la proprietà Placement della geometria.

Ovviamente le possibilità su come specificare questa proprietà sono molte, alcune complesse da capire, questa scrittura della proprietò Placement, soprattutto per quanto riguarda la parte Rotation è in linea con quanto spiegato nel Tutorial citato e sembra il più gestibile.

  
FreeCAD.Placement(Vector(0,0,0), FreeCAD.Rotation(10,20,30), Vector(0,0,0))


Esiste sempre un punto di criticità, è riguarda il riferimento di costruzione, cioè il punto il base al quale è costruito l'oggetto, questa tabella, copiata da Posizionamento:


Geometria Riferimento di Costruzione
Part::Box vertice sinistro (minimo x), frontale (minimo y), in basso (minimo z)
Part::Sphere centro della sfera (centro del suo contenitore cubico)
Part::Cylinder centro della faccia di base
Part::Cone centro della faccia di base (o superiore se il raggio della faccia di base vale 0)
Part::Torus centro del toro
Caratteristiche dervate da Sketch la caratteristica eredita la posizione dello schizzo sottostante. Lo schizzo inizia sempre con Position = (0,0,0).


Queste informazioni sono da tenere ben presente quando volete usare una rotazione.

Facciamo qualche esempio, cancellate tutte le righe dopo il metodo base_cyl ed inserite queste righe


def sfera(nome, rad):
    obj = DOC.addObject("Part::Sphere", nome)
    obj.Radius = rad
    
    DOC.recompute()

    return obj   


def mfuse_obj(nome, objs):
    obj = DOC.addObject("Part::MultiFuse", nome)
    obj.Shapes = objs
    obj.Refine = True
    DOC.recompute()

    return obj


def aeroplano():

    lung_fus = 30
    diam_fus = 5
    ap_alare = lung_fus * 1.75
    larg_ali = 7.5
    spess_ali = 1.5   
    alt_imp = diam_fus * 3.0  
    pos_ali = (lung_fus*0.70)
    off_ali = (pos_ali - (larg_ali * 0.5))

    obj1 = base_cyl('primo cilindro', 360, diam_fus, lung_fus)

    obj2 = cubo('ali', ap_alare, spess_ali, larg_ali, True, off_ali)

    obj3 = sfera("naso", diam_fus)
    obj3.Placement = FreeCAD.Placement(Vector(0,0,lung_fus), FreeCAD.Rotation(0,0,0), Vector(0,0,0))

    obj4 = cubo('impennaggio', spess_ali, alt_imp, larg_ali, False, 0)
    obj4.Placement = FreeCAD.Placement(Vector(0,alt_imp * -1,0), FreeCAD.Rotation(0,0,0), Vector(0,0,0))

    objs = (obj1, obj2, obj3, obj4)

    obj = mfuse_obj("Forma esempio", objs)
    obj.Placement = FreeCAD.Placement(Vector(0,0,0), FreeCAD.Rotation(0,0,0), Vector(0,0,0))
    obj.Placement = FreeCAD.Placement(Vector(0,0,0), FreeCAD.Rotation(0,0,-90), Vector(0,0,pos_ali))

    DOC.recompute()

    return obj


aeroplano()

setview()


l'aereo di esempio


Analizziamo il codice:

  • Abbiamo definito un metodo per creare una sfera, abbiamo usado la definizione più semplice, definendo solo il raggio.
  • Abbiamo introdotto una seconda forma per l'Unione quella multipla, niente di speciale, notate solo che alla proprietà Shapes abbiamo passato una tupla
  • Abbiamo definito una forma complessa, in modo "parametrico", cioè definendo alcuni parametri e mettendo delle formule che calcolano in modo automatico molti dei valori da passare alla geometria finale.
  • Abbiamo usato prima di ritornare l'oggetto un posizionamento usando la poprietà rotation e il Vettore finale del grupo che definisce il centro di rotazione


Alla prossima!