Analisi del Codice

(premessa: qui riguarda RCommon a prescindere dal linguaggio di programmazione)

qualcuno mi potrebbe dare qualche precisazioni su questa riflessione:

import Rhino
import scriptcontext
 
def HatchCurve():
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt("Select closed planar curve")
    go.GeometryFilter = Rhino.DocObjects.ObjectType.Curve
    go.GeometryAttributeFilter = Rhino.Input.Custom.GeometryAttributeFilter.ClosedCurve
    go.SubObjectSelect = False
    go.Get()
    if go.CommandResult()!=Rhino.Commands.Result.Success: return
 
    curve = go.Object(0).Curve()
    if (not curve or not curve.IsClosed or not curve.IsPlanar()): return
 
    hatch_name = scriptcontext.doc.HatchPatterns[scriptcontext.doc.HatchPatterns.CurrentHatchPatternIndex].Name
    rc, hatch_name = Rhino.Input.RhinoGet.GetString("Hatch pattern", True, hatch_name)
    if rc!=Rhino.Commands.Result.Success or not hatch_name: return
 
    index = scriptcontext.doc.HatchPatterns.Find(hatch_name, True)
    if index<0:
        print "Hatch pattern does not exist."
        return
 
    hatches = Rhino.Geometry.Hatch.Create(curve, index, 0, 1)
    for hatch in hatches:
        scriptcontext.doc.Objects.AddHatch(hatch)
    if hatches: scriptcontext.doc.Views.Redraw()
 
if __name__=="__main__":
    HatchCurve()

abbiamo il metodo Rhino.Input.Custom.GetObject() che assegna un oggetto alla variabile go
poi vengono assegnati i vari parametri per filtrare ecc fino a go.Get() che va a prendere lā€™oggetto

Fin qui ci siamo mossi utilizzando Rhino.Input.Custom

curve = go.Object(0).Curve()

nella riga sopra invece, alla variabile curve viene assegnato lā€™oggetto stesso usando

go.Object(0) che fa sempre parte di Rhino.Input.Custom
anzi piĆ¹ precisamente ĆØ un metodo della classe GetObject()
ma viene anche aggiunta la classe Curve() che fa parte di Rhino.Geometry

if (not curve or not curve.IsClosed or not curve.IsPlanar()): return

per poi (nella riga sopra) verificare se la curva sia chiusa utilizzando per lā€™appunto IsClosed
che ĆØ una proprietĆ  sempre della classe Curve() menzionata alla riga precedente

mi chiedo, a parte il fatto di andarsi a cercare un esempio per ogni azione che si voglia compiere
e quindi guardare la sintassi e adattarla nel proprio caso, ma oltre a ciĆ², a priori, qualā€™Ć© la
logica per sapere quale parte del codice puĆ² essere aggiunta ad unā€™altra?

Provo a dire qualcosa con parole mie.

Forse confonde meno scritto in questo modo:

obref = go.Object( 0 )
curve = obref.Curve()

Dalla documentazione della classe GetObject vediamo che questo metodo
GetObject.Object Method (rhino3d.com)
restituisce un ObjRef ( piuā€™ o meno un riferimento ad un oggetto Rhino )

e dalla documentazione della classe ObjRef vediamo che questo metodo
ObjRef.Curve Method (rhino3d.com)
restituisce una Curve

Quindi qui

Curve non eā€™ una classe, ma un metodo di ObjRef

Gli esempi di solito sono il punto di partenza, ma eā€™ utile cercare di capire come funziona lā€™esempio,
quali oggetti, classi, metodi ecc utilizza, e per fare cosa.
Capire meglio queste cose ci permette di utilizzare cioā€™ che vediamo nellā€™esempio in altre circostanze.
( Vedi sopra lā€™istruzione che ricava la curva. Prima cosa eā€™ capire cosa fa e come funziona.
Chiedere sul forum, come hai fatto, eā€™ un ottimo modo per informarsi.
Copiare senza capire cosa stai copiando puoā€™ essere lā€™ultima alternativa, ma capire cosa succede eā€™ molto piuā€™ utile)

Poi la logica per costruire uno script potrebbe essere grosso modo:
scomporre idealmente lā€™operazione richiesta in operazioni piuā€™ semplici, compresi cicli e scelte, fino ad ottenere operazioni cosiā€™ semplici da poter essere eseguite da un singolo metodo, o proprietaā€™ ecc.
Cercare di capire, da esempi e richieste sul forum, quali dati/classi bisogna utilizzare.
Per ogni operazione, data la classe da utilizzare, cercare nella documentazione un metodo o una proprietaā€™ che faccia cioā€™ che serve.
Ma anche per questo gli esempi (ed eventualmente il forum) danno una grossa mano per individuare il metodo (o proprietaā€™) giusto.

EDIT

Ovviamente, facendo esperienza poco per volte, impari cosa devi utilizzare per fare cosa e inizi a concentrarti su cosa devi fare anzicheā€™ su come farlo, come succede anche per rhinoscriptsyntax, Grasshopper ecc.

non proprio Emilio, passare per altre variabili non mi cambia, questo credo di averlo assimilato ormai

mi pare piĆ¹ che voglia un oggetto, in questo caso una curva essendo che gli ĆØ stato imposto un filtro
che lā€™oggetto selezionato deve avere come attributo una curva e chiusa giusto?

eeee stavo proprio cercando un esempio simile a questo;
avevo notato che in certi casi la nomenclatura ĆØ uguale ma sono due cose distinte e separate
infatti come puoi vedere esiste anche la classe Curve che fa parte di Rhino.Geometry

https://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_Geometry_Curve.htm

infatti ĆØ quello che ho sempre fatto, sia in VBS che IPy, per prima cosa se non sapevo da dove partire chiedevo a voi qui sul forum, e da li anche dopo avermi dato la soluzione disassemblavo la funzione
e vedevo cosa era obbligatorio metterci e cosa no, verificavo ogni singolo passaggio ecc ecc
ma non mi era mai capitato di trovare lo stesso nome sia per una classe che altro

(io ero rimasto alla sintassi consecutiva)

a questo punto credo che una parte dellā€™equivoco sia la mancanza dellā€™assegnazione principale cioe:
la mancanza della parte iniziale che chiama la classe o il metodo. forse mi sarebbe dā€™aiuto una cosa tipo:
nomespace.classe.metodo.proprietĆ 
nomespace.classe.metodo.attributi
nomespace.classe.metodo.ecc

chissĆ  forse in questo modo mi sarebbe piĆ¹ chiaro di chi fa parte ciĆ² che si va a richiamare

rileggendo la citazione sopra, mi porta a capire che un metodo richiama unā€™altro metodo?

Annotazione 2023-02-08 175009

GetObject restituisce ObjRef che ĆØ un metodo mentre dalla foto ObjRef viene riportato prima
come classe e poi sotto mi fa intendere che sono elencati i metodi che fanno parte di essa appunto.

tutto questo mi ha fatto tornare in mente un tuo esempio, dove concatenavi metodi a metodi:

nel tuo caso erano metodi della stessa classe, mentre:
GetObject fa parte di Rhino.Input.Custom
ObjRef invece fa parte di Rhino.DocObjects

quindi funziona anche in questo modo, richiamare prima un metodo da un ns e poi anche da unā€™altro?

GetObject ti fa cliccare un oggetto Rhino, ma lā€™informazione relativa allā€™oggetto cliccato te la daā€™ sotto forma di oggetto ObjRef (istanza della classe ObjRef), quando richiami il metodo Object().
Tu dallā€™ObjRef, tramite il suo metodo Curve(), ricavi la curva, cioeā€™ lā€™istanza della classe Rhino.Geometry.Curve

Parli dei metodi ecc. utilizzati ?
Per capire bene di cosa si tratta ?

Conoscendo il tipo della variabile (cioeā€™ a quale classe appartiene lā€™oggetto contenuto nella variabile), non ci si puoā€™ confondere.
Il metodo (o proprietaā€™) ā€˜attaccatoā€™ tramite il punto alla variabile deve essere un metodo di quella classe.
Non puoā€™ appartenere ad altre classi, per una questione di sintassi del linguaggio.
Non possiamo richiamare un metodo di una classe tramite un oggetto di una classe diversa.

Nello script, ad esempio, la variabile go eā€™ di tipo GetObject
Quindi dopo go e il punto puoā€™ esserci solo un metodo (o proprietaā€™) di GetObject, non di altre classi.

Non un metodo, ma lā€™oggetto restituito dal metodo puoā€™ richiamare a sua volta un suo metodo.
Il metodo Object() di GetObject restituisce un oggetto ObjRef, quindi a questo punto possiamo richiamare un metodo della classe ObjRef

Per quello dicevo che scrivendo due istruzioni anzicheā€™ una confonde meno.
Percheā€™ vedi chiaramente lā€™oggetto restituito da Object(), che a sua volta richiama il metodo Curve().

Come abbiamo visto, ObjRef eā€™ una classe, cioā€™ che restituisce GetObject.Object() eā€™ un oggetto della classe ObjRef.

Infatti eā€™ la stessa cosa.
Ma anche liā€™ ovviamente, ogni metodo restituisce un oggetto, che a sua volta richiama un altro metodo.
I metodi non richiamano altri metodi.
Gli oggetti richiamano i metodi.

Il namespace non cā€™entra niente.
Quello che conta eā€™ la classe a cui appartiene lā€™oggetto in questione.
Quella classe stabilisce quali metodi puoi chiamare.

grazie per la spiegazione :wink:

:+1:

immagine

ma anche GetObject ĆØ una classe
quindi una classe richiama altra classe
ps in conclusione classe = oggetto?

Certo

No, dove vedi una cosa simile ? :slight_smile:

No, ma la relazione eā€™ stretta.
La classe eā€™ il tipo di dati.
E come int o float o string.
Se scrivi

cc = 33

Python riconosce il valore come un int e quindi carica nella variabile un valore di tipo int che vale 33
int eā€™ il tipo di dati.
cc eā€™ un int, nel senso che il valore appartiene a quel tipo di dati.

immagine

se clicco su GetObject Class la guida mi dice che GetObject ĆØ una classe

poi subito dopo cā€™Ć© GetObject Methods

cerco di riepilogare
abbiamo {namespace}Rhino.Input.Custom
usando tale libreria ci permette di chiamare la classe GetObject

go = Rhino.Input.Custom.GetObject()

alla riga sopra GetObject() ĆØ una classe oppure un metodo?
(perchƩ da quello che mi ricordo quando ci sono le parentesi, dovrebbero essere metodi giusto?)

Quello eā€™ semplicemente lā€™elenco dei metodi della classe GetObject

Esatto, se ci sono le parentesi eā€™ un metodo.
Un metodo particolare, chiamato costruttore, che ha lo stesso nome della classe.
Questo qui:
GetObject Constructor (rhino3d.com)

In C# eā€™ piuā€™ semplice riconoscere questi casi, percheā€™ prima del costruttore si scrive new.
Python non scrive niente, per cui un costruttore lo riconosci solo percheā€™ ha il nome della classe ed eā€™ seguito dalle parentesi.

Benvenuto nelle complicazioni della OOP ! :wink: :grinning:

:exploding_head: :exploding_head:

eeee (se non erro nonā€™Ć© la prima volta) ma ci vorrebbe prima un corso per capire come leggere la guida. . .

che cā€™era qualcosa che mi sfuggiva tra la classe ed i metodi mi era chiaro quindi il sunto
del discorso ĆØ che chiamando il costruttore di una classe, chiamo indirettamente anche la classe?

sui costruttori mi sono impegnato ma avevo riassunto alcune cose diversamente:
nel senso che io chiamavo la classe. poi avendo scritto overloading dei costruttori
ti permettevano di richiamarla ognuno con i vari parametri e firme/signature diversi

ma andavo a chiamare direttamente la classe stessa
che mi dava modo di scegliere quali parametri usare
tramite utilizzo del ā€œmetodo/costruttoreā€ desiderato

mentre dalla tua spiegazione, si va a chiamare il metodo/costruttore per avviare la classe

using System;
// using System.Collections.Generic;

class gh
{

  public void RunScript( ref object A )
  {
    var oba = new cla();
    var tex = oba.Disegna();
    A = tex;
  }

}

class cla
{
  public string Disegna()
  {
    return "Disegna da classe cla";
  }
}

scusa se uso un tuo esempio, ma ĆØ giusto per spiegare del perchĆ© avevo inteso la mia versione;
in questo caso, abbiamo due classi, la classe gh col metodo RunScript per richiamare la classe cla
che oltre alla parola chiave new viene scritto cla(), per poi richiamare il metodo Disegna()
quindi abbiamo in entrambi i casi, sia la classe che il metodo con le parentesi
e la classe cla in questo caso non ha nessun metodo/costruttore. . .

(quindi come da esempio sopra avevo inteso che per richiamare un metodo in questo caso Disegna()
si ĆØ obbligati comunque a passare per la sua classe in questo caso cla se poi nella classe sono indicati
i metodi/costruttori, si deve anche rispettare le restrizioni messi coi parametri/firme indicati in questā€™ultimi)

Supergiuā€™ eā€™ quello che stiamo facendo ā€¦ :confused: :smile:
Provo a dire quello che capisco io, poi, soprattutto in questo campo, ho lā€™impressione che ognuno veda le cose a modo suo.
Lā€™importante eā€™ sapere come usare le cose, poi come le chiami non eā€™ importante, almeno fincheā€™ non ci discuti con gli altri ā€¦ :wink:

Le classi non si chiamano.
Come abbiamo detto, una classe eā€™ un tipo di dati, come ā€˜stringā€™.
ā€˜stringā€™ non viene chiamata, la usiamo per indicare/dichiarare che una certa variabile contiene una stringa, cioeā€™ il suo tipo di dati eā€™ ā€˜stringā€™.

I costruttori si chiamano, e hanno lo stesso nome della classe, ma hanno le parentesi dopo.
Sono una cosa diversa, anzi i costruttori appartengono alla classe e servono per costruire oggetti a loro volta appartenenti a quella classe.
Un costruttore della classe Line serve a costruire oggetti di tipo Line, cioeā€™ le linee che utilizza Rhino.
E cosiā€™ via per ogni altra classe.

Tutto giusto, salvo che di solito non diciamo ā€˜chiamare la classeā€™, ma ā€˜chiamare il costruttoreā€™.

La classe non deve essere avviata, non eā€™ una routine.
Eā€™ solo un tipo di dati, che in piuā€™ permette di definire metodi, proprietaā€™ e compagnia bella. :grinning:
Il costruttore lo chiami per ottenere/costruire un oggetto di quella classe.

Giusto.
Cioeā€™ non ha nessun costruttore definito da noi.
Ma quando tu non definisci nessun costruttore, il linguaggio te ne daā€™ uno ā€˜gratisā€™ :wink: .
Per cui un costruttore ā€˜di defaultā€™ eā€™ sempre a disposizione.
per cui possiamo scrivere

utilizzando quel costruttore ā€˜di defaultā€™, per cosiā€™ dire.

1 Mi Piace

io avevo in mente una struttura tipo matriosca che partiva da:

{namespace} . Classi . Metodi/ProprietĆ /ecc

heeee a questo punto mi sa che debbo rivedere tutta la struttura che mi ero costruito sui OOP. . .

(ĆØ un argomento che dovrĆ² riprendere, farĆ² delle prove per poi continuare il post)

ps Emilio, la struttura da me costruita ĆØ crollata come un castello di sabbia ahahahah

domanda: ma lo stesso discorso vale anche usando RCommon con Python in Rhino?
se IPython nonā€™Ć© un linguaggio OOP come fa a gestire classi/metodi ecc?

    class Program
    {
        static void Main(string[] args)
        {
            Classe1 esec1 = new Classe1();
            Console.WriteLine(esec1.Metodo1_1());
            Console.WriteLine(esec1.Metodo1_2());

            Console.ReadLine();
        }
    }

    class Classe1
    {
        private int a;
        private string b;

        public int Metodo1_1() { return a = 100; }
        public string Metodo1_2() { return b = "prova1"; }
    }

Emilio con Eā€™ solo un tipo di dati cosa intendi precisamente?

perchƩ nel codice si vanno a impostare i Metodi come tipi di dati da ritornare: int string bool ecc ecc


edit:

provando a stampare Console.WriteLine(esec1);
mi dice che ĆØ una classe: ConsoleApp9.Classe1

anzi dallā€™output viene specificato che esec1 ā€œĆØā€ la Classe1 del progetto ConsoleApp9

Certamente Python supporta la OOP.
Non ti ricordi le prove che facevi con classi e metodi qualche anno fa ? :grinning:

Una struttura a matrioska puoā€™ essere quella della classi derivate da altre classi.
La famosa ereditarietaā€™ della OOP.
Come ad esempio in RhinoCommon
GeometryBase => Curve => NurbsCurve

Ma parliamo sempre di classi, che certo possiamo organizzare con i namespace, ma eā€™ solo un modo per organizzare progetti con un alto numero di classi, come RhinoCommon.

A noi, come utilizzatori di RhinoCommon interessano le classi e i relativi oggetti.
E ogni classe ha i suoi metodi, proprietaā€™ ecc. Che possiamo richiamare tramite gli oggetti
(o direttamente tramite la classe se sono static, ma cambia poco)

Hai presente in Python quando si parla di int o list, string, dictionary ā€¦
Sono tutti tipi di dati.
Ci dicono cosa eā€™ contenuto in una variabile, se un numero o una stringa o una lista ecc.
Ed eā€™ importante aver presente il tipo di dati dei valori che usiamo.
Se sono numeri possiamo ad esempio dividerli tra loro, se sono stringhe o liste no.
Se sono liste le possiamo indicizzare e quindi individuare uno o piuā€™ elementi, se sono numeri no.
E cosiā€™ via ā€¦
Quelli di cui abbiamo parlato (int, float, list, string eccā€¦) sono tipi di dati nativi di Python.
Sono definiti dal linguaggio e noi li possiamo usare quando vogliamo.
Con la OOP (non solo con la OOP, ma non divaghiamo) possiamo definire altri tipi di dati secondo cosa ci serve.
Tipi di dati diversi da quelli ā€˜standardā€™, come ad esempio in RhinoCommon Curve, View, RhinoObject, Layer ecc. ecc. ecc. ecc.
Questo lo facciamo definendo una nuova classe con i suoi campi, metodi ecc.
Ogni classe definisce un uovo tipo di dati che potremo utilizzare nel nostro script.

Buon esempio.
I valori restituiti da funzioni e metodi hanno il loro bel tipo di dato ben definito.
E quel tipo di dato puoā€™ essere anche una classe ovviamente.

quindi lā€™esempio che avevo fatto con i Metodi int e string non centrano nulla
tu intendevi che la classe ĆØ un tipo di dato come curve ecc

questa era unā€™altra cosa che volevo approfondire; come conoscere di preciso una
classe cosa puĆ² ritornare. credo che sia molto importante avere unā€™ampia visione di ciĆ²

in che senso :thinking: :thinking:

ora anche quel tipo di dati possono essere una classe :exploding_head:

signor Emilio. . . ā€œabbi pietĆ  di meā€

ma nel senso che ad esempio scrivendo int si richiama una classe?

ps comunque Emilio incredibile sei peggio delle torturi cinesi ahahahah


dopo tutta questa teoria un semplice esempio con la pratica
usando prima un metodo e poi una proprietĆ  per poi analizzarlo?

Temo di non capire a cosa ti riferisci ā€¦

Nel senso che oltre che int o string un metodo puoā€™ restituire anche un valore appartenente a una classe ā€¦ che so, una Curve ad esempio.

Lo dicevo.
Queste cose ognuno le interpreta a modo suo.
Se rispondo solo io non hai molti punti di vista da confrontare ā€¦

Non so se eā€™ quello che chiedi, ma qui cā€™eā€™ un semplicissimo esempio che utilizza una proprietaā€™ ed un metodo su un oggetto di classe Curve

import Rhino

ok, obref = Rhino.Input.RhinoGet.GetOneObject( 
    'Curve ?', True, Rhino.DocObjects.ObjectType.AnyObject )
cur = obref.Curve()
p0 = cur.PointAtStart
print p0
lng = cur.GetLength()
print lng

Breve analisi:
Chiediamo allā€™utilizzatore di selezionare una curva tramite GetOneObject
Otteniamo un oggetto di tipo (classe) ObjRef
Da questo, tramite il metodo Curve() otteniamo un oggetto di tipo Curve
Con questo richiamiamo una proprietaā€™ ( PointAtStart ) e un metodo ( GetLength() )
e stampiamo i risultati.

Cosa vuoi sapere ? :slight_smile:

non so da dove inizare, a fare domande ahahahah (ormai mi conosci bene. . .)

immagine

sono andato a vedere un po i metodi usati per capire come muovermi con la guida
faccio subito questa domanda ampliando il contesto: ho notato che GetOneObject usa sia
ObjectType che GetObjectGeometryFilter quindi ci sono piĆ¹ metodi che fanno le stesse cose

poi alla fine della spiegazione di PointAtStart e GetLength() riporta scritto queste referenze:

See Also

Reference

RhinoGet Class
Rhino.Input Namespace

quindi sembra dire che RhinoGet ĆØ una classe, anche GetOneObject ha come referenza RhinoGet Class

quindi se Rhino.Input ĆØ il namespace e RhinoGet ĆØ una sua classe sottostante
e come da esempio postato per richiamare il metodo GetOneObject( )
bisogna accedere prima sia al namespace che alla sua classe

mi confonde lā€™affermazione che le classi non vengono richiamate. . .

E lā€™overloading a cui avevi accennato prima a proposito dei costruttori.
Anche i metodi possono avere diversi overload.

Se vuoi dirlo in questo modo, OK.
Io dico che Rhino.Input.RhinoGet eā€™ semplicemente il nome completo della classe
e Rhino.Input.RhinoGet.GetOneObject eā€™ il nome completo del metodo (statico in questo caso).

Cosa intendi con ā€˜richiamateā€™ ?
Forse eā€™ qui che non ci capiamo ā€¦

EDIT:

Se intendi dire che in questo caso dobbiamo scrivere

import Rhino

Eā€™ vero.
Cosiā€™ facendo possiamo utilizzare tutto cioā€™ che eā€™ contenuto nel namespace Rhino.

detta in parole povere per le dimensioni della guida, lā€™associo ad un enorme deposito RhinoCommon API
dove ci sono i vari capannoni che sarebbero i ā€œnamespaceā€ ognuno con il proprio indirizzo/riferimento

poi import Rhino (la vedo come una chiave) in questo caso apriemo il capannone Rhino.Input
dentro il quale troviamo enormi container che sarebbero le classi quindi con RhinoGet accediamo
al rispettivo container, che a sua volta contiene vari scatoloni Metodi ProprietĆ  ecc che utilizziamo

eeee forse richiamare non ĆØ proprio il termine corretto, volevo intendere che per richiamare/utilizzare
il metodo GetOneObject bisogna passare prima per la sua classe di appartenenza cioĆØ RhinoGet


comunque in tutto questo volevo fare una prova che perĆ² non ci sono riuscito:

https://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_DocObjects_ObjectType.htm

https://developer.rhino3d.com/api/RhinoCommon/html/T_Rhino_Input_Custom_GeometryAttributeFilter.htm

gli oggetti elencati nei due link sono associati a dei valori numerici tipo: i Punti a 1 le Curve a 4 ecc
volevo che dopo aver selezionato un oggetto mi tornasse tale valore numerico. come si fa?

Bene.
Come dicevamo, ognuno ragiona a modo suo.
Lā€™importante eā€™ riuscire a utilizzare la libreria. :slight_smile:

Ho trovato questa proprietaā€™, partendo da un oggetto RhinoObject:

RhinoObject.ObjectType Property (rhino3d.com)

( Hehe ā€¦ ci vuole un poā€™ di esperienza con RhinoCommon ā€¦
Dopo un poā€™ impari dove cercare ā€¦ :smile: )

import Rhino

ok, obref = Rhino.Input.RhinoGet.GetOneObject( 
    'Curve ?', True, Rhino.DocObjects.ObjectType.AnyObject )
print obref.Curve().ObjectType

in veritĆ  Emilio cā€™ero arrivato anchā€™io ad usare questa proprietĆ , ma mi ritorna la scritta Curve
come output, come faccio a stampare il valore 4 ad esso associato?