Rhino8 adattare codice C#

Mah … a me sembra piu’ una tendenza a voler modificare le cose senza preoccuparsi prima di capire come funzionano.
Ma ognuno ha i suoi modi di sperimentare …

Se il problema e’ usare una variabile globale anziche’ una locale, si risolve in fretta.
Ma non facendo come nel tuo esempio, perche’ …

… qui dice:
continue to use the same doc after the first call to ActiveDoc.
Cioe’ dice di richiamare una sola volta la proprieta’ AtciveDoc e in seguito usare il valore ottenuto da quell’unica chiamata.
(Almeno e’ quello che capisco, perche’ non mi sembra chiarissimo, probabilmente non capisco bene la frase in inglese)
In pratica dice: chiama ActiveDoc all’inizio dello script, salva il valore ottenuto in una variable e in seguito usa quella variabile.

Che poi e’ esattamente quello che si vede nell’esempio che avevi postato.

Io copierei quello che fa l’esempio di McNeel.

… Se per te i parametri delle funzioni sono intrecci … OK.
:confused: :wink: :smile:

EDIT:

Se guardi dentro scriptcontext, c’e’ questo:


'''The Active Rhino document (Rhino.RhinoDoc in RhinoCommon) while a script
is executing. This variable is set by Rhino before the exection of every script.
'''
doc = None

Dove dice che Rhino inizializza doc prima di eseguire lo script.

In pratica fa quello che fa l’esempio C# che abbiamo visto sopra. :slight_smile:

1 Mi Piace

ok grazie mille Emilio, quindi la mia ipotesi che si trattava di parte di un codice preso da altro era errata.

infatti ho perso molto tempo provando a richiamare using Rhino.RhinoDoc e ActiveDoc dove serviva

senza riuscirci, ma forse con le poprietà questo non’è possibile. . .

vabbè intreccio non era riferito al parametro in se per se, ma nel senso, perché richiamarlo dal metodo. . .

non per discolparmi:

avevo semplificato la situazione, ma se non si può fare, seguo le regole che meglio come mi hai cosigliato
(ma preferisco come nella foto che hai rigirato :+1:)

(giusto per domistrare che i tuoi consigli non vengono persi)
mentre prima ti rispondevo, pensavo a come modificare il codice con le nuove info a disposizione:

using System;
using Rhino;

var main = new Program();
main.DivideCurveBySegments();

class Program
{
    public RhinoDoc doc = RhinoDoc.ActiveDoc;

    public Rhino.Commands.Result DivideCurveBySegments()
    {
        const Rhino.DocObjects.ObjectType filter = Rhino.DocObjects.ObjectType.Curve;
        Rhino.DocObjects.ObjRef objref;
        var rc = Rhino.Input.RhinoGet.GetOneObject("Select curve to divide", false, filter, out objref);
        if (rc != Rhino.Commands.Result.Success || objref == null)
        return rc;

        var curve = objref.Curve();
        if (curve == null || curve.IsShort(RhinoMath.ZeroTolerance))
        return Rhino.Commands.Result.Failure;

        var segment_count = 2;
        rc = Rhino.Input.RhinoGet.GetInteger("Divide curve into how many segments?", false, ref segment_count);
        if (rc != Rhino.Commands.Result.Success)
        return rc;
        
        Rhino.Geometry.Point3d[] points;
        curve.DivideByCount(segment_count, true, out points);
        if (points == null)
        return Rhino.Commands.Result.Failure;

        foreach (var point in points)
        doc.Objects.AddPoint(point);

        doc.Views.Redraw();
        Console.WriteLine(doc);
        return Rhino.Commands.Result.Success;
    }
}

alla fine però ho dovuto ri-mettere la classe :blush:

:pray: :pray:

Credo sia semplicemente una routine generica, che va bene sia per i plug-in, sia per GH, sia per gli script.
In alcuni di questi casi, se non erro, il valore RhinoDoc e’ predifinito da Rhino, quindi e’ comodo poterlo usare come parametro per la routine principale dello script in quell’esempio.

Andando a naso (ma posso sbagliare) …
Credo che con using si possano importare solo i namespace, non le classi.
In questo caso Rhino e’ un namespace, ma RhinoDoc e’ una classe.

Dai, era una battuta … ma intendevo consigliare di abituarsi a usare i parametri delle funzioni.
In uno script breve non cambia niente, ma scrivendo cose piu’ lunghe solitamente (e personalmente concordo) e’ considerato un buon sistema per evitare possibili confusioni.

:+1:

Scusa, perche’ ? :slight_smile:

per usarla in questo modo:

invece di optare per la soluzione indicata inizialmente, utilizzando RhinoDoc.ActiveDoc come parametro

using System;
using rh = Rhino;

DivideCurveBySegments(rh.RhinoDoc.ActiveDoc);
static rh.Commands.Result DivideCurveBySegments(rh.RhinoDoc doc)

essendo che, ho il dubbio nel chiamare DivideCurveBySegments(rh.RhinoDoc.ActiveDoc);
in questo modo non sia la stessa cosa dell’esempio nella foto appena postata con la classe.

probabilmente mi sbaglio ma:

public RhinoDoc doc = RhinoDoc.ActiveDoc;

in questo modo associo a doc il RhinoDoc.ActiveDoc e poi il doc viene richiamato di volta in volta.

mentre il questo modo:

DivideCurveBySegments(rh.RhinoDoc.ActiveDoc);

chiamo direttamente all’inizio il RhinoDoc.ActiveDoc

static rh.Commands.Result DivideCurveBySegments(rh.RhinoDoc doc)

che poi viene associato al doc all’interno del metodo. (oppure è un ragionamento errato?)

Diciamo che usare una variabile (o un campo, essendo dentro una classe) va bene in tutti i casi, anche se dovessi richiamare la routine principale piu’ volte.
Nel caso specifico, visto che DivideCurveBySegments viene richiamata una volta sola, mi sembra che il funzionamento sia analogo.

In ogni caso usare una variabile apposita male non fa e la puoi prendere come abitudine per tutti gli script C#.
Si’, mi sembra la soluzione migliore .:slight_smile:

Quindi la classe ti serve per poter scrivere la funzione DivideCurveBySegments ?
Suppongo di si’ …

Non so come funzioni l’ambiente per gli script C# di Rhino.
Se provi a scrivere la funzione senza racchiuderla in una classe ti da’ errore ?

Se e’ cosi’, si’, bisogna usare una classe …

using System;
using rh = Rhino;

DivideCurveBySegments(rh.RhinoDoc.ActiveDoc);
static rh.Commands.Result DivideCurveBySegments(rh.RhinoDoc doc)
{
    const rh.DocObjects.ObjectType filter = rh.DocObjects.ObjectType.Curve;
    rh.DocObjects.ObjRef objref;
    var rc = rh.Input.RhinoGet.GetOneObject("Select curve to divide", false, filter, out objref);
    if (rc != rh.Commands.Result.Success || objref == null)
    return rc;

    var curve = objref.Curve();
    if (curve == null || curve.IsShort(rh.RhinoMath.ZeroTolerance))
    return rh.Commands.Result.Failure;

    var segment_count = 2;
    rc = rh.Input.RhinoGet.GetInteger("Divide curve into how many segments?", false, ref segment_count);
    if (rc != rh.Commands.Result.Success)
    return rc;
    
    rh.Geometry.Point3d[] points;
    curve.DivideByCount(segment_count, true, out points);
    if (points == null)
    return rh.Commands.Result.Failure;

    foreach (var point in points)
    doc.Objects.AddPoint(point);

    doc.Views.Redraw();
    Console.WriteLine(doc);
    return rh.Commands.Result.Success;
}

come anche esempio fatto inizialmente con la tua soluzione funziona:

DivideCurveBySegments(rh.RhinoDoc.ActiveDoc);

(ovviamente in Rhino8 dico)

:+1:

OK, la funzione si puo’ scrivere.

Resta solo da vedere se la funzione ‘vede’ le variabili definite fuori, cosi’ puoi utilizzare la tua bella variabile doc senza dover usare classi ( … se funziona )
Poi se vuoi usare una classe, niente di male, usala pure … :smile:
E’ solo curiosita’ … :blush:

Una cosa cosi’ che fa ? :wink:

using System;
using rh = Rhino;

RhinoDoc doc = RhinoDoc.ActiveDoc;

DivideCurveBySegments();
static rh.Commands.Result DivideCurveBySegments()
{
  // ...
  foreach (var point in points)
  doc.Objects.AddPoint(point);

  doc.Views.Redraw();
  Console.WriteLine(doc);
  // ...
}

La funzione DivideCurveBySegments non cambia, perde solo il parametro.

Lo hai aggiunto tu il WriteLine ?
Cosa stampa ?
… qualcosa come … “oggetto Rhino.RhinoDoc” ? :slight_smile:

EDIT

forse e’ meglio

using Rhino;

… non so …

si, l’avrò aggiunto per vedere di cosa si trattava, ma poi mi sono dimenticato di toglierlo dal post 34 :grin:

tipo la sintassi che hai postato, anch’io ci avevo provato. ho ri-provato con la tua ma correggendola:

immagine

A static local function cannot contain a reference to ‘doc’.

ps era un test?

:sweat_smile: :sweat_smile:

1 Mi Piace

Grazie.

Accc ! :confused:

E’ un test per provare a non usare classi … una cosa stupida se vuoi … :blush: :smile:

Giusto, la funzione e’ dichiarata statica …

Se dichiariamo statica anche la variabile ?

static RhinoDoc doc = rh.RhinoDoc.ActiveDoc;

Oppure togliere lo static dalla funzione

using System;
using Rhino;

RhinoDoc doc = RhinoDoc.ActiveDoc;

DivideCurveBySegments();
Commands.Result DivideCurveBySegments()
{
  // ...
  foreach (var point in points)
  doc.Objects.AddPoint(point);

  doc.Views.Redraw();
  Console.WriteLine(doc);
  // ...
}

Scusa eh, non voglio farti perder tempo.
Se vuoi, prova poi con calma, se no fa lo stesso.
E’ solo curiosita’ per capire se c’e’ modo di fare gli script senza classi.
Che poi con o senza non cambia niente …

ok, per un attimo credevo che fosse un test per vedere se ero attento ihihihih

immagine

essendo che senza mettere prima rh compaiono molte parti evidenziate. . .

mi inviti a nozze :laughing: :laughing:

ok faccio varie prove e ti aggiorno :+1:

eeee grande Emilio ci sono belle novità, il codice seguente togliendo lo static al metodo funziona:

using System;
using rh = Rhino;

rh.RhinoDoc doc = rh.RhinoDoc.ActiveDoc;
DivideCurveBySegments();

rh.Commands.Result DivideCurveBySegments()
{
    const rh.DocObjects.ObjectType filter = rh.DocObjects.ObjectType.Curve;
    rh.DocObjects.ObjRef objref;
    var rc = rh.Input.RhinoGet.GetOneObject("Select curve to divide", false, filter, out objref);
    if (rc != rh.Commands.Result.Success || objref == null)
    return rc;

    var curve = objref.Curve();
    if (curve == null || curve.IsShort(rh.RhinoMath.ZeroTolerance))
    return rh.Commands.Result.Failure;

    var segment_count = 2;
    rc = rh.Input.RhinoGet.GetInteger("Divide curve into how many segments?", false, ref segment_count);
    if (rc != rh.Commands.Result.Success)
    return rc;
    
    rh.Geometry.Point3d[] points;
    curve.DivideByCount(segment_count, true, out points);
    if (points == null)
    return rh.Commands.Result.Failure;

    foreach (var point in points)
    doc.Objects.AddPoint(point);

    doc.Views.Redraw();
    return rh.Commands.Result.Success;
}

mentre aggiungedo lo static alla variabile non l’accetta e mi evidenzia l’errore.

ottima intuizione quella di togliere lo static al metodo :clap:

1 Mi Piace

Bene.
Grazie per il test ! :slight_smile:

L’errore era stato mio, dovevo toglierlo subito lo static.
Fuori da una classe non ha senso.

Poi probabilmente Rhino incapsula tutto lo script in una classe nascosta, ma noi non la vediamo e non dobbiamo preoccuparcene.

OK, da tutto cio’ sappiamo che:

Puoi fare come ti pare con gli script.
O usare una classe o non usarla.
Poi per script complessi potrebbe essere comodo usare anche piu’ di una classe.
Ma per quelli semplici possiamo anche decidere di non usarne.
:grinning:

“Usarne” nel senso di scrivere nuove classi.
Le classi .NET e RhinoCommon le useremo regolarmente.

1 Mi Piace

:+1:

anch’io avevo pensato a questo che hai detto. . .
non so se ricordi, un po di tempo fa, parlammo di una cosa simile, ma inerente a Py sempre di Rhino,
dove io feci alcune domande sul funzionamento di questa stringa di codice if __name__ == "__main__":
ipotizzando che main, potrebbe essere il nome del foglio bianco di un livello superiore di Py in Rh
in pratica, il foglio bianco di Py in Rhino (che non vediamo) avrebbe di default il nome main
la stessa cosa con C#, e se analizziamo la regola in VS dove per avviare un codice si è obbligati a creare in una classe, un metodo di nome Main statica, e questo metodo viene avviato per eseguire il tutto.

Questo indica se lo script e’ stato lanciato direttamente (ad esempio da EditPythonScript o da un pulsante)
o se invece e’ un modulo caricato da uno script diverso.
Credo serva per poter testare facilmente un modulo senza interferire col suo uso da modulo esterno.

1 Mi Piace