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

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:

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?