Esperimento: script in Lisp

Ciao scriptomani. :slight_smile:

Volevo vedere se riuscivo a usare il Lisp (una specie) per scriptare Rhino,
e ho provato a farmi semplicemente uno script in Python in grado di eseguire istruzioni Lisp.

In rete si trova diverso materiale a riguardo.
E ovviamente si tratta di cose molto piu’ serie e ben fatte.
Ad esempio:

https://norvig.com/lispy.html

Ma, parlando di script per Rhino, a me interessava in particolare
l’interazione con Rhino … cioe’ vedere come fare per utilizzare le librerie per Python
sviluppate da McNeel che utilizziamo normalmente nei nostri script.

Dai miei primi (e forse ultimi :wink: ) test, direi che la cosa funziona si’ e no … :blush:
Le funzioni rhinoscriptsyntax si usano abbastanza comodamente.
Mentre per RhinoCommon la cosa e’ piu’ complicata …
In pratica conviene richiamarlo passando al Lisp il testo con l’istruzione in Python.
… Pure un po’ modificata se dobbiamo usare delle variabili (Lisp). :blush:
Non il massimo della comodita’ …

Come dicevo, ho fatto solo qualche piccola prova, anche perche’ non sono abituato a usare il Lisp e ci fatico parecchio. :roll_eyes:
Ma, dato che ho bell’e che finito le ferie, faccio che postare quello che ho adesso, nella remota possibilita’ che l’argomento interessi qualcuno … :confused:
… Anche se lo script e’ molto rozzo e incompleto, per non parlare di tutti i bug che ci saranno. :confused:

Ho cercato di ispirarmi, per quanto possibile, ad AutoLISP, ma non solo …
ho ‘attinto’ qualcosa anche dal Common Lisp … e da un paio di vecchi libri sul Lisp.
Oltre alle normali funzioni (e forme speciali) Lisp, ci sono delle funzioni ausiliarie, utili, ad esempio, per l’output delle informazioni, per il debug ecc.
Queste funzioni iniziano con la lettera “A” maiuscola.

Qui ci sono un paio di brevi script ‘tradotti’ nel nostro Lisp, con il testo originale in Python sotto.
Il primo usa rhinoscriptsyntax e il secondo RhinoCommon.

(defun a2l(lines)
  (cond(lines
    (setq line(car lines))
    (setq p0(rs "CurveStartPoint" line))
    (setq p1(rs "CurveEndPoint" line))
    (rs "AddLine" p0 p1)
    (rs "DeleteObject" line)
    (a2l (cdr lines)))))

(setq lis(rs "GetObjects" "Arcs to transform ?" 0 T T))
(cond((null lis)(exit)))
(a2l lis)


; import rhinoscriptsyntax as rs

; def main():
;   lis = rs.GetObjects( 'Arcs to transform ?' )
;   for lin in lis:
;     if rs.IsArc( lin ):
;       p0 = rs.CurveStartPoint( lin )
;       p1 = rs.CurveEndPoint( lin )
;       rs.AddLine( p0, p1 )
;       rs.DeleteObject( lin )

; main()

(setq reslin(py "Rhino.Input.RhinoGet.GetLine()"))
(setq res(car reslin))
(setq lin(cadr reslin))
(cond((null lin)(quit)))
(setq resnum(py "Rhino.Input.RhinoGet.GetNumber('Circle Diameter ?',True,10)"))
(setq res(car resnum))
(setq num(cadr resnum))
(cond((not(equal res(py 'Rhino.Commands.Result.Success)))(quit)))
(setq rad(/ num 2.0))
(setq respnt(py "Rhino.Input.RhinoGet.GetPoint('Circle Centre ?',True)"))
(setq res(car respnt))
(setq pnt(cadr respnt))
(cond((null pnt)(quit)))
(setq pla(py "Rhino.Geometry.Plane(var('pnt'),var('lin').Direction)"))
(setq cir(py "Rhino.Geometry.Circle(var('pla'),var('rad'))"))
(setq gid(py "scriptcontext.doc.Objects.AddCircle(var('cir'))"))
(py "scriptcontext.doc.Views.Redraw()")


; import Rhino
; import scriptcontext

; def main():
;   res, lin = Rhino.Input.RhinoGet.GetLine()
;   if not lin:
;     return
;   res, num = Rhino.Input.RhinoGet.GetNumber( 'Circle Diameter ?', True, 10 )
;   if res != Rhino.Commands.Result.Success:
;     return
;   rad = num / 2.0
;   res, pnt = Rhino.Input.RhinoGet.GetPoint( 'Circle Center ?', True )
;   if not pnt:
;     return
;   pla = Rhino.Geometry.Plane( pnt, lin.Direction )
;   cir = Rhino.Geometry.Circle( pla, rad )
;   gid = Rhino.RhinoDoc.ActiveDoc.Objects.AddCircle( cir )
;   scriptcontext.doc.Views.Redraw()

; main()

Per chi volesse provare, lo script si usa naturalmente come un normale script Python.

Nel pulsante possiamo scrivere semplicemente:

-RunPythonScript lisplike.py

In questo caso lo script mostra delle opzioni:
PickFile: per scegliere lo script Lisp da eseguire.
RunConsole: per eseguire comandi Lisp in modo interattivo.
SaveDocs: per salvare su file la (ridottissima) documentazione sulle funzioni Lisp disponibili.
ViewFile: per vedere il contenuto di un file in una finestra di dialogo.
Invece di scegliere un’opzione possiamo scrivere direttamente il nome dello script Lisp da eseguire.

E ovviamente possiamo farci dei pulsanti customizzati per eseguire una delle opzioni o un particolare script Lisp.
Ad esempio:

-RunPythonScript lisplike.py RunConsole

-RunPythonScript lisplike.py SaveDocs

Eccetera.
Oppure per eseguire uno script particolare (“arcs2lines.rls”):

-RunPythonScript lisplike.py arcs2lines.rls

All’inizio dello script ci sono degli alias per i nomi delle funzioni.
Ognuno puo’ adattarli alle sue preferenze/necessita’.

Non mi dilungo oltre.

Nel caso, per le altre informazioni o segnalazioni di bug ecc., chiedete qui. :slight_smile:

Ciao !

lisplike.py (88,2 KB)

3 Mi Piace

lisplike.py (88,8 KB)
… sr1 … :wink:

1 Mi Piace

lisplike.py (91,7 KB)
… e sr2

1 Mi Piace

lisplike.py (93,9 KB)
( 3 )

1 Mi Piace

Bella Emi!
C’era il mio amico Federico che chiedeva a suo tempo in merito a lisp. Non so se ricordi…

Ciao Giuspa.

Si’, l’idea me l’ha data la richiesta di Federico.
Che mi sembra fosse piu’ interessato scriptare GH che Rhino.

Sotto dico quel poco che so io su GH, puo’ darsi che ci siano altri modi di far le cose …
Per questo lascio parlare gli esperti. :slight_smile:
… Ma per quanto ne so io …

Purtroppo questa specie di interprete Lisp ha dei pesanti limiti per quanto riguarda GH.
Riesce a usare abbastanza bene rhinoscriptsyntax, che e’ un normale modulo Python che contiene un elenco di funzioni.
Ma per RhinoCommon invece la faccenda si complica.
RC e’ scritto in C# ed e’ composto da parecchie classi, che a loro volta definiscono costruttori, proprieta’, metodi, sia di classe che di istanza, ecc. (Tutto il solito ‘armamentario’ OOP :wink: )
Inoltre il C# supporta l’overloading, cioe’ metodi diversi ma con lo stesso nome.
Cosa che Python non fa.
Questo gia’ a volte da’ dei grattacapi nei normali script in Python … e far funzionare la cosa eseguendo istruzioni Lisp e’ purtroppo oltre le mie infime capacita’. :blush:

Quindi l’interprete Lisp, per utilizzare RhinoCommon, aggira l’ostacolo eseguendo direttamente istruzioni Python, che devono essere inserite nello script Lisp come stringhe. Con un’ulteriore complicazione per l’accesso alle variabili Lisp …
Per cui il modo piu’ semplice di utilizzare lo script (l’interprete) con GH credo sia limitarsi all’uso di rhinoscriptsyntax.
E personalmente non mi sembra abbia molto senso.
Gia’ il fatto di poter utilizzare rhinoscriptsyntax in GH e’ una forzatura (richiesta a suo tempo da alcuni utilizzatori), in quanto rs utilizza i Guid degli oggetti nella ObjectTable di Rhino, e GH non usa gli oggetti Rhino, ma usa direttamente gli oggetti geometrici di RhinoCommon. E non ha nessuna ObjectTable.
… Ma per utilizzare rhinoscriptsyntax e’ costretto a costruirsi una ObjectTable ‘farlocca’. :wink:

Alla fine non poter utilizzare RhinoCommon in GH risulta molto penalizzante, ti toglie la maggior parte delle possibilita’. :confused:

Pero’ … :wink:
Ho letto che Steve vuole rendere Rhino 8 scriptabile con CPython. (Ottima cosa, BTW :grinning:)
Bisogna vedere come fara’ per poter accedere a RhinoCommon da CPython.
Senz’altro lui sa come fare …
Suppongo che questo ‘meccanismo’ potrebbe essere una via per superare i problemi di cui sopra.
… Ammesso che CPython approdi poi anche su GH …

Vedremo quando appariranno queste novita’ nella WIP Rhino 8 … :slight_smile:

Oppure, come dicevo sopra, se qualcuno conosce un modo per evitare questi problemi … ottimo ! :grinning:
l’interprete e’ li’ disponibile. Ognuno puo’ farci quello che vuole. :slight_smile:

2 Mi Piace

Ciao Emilio

scrivere un linguaggio di programmazione / interprete non è uno scherzo … :sunglasses:
A leggere il codice lisp ho provato la stessa sensazione che provavo tanti anni
fa con il fortran 90 :woozy_face: :woozy_face: :woozy_face:
Passo. :smiley:

Sergio

Ciao Sergio

Come sai, c’e’ modo e modo di fare le cose (in questo caso gli intepreti) :wink:
Dal lavoro professionale, completo, affidabile, efficiente ecc. ecc. …
Al giochino fatto per divertimento, alla buona e senza nessuna pretesa.
Ovviamente qui siamo nel secondo caso … :grinning_face_with_smiling_eyes:

Se sbirci nel link che avevo postato sopra ci trovi un mini-interprete, fatto in questo caso da un esperto,
per (un dialetto del) Lisp che consiste di circa 120 istruzioni.
Ovvio che un compilatore per Common Lisp sia una cosa neanche lontanamente paragonabile. :grinning:

Pero’ il Lisp si presta molto bene a queste cose (i giochini).
Non so se ti ci sei mai interessato, ma concettualmente e’ semplicissimo, non c’e’ nemmeno differenza tra programmi e dati, cioe’ il formato e’ lo stesso. E la sintassi e’ sempre uguale.
Io lo trovo assolutamente geniale. :grinning:
Come semplicita’ credo sia paragonabile solo al Forth.
Concordo che non sia semplicissimo da leggere … :grinning_face_with_smiling_eyes:
Ogni sintassi diversa da quella a cui siamo abituati e’ dura da capire … :sweat:
Io il Fortran lo avevo studiato a scuola (era ancora il Fortran IV) … ma ovviamene ormai non mi ricordo niente. :grinning_face_with_smiling_eyes:

Tanti anni fa avevo comprato un libro sull’APL … non sono mai riuscito a capirci una cippa … terribile ! :scream: :grinning_face_with_smiling_eyes:

1 Mi Piace

lisplike.py (94,3 KB)
( 4 )

lisplike.py (95,6 KB)
( 5 )

Ciao

… Ormai GH e’ imprescindibile …
:wink:
Quindi sto cercando di utilizzare il Lisp con GH.
Ho portato sul Lisp alcune funzioni di RhinoCommon … poche ovviamente … per poter fare qualcosa con gli oggetti geometrici piu’ agevolmente.
( E vorrei aggiungerne ancora qualcuna … )

Qui c’e’ lo script Python in due versioni:
Per gli script di Rhino e come modulo da importare per gli script di GH
( E’ sempre lo stesso script, cambia solo l’ultima linea :slight_smile: )

lisplike.py (195,4 KB)

lisplikelib.py (195,4 KB)

Aggiungo un file con un minimo di documentazione:

lisplikedoc.txt (32,2 KB)

Per generare il file di documentazione c’e’ la funzione Lisp SaveDocs
Oppure si puo’ fare da un pulsante Rhino in questo modo:

Qui c’e’ un esempio di script Lisp che costruisce un arco per 3 punti:
(A destra c’e’ un componente che mostra il file di documentazione, non c’entra con l’arco.)

Per eseguire il Lisp usiamo un componente script per Python.
Le istruzioni in Python sono quelle mostrate.
Bisogna pero’ elencare i parametri in entrata e in uscita per il Lisp.
Per questo si editano le liste ‘input’ e ‘output’ nello script.
Qui ad esempio in input abbiamo ‘p0’, ‘p1’ e ‘p2’ mentre in output c’e’ solo ‘a’.
Lo script Python ha alcuni altri input:
‘debug’ e’ un booleano per avere informazioni di debug su ‘out’
a ‘load’ possiamo collegare i nomi di eventuali librerie Lisp utilizzate nel nostro script
a ‘lisp’ infine colleghiamo il nostro script in (pseudo) Lisp.
Al componente Python, caso per caso, aggiungiamo poi i vari parametri in input e output per lo script Lisp.
Qui sono ‘p0’, ‘p1’ 2 ‘p2’ in input e ‘a’ in output.

Il tutto e’ piuttosto macchinoso, ma non sono riuscito a fare di meglio …

lisp-7.gh (17,2 KB)

Ho inserito anche un modo per generare il codice Lisp da un oggetto (non tutti, le trimmate per esempio no), in modo da poterlo ricostruire da Lisp.

Questo e’ un esempio sempre con l’arco visto sopra, ma in questo caso dall’arco ricaviamo poi le istruzioni Lisp e infine lo ricostruiamo tramite quelle.

lisp-9.gh (18,5 KB)

… Work in progress, come sempre … :neutral_face:

dai che tutto sommato, superato lo scoglio iniziale della differenza tra scritto/grafico, non’é così differente.
alla fine prima si poteva copiare il codice, adesso invece inserisci il componente che contiene il codice.

ps dici sempre che non sei esperto, ma con Gh ti ho visto fare definizioni non proprio semplici. . . .

Ciao Salvio

Non intendevo lamentarmi … :slight_smile:
Era solo una constatazione: mi sembra che GH attiri molti utilizzatori, almeno da quanto si legge nei forum.
Come attira molti condivisori, se posso usare questa parola. Mi riferisco a chi sviluppa gli Add-On e poi li rende disponibili, spesso gratuitamente.
Quella di GH e’ senza dubbio una gran bella comunita’. :grinning:
Niente in contrario, naturalmente, anzi !
A volte anch’io mi diverto con GH, pur nei limiti della mia scarsa conoscenza (fidati ! :grinning_face_with_smiling_eyes:) dello strumento.

Direi che e’ complementare agli script classici, almeno per ora.
Ma con Grasshopper Player sta andando nella direzione di una migliore integrazione con l’ambiente Rhino …Chissa’ … Forse in futuro si arrivera’ ad unificare GH e scripting. :grinning:

1 Mi Piace

Versione 9 ottobre

lisplike.py (216,4 KB)

lisplikelib.py (216,4 KB)

Esempio su GH

lisp-10.gh (18,5 KB)

ciao Emilio, cercando in rete “script in Lisp” leggo che è un linguaggio compilate/interpretate

se ho compreso bene, tramite Python riesci ad interagire e quindi a usare Lisp?

in tal caso quali sono le differenze/vantaggi di tutto ciò?

Ciao Salvio.

… E’ solo uno dei miei soliti giochini. :grinning:

Esatto … una specie di Lisp ‘fatto in casa’. :wink:

Non so se ricordi … tempo fa un utilizzatore aveva chiesto qui sul forum se fosse possibile usare il Lisp con Rhino (o GH).
Di solito questo succede a chi proviene da AutoCAD, che storicamente utilizza il suo AutoLISP per lo scripting, anche direttamente dalla command line, per cosi’ dire.
O almeno cosi’ mi sembra di capire … purtroppo non conosco AutoCAD.

Comunque, questo mi ha dato l’idea di cercare un modo per utilzzare il Lisp (o una cosa che cerca di assomigliargli) con Rhino e GH.
Confesso che il Lisp mi ha sempre affascinato … anche se in pratica non lo so usare. :grinning_face_with_smiling_eyes:

Non credo ci siano dei vantaggi, anche perche’ l’uso su GH e’ particolamente macchinoso …
Come dicevo … e’ solo un giochino (pieno di bug naturalmente).
E ho spudoratamente approfittato di quella (vecchia) richiesta del nostro amico per postarlo sul forum …
:blush:

quindi se ho capito bene, AutoCad per gli script non usa gli stessi linguaggi di Rhino, e quindi questa
persona avendo realizzato alcuni script in Lisp aveva chiesto se ci fosse un modo per “travasarli”
domanda: ma per interagire con Lisp in Python, poi bisogna importare un modulo che intermedi?

ps ma la barra delle icone nella parte superiore dell’ultima foto che hai postato si tratta di Rhino giusto?
vedo tante icone strane :thinking: (sai giusto per “non” farmi gli affari tuoi) :joy: :rofl:

Eh … non lo so. :confused:
Credo che il Lisp sia stato il primo linguaggio di scripting usato da AutoCAD.
Forse ora ce ne sono anche altri …

Questo lo vedrei difficile, perche’ AutoCAD ovviamente ha i suoi comandi di scripting per interagire con il CAD.
Non so se si possano usare gli stessi comandi anche per Rhino … mi sembra difficile.
Credo che al massimo lo scripting in Lisp possa servire a scrivere nuovi script per Rhino senza dover imparare un nuovo linguaggio.
Ma certo per un utilizzo serio ci vorrebbe uno strumento di scripting altrettanto serio.
(non un giochino :wink: )

Certo, c’e’ GH ‘sopra’ … :grinning_face_with_smiling_eyes:

Ah, se e’ per questo ne ho molte di piu’ (di icone strane)
:grinning_face_with_smiling_eyes:

… Anche se vorrei ‘rifare’ per l’ennesima volta il workspace, cioe’ le varie toolbar visibili.
… Perche’ adesso ne uso di affiancate (lungo la ‘X’ dello schermo, per cosi’ dire)
e ogni volta che apro Rhino le trovo un po’ sparpagliate. :roll_eyes:
Ma non e’ niente di nuovo … lo so (da lungo tempo) che l’unico modo e’ avere toolbar a tutta larghezza.
Devo mettermici …

1 Mi Piace