RhinoScript 8. dil: Uživatelské funkce
Publikováno: 29.8.2005 | Autor: David Rutten | Rubrika: Rhinoceros | Komentáře: 1 - Doporučit

8.1 Procedury a funkce
Víteje vposlední kapitole této příručky. Probereme zde poslední záležitosti, které musíte znát, než budete schopni naprogramovat téměř cokoliv, co si přejete. Již víte, že se téměř všechny naše 'akce’ odehrávají v procedurách a funkcích. Také víte, že vbScript obsahuje množství předdefinovaných funkcí jako Sin()
, Cos()
, Left()
, UCase()
atd.
Nyní se dozvíte, jak vytvořit své vlastní funkce...
8.2.1 Jak funkce pracují
Funkce (nebo procedura) je kus kódu, který je vykonán z nějakého jiného místa. Funkcím můžete předat argumenty a funkce mohou provádět akce nebo vracet hodnoty nebo obojí. Do funkcí často vkládáme algoritmy. Algoritmy jsou řešitelé poblémů.
Často potřebujeme provést určité operace několikrát. Někdy je nejlepším řešením cyklus, ale jindy používáme ve funkcích algoritmy, abychom zachovali náš kód malý a čitelný.
Bez okolků si ukážeme si první funkci:
01 Function VypoctiProstredniBod(arrBod1, arrBod2)
02 Dim arrProstredniBod(2)
03 Dim i
04
05 For i = 0 To 2
06 arrProstredniBod(i) = (arrBod1(i)+arrBod2(i)) / 2
07 Next
08
09 VypoctiProstredniBod = arrProstredniBod
10 End Function
Tato konkrétní funkce je navržena pro nalezení bodu v polovině mezi dvěma zadanými body. V podstatě jsme použili téměř identický kód jako v dlouhém skriptu na konci minulého dílu. Procedury a funkce nikdy nejsou navzájem zahnízděny. Nelze je zahnízdit jako podmínky If..Then
nebo jako cykly. Vždy jsou ve skriptu řazeny sekvenčně za sebou.
Tato funkce má název VypoctiProstredniBod(
) a má dva argumenty (arrBod1 a arrBod2). Oba argumenty musí být numerická pole, každé se 3 prvky, jinak dojde ke zhroucení funkce (nepoužili jsme žádné odchytávání chyb). Funkce vrátí jedno numerické pole, také se 3 prvky. Pokud bychom chtěli zavolat tuto funkci zevnitř procedury Main()
, museli bychom přidat následující řádek kódu:
Dim arrProstredniBod
arrProstredniBod = VypoctiProstredniBod(arrPrvniBod, arrDruhyBod)
Proměnná před znaménkem = bude naplněna daty, vrácenými funkcí. V našem případě to bude numerické pole se 3 prvky.
Jak vidíte, není žádný rozdíl v použití nativních a uživatelských funkcí. Syntaxe pro obě je zcela identická.
Dalším zajímavým faktem je, že můžeme použít více než jeden argument. Zde používáme dva argumenty, ale tento počet není omezen. Mnoho nativních funkcí a metod Rhina také přijímá či dokonce vyžaduje více argumentů. Vjednom zpředchozích dílů jsme probrali funkci Left()
. Kdykoliv chcete použít tuto funkci, musíte zadat řetězec a hodnotu typu Long. Funkce vrátí řetězec, který je identický se zadaným, ale bude zkrácen na zadanou délku.
Daleko složitějším příkladem je metodaRhino.GetObjects()
. Tuto mehodu jsme již dříve použili, ale vždy s jedním argumentem. Pokud si tuto metodu vyhledáte v nápovědě RhinoScriptu, uvidíte následující řádek:
Rhino.GetObjects ([strMessage [, intType [, blnGroup [,
blnPreSelect [, blnSelect [, arrObjects ]]]]])
To je syntaxe této konkrétní metody. Jak vidíte, můžeme použít až 6 argumentů a žádný není povinný. Argumenty mezi závorkami [ ] jsou vždy volitelné.
strMessage
Zde vložíme text, který chceme zobrazit v příkazovém řádku.
intType
Zde definujeme, jaký druh objektu akceptujeme. Pouze křivky nebo jen body, nebo pouze spojené plochy a obyčejné plochy...
blnGroup
Zde definujeme, zda budou nebo nebudou vybrány skupiny, pokud bude vybrán jeden objekt z této skupiny.
blnPreselect
Zde definujeme, zda se budou brát do úvahy již vybrané objekty.
blnSelect
Zde definujeme, zda budou zvolené objekty vybrány.
arrObjects
A konečně můžeme specifikovat pole s identifikátory objektů, pokud chceme omezit výběr na určité objekty.
Pokud tedy chceme, aby uživatel vybral pouze křivky a mraky bodů, chceme akceptovat předem vybrané objekty a nechceme aby uživatel vybíral skupiny, obsahoval by náš skript následující řádek:
arrObj = Rhino.GetObjects("Pick curves", 4+2, vbFalse, vbTrue, vbFalse)
8.3 Další informace
Měli byste vědět pár důležitých věcí, které se týkají použití funkcí. Jejich chování bohužel není vždy logické. Až dosud jsme k předávání argumentů funkcím používali závorky:
arrObjekty = Rhino.GetObjects("Vyberte křivky")
Závorky jsou ale povoleny pouze tehdy, když funkce vrací hodnotu. Pokud zavoláme funkci aniž bychom zpětně obdrželi nějaká data, nemůžeme závorky použít:
Špatně! Rhino.AddPoint (arrSouradniceBodu)
Správně Rhino.AddPoint arrSouradniceBodu
Správně strPointID = Rhino.AddPoint(arrSouradniceBodu)
Když vytvoříme vlastní funkce (uživatelské funkce), nemůžeme přidávat volitelné argumenty. Pouze nativní funkce vbScriptu a metody Rhina mohou mít volitelné argumenty.
01 Sub Main()
02 Dim blnResult
03 blnResult = DisplayCopyRightMessage("Reinier a Carl", vbTrue)
04 End Sub
05
06 Funkce DisplayCopyrightMessage(strNazvy, blnPouzitPrikazovyRadek)
07 Dim strZprava
08
09 strZprava = "Tento skript napsala autorská práva vlastní " & _
10 strNazvy & "." & vbNewLine & _
11 "Smíte používat a upravovat tento kód " & _
12 "ale nesmíte odstranit copyright."
13
14 If blnPouzitPrikazovyRadek Then
15 Rhino.Print strZprava
16 Else
17 Rhino.MessageBox strZprava, 64, "info o copyrightu"
18 End If
19
20 DisplayCopyRightMessage = vbTrue
21 End Function
Funkci můžete ukončit kdykoliv pomocí příkazu Exit Function
. Všechny akce budou ukončeny a funkce vrátí řízení funkci nebo proceduře, která ji zavolala. Kdykoliv zastavíte funkci, ať už pomocí End Function
nebo Exit Function
, vrátí proměnnou, kterou jste přiřadili jejímu názvu. V předchozí funkci jsme přiřadili hodnotu funkci na řádku 21. Můžeme to bezpečně udělat, protože nikde není příkaz Exit Function
a proto budou vždy vykonány všechny řádky. Jakmile však začneme používat odchytávání chyb a příkazy Exit Function
, začne být nezbytné, abyste se ujistili, zda vaše funkce vždy vrátí proměnnou.
Jak si možná pamatujete, metody Rhina vždy vrací proměnnou vbNull, pokud se přihodí něco špatného. Abychom to implementovali do našich funkcí, provedeme následující:
1 Function FixStringLength(strZaklad, lngDelka)
2 FixStringLength = vbNull
3
4 If Not IsNumeric(lngDelka) Then Exit Function
5 If VarType(strZaklad) <> vbString Then Exit Function
6
7 lngDelka = Fix(lngDelka)
8 If lngDelka < 1 Then
9 FixStringLength = ""
10 Exit Function
11 End If
12
13 strZaklad = strZaklad & Space(lngDelka)
14 strZaklad = Left(strZaklad, lngDelka)
15
16 FixStringLength = strZaklad
17 End Function
Tato funkce má neprůstřelný systém odchytávání chyb. Jakmile funkce začne (řádek 2), okamžitě nastavíme proměnnou s názvem funkce na vbNull
. Nyní, pokud ukončíme funkci, bude vrácena hodnotavbNull
.
Všimněte si, že tato funkce neinicializuje žádné proměnné. Ale to nutně neznamená, že bychom je nepoužívali. Tato funkce má v podstatě 3 proměnné dokonce ještě před tím, než začne běžet. Název funkce (FixStringLength) je ždy automaticky proměnná, stejně jako její argumenty (strZaklad a lngDelka).
Nebudeme si už dělat analýzu řádek po řádku, protože to byste již měli být nyní schopni provést sami. Zmíním však všechny nové věci...
Řádek 4: IsNumeric()
určí, za proměnná může být Rhinem vyhodnocena jako číslo. Také řetězce, které obsahují pouze čísla, lze načíst jako čísla.
Řádek 7: Fix()
přemění jakékoliv číslo na celé číslo... a na nic se neptá.
Řádek 9: "" znamená prázdný řetězec.
Řádek 13: Space()
vytvoří řetězec se zadaným počtem mezer.
Tato funkce tedy převede každý řetězec na řetězec pevné délky. Můžete zadat délku pomocí hodnoty Double nebo Long. Double budou převedeny na celá čísla. Chybějící znaky (pokud je řetězec příliš krátký) budou zaplněny mezerami.
8.4 Čas cvičení
Nyní byste již měli být schopni sami některé skripty sami. Problém se skutečnou prací je ten, že je obvykle velice složitá. Proto jsem začlenil malé úkoly sjednoduchými problémy. Cílem každého úkolu je napsat funkci, která provede určitou akci nebo vypočítá určité řešení. Radím vám, abyste svůj postup konzultovali s touto příručkou, s nápovědou vbScriptu a s nápovědou RhinoScriptu.
Úkol 1: Práce s booleovskými proměnnými
Vytvořte funkci, která vypočítá většinu hlasů ve struktuře se 3
hlasy. Většina se skládá ze 2 nebo 3 identických booleovských hodnot.
Vstup: 3 booleovské proměnné
Výstup: 1 booleovská proměnná nebo vbNull nebo chyba
Pokuste se vejít do 30 řádků kódu.
Úkol 2: Práce s čísly
Vytvořte funkci, která zkontroluje, zda je numerická proměnná
součástí multiplikační tabulky jiné numerické proměnné.
Proměnná 1 musí tedy být celočíselným dělitelem proměnné 2.
Vstup: 2 numerické proměnné
Výstup: 1 booleovská proměnná nebo vbNull nebo chyba
Pokuste se vejít do 30 řádků kódu...
Úkol 3: Práce s řetězci
Vytvořte funkci, která odstraní každý druhý znak ze řetězce.
"aAbBcCdDeEfF" se tak stane "abcdef" a "0123456789" se stane"02468".
Vstup: 1 proměnná typu řetězec
Výstup: 1 proměnná typu řetězec nebo vbNull nebo chyba
Pokuste se vejít do 40 řádků kódu...
Úkol 4: Práce s Rhinem
Vytvořte skript, který umožní vstup nekonečného počtu bodů (vybraných myší
nebo již existujících bodů... volba je na vás) a který vypočítá průměrné souřadnice všech těchto bodů.
Pro „komplikované“ matematické záležitosti zkuste použít funkce. Také nezapomeňte přidat co nejvíce odchytávání chyb.
Než začnete kódovat, udělejte si plán (v češtině) a ujistěte se, zda tento plán funguje...
Úkol 1, možné řešení
01 Function Vetsina(blnHlas1, blnHlas2, blnHlas3)
02 Vetsina = vbNull 'Dáme funkci návratovou hodnotu
03 Dim blnMajorityResult 'Deklarujeme booleovskou proměnnou
04
05 If VarType(blnHlas1) <> vbBoolean Then Exit Function
06 If VarType(blnHlas2) <> vbBoolean Then Exit Function
07 If VarType(blnHlas3) <> vbBoolean Then Exit Function
08 'Zajistili jsme korektní vstup
09 blnMajorityResult = vbFalse
10 'Nastavili jsme výchozí výsledek na FALSE
11 If (blnHlas1 And blnHlas2) Or (blnHlas2 And blnHlas3) Or _
12 (blnHlas1 And blnHlas3) Then
13 'Určíme zda alespoň 2 ze 3 hodnot
14 'jsou TRUE. Pokud nebude se žádný ze členů
15 'vyhodnocen jako TRUE, bude kód uvnitř
16 'konstrukce If..Then přeskočen
17
18 blnMajorityResult = vbTrue
19 'Změna výsledku na TRUE
20 End If
21 End Function
Tato funkce má neprůstřelný systém odchytávání chyb. Prvně zajistíme, že procedura nebo funkce, která zavolala tuto funkci, dodala 3 booleovské hodnoty. Pokud se ukáže, že jedna ztěchto hodnot je něco jiného, ukončíme funkci a vrátíme hodnotu vbNull
.
Poté budeme předpokládat, že výsledek bude vbFalse
. Samozřejmě, pokud nejméně 2 ze 3 hodnot budou pravdivé, pak celá kosntrukce:
(blnHlas1 And blnHlas2) Or (blnHlas2 And blnHlas3) Or _
(blnHlas1 And blnHlas3)
bude vyhodnocena jako TRUE. Vtakovém případě bude vykonán blok kódu v příkazu If..Then
. Zde změníme výslednou hodnotu funkce na vbTrue
.
Také si všimněte, že jsem použil podtržítko pro prodloužení řádku kódu. Enter obvykle označuje konec řádku. Několik řádků však můžeme „sešít“ dohromady pomocí podtržítek. To je užitečné, když jsou řádky kódu širší než obrazovka.
Tato funkce je čitelná, ale také velice neefektivní. V podstatě, pokud rezignujeme na odchytávání chyb, můžeme ji napsat do jednoho řádku:
1 Function Vetsina(Hlas1, Hlas2, Hlas3)
2 Vetsina = (Hlas1 And Hlas2) Or (Hlas2 And Hlas3) Or (Hlas1 And Hlas3)
3 End Function
Úkol 2, možné řešení
1 Function JeDelitelne(numKontrola, numTabulka)
2 JeDelitelne = vbNull
3 'Dáme funkci návratovou hodnotu
4
5 If Not IsNumeric(numKontrola) Then Exit Function
6 If Not IsNumeric(numTabulka) Then Exit Function
7 If numTabulka = 0 Then Exit Function
8 'Zajistili jsme korektní vstup.
9 If (numKontrola / numTabulka) = CLng(numKontrola / numTabulka) Then
10 JeDelitelne = vbTrue
11 Else
12 JeDelitelne = vbFalse
13 End If
14 End Function
Tento příklad není úplně neprůstřelný. Nejprve by měl akceptovat všechny typy numerických proměnných. Mezi ně patří Long a Double, ale také jiné typy numerických proměnných, o kterých jsme se nebavili, jako je Byte, Integer, Single a Currency. Vlastně by měl pracovat i s numerickými řetězci, jako "3.256" nebo "-9805".
Kontrola, zda patří vstupní hodnoty k *jakémukoliv* z těchto typů by zabrala mnoho řádků. Místo toho je snadnější použít funkci IsNumeric()
.
Dále nemá smysl dávat hodnotu 0 (nula) jako hodnotu numTabulka
. Také musíme pro tento případ přidat odchytávání chyb.
Abychom zkontolovali, zda je číslo částí multiplikačních tabulek jiných čísel, podíváme se, zda je výsledkem dělení celé číslo. Provedeme to nejsnadněji tak, že porovnáme toto dělení s Long verzí sebe sama. Měli bychom přelstít strukturu If..Then
použitím funkceCBool()
:
JeDelitelne = CBool((numKontrola / numTabulka) = CLng(numKontrola / numTabulka))
Opět, pokud bychom si mohli dovolit ignorovat odchytávání chyb, tato funkce by se vešla do jediného řádku...
Úkol 3, možné řešení
01 Function SliceString(strVstup)
02 SliceString = vbNull
03 If VarType(strVstup) <> vbString Then Exit Function
04 'Zkontrolujeme platný vstup
05 SliceString = strVstup
06 If Len(strVstup) <= 1 Then Exit Function
07 'Kontrola, zda je řetězec dost dlouhý
08 Dim strOutput
09 Dim i
10 strOutput = ""
11 'Inicializace proměnných
12 For i = 1 To Len(strVstup) Step 2
13 strOutput = strOutput & Mid(strVstup, i, 1)
14 Next
15
16 SliceString = strOutput
17 End Function
To je celkem jasné. Pro vykonání této úlohy potřebujeme cyklus, protože zadaný řetězec může mít jakoukoliv délku. Dále také potřebujeme funkci, která dokáže vyjmout zřetězce jeden znak. Udělá to funkce Mid()
.
Nad rámec Mid()
potřebujeme také funkciLen()
, která vrací délku řetězce. Potřebujeme vědět, kolikrát máme cyklus vykonat.
Možná jste si všimnuli, že před příkazy pro deklaraci proměnných je v této funkci hodně kódu. Myšlenka toho je následující: pokud ukončíme funkci kvůli chybnému vstupu, nebudeme potřebovat deklarovat proměnné. Z důvodu optimalizace kódu je vždy nejlepší předejít věcem, které nejsou nezbytné.
Úkol 4, možné řešení
Plán v krocích
A Vyzveme uživatele kzadání bodů.
B Ujistíme se, zda uživatel provedl, oč byl žádán.
C Zahájíme cyklus pro každý bod
D Získáme souřadnice (x,y,z) každého bodu
E Přidáme každou souřadnici khodnotě sumy
F Vrátíme se na začátek cyklu
G Podělíme všechny sumy počtem bodů
H Vytiskneme průměrnou souřadnici do příkazového řádku
I Do modelu přidáme textové kolečko
Celý skript
01 Option Explicit
02 'Script napsal Gelfling '04 07-07-2004
03 Sub Main()
04 Dim arrObjekty, arrSouradnice
05 Dim arrPrumer(2)
06 Dim i, sumaX, sumaY, sumaZ
07 arrObjekty = Rhino.GetObjects("Vyberte body",1,,vbTrue)
08 If IsNull(arrObjekty) Then Exit Sub
09 sumaX = 0
10 sumaY = 0
11 sumaZ = 0
12
13 For i = 0 To Ubound(arrObjekty)
14 arrSouradnice = Rhino.PointCoordinates(arrObjekty(i))
15 sumaX = sumaX + arrSouradnice(0)
16 sumaY = sumaY + arrSouradnice(1)
17 sumaZ = sumaZ + arrSouradnice(2)
18 Next
19
20 arrPrumer(0) = sumaX / (UBound(arrObjekty)+1)
21 arrPrumer(1) = sumaY / (UBound(arrObjekty)+1)
22 arrPrumer(2) = sumaZ / (UBound(arrObjekty)+1)
23
24 Rhino.Print "Průměr: " & Rhino.Pt2Str(arrPrumer, 5)
25 Rhino.AddTextDot "Těžiště", arrPrumer
26 End Sub
27
28 Main
Krátké, efektivní, čisté, čitelné. Použili jsme více proměnných než je nutné, více řádků než je nutné, ale jedinou chybou v tomto skriptu je, že postrádá komentáře.
Také by bylo lepší vložit sekci s cyklem do samostatné, uživatelské funkce místo toho, abychom ji vkádali do procedury Main()
.
Související články
- RhinoScript 1. díl: Makra a posloupnosti příkazů - 10.06.2005
- RhinoScript 2. díl: Skripty - 22.06.2005
- RhinoScript 3. díl: Rozvržení skriptu - 29.06.2005
- RhinoScript 4. díl: Operátory a funkce - 06.07.2005
- RhinoScript 5. díl: Pokročilé proměnné - 13.07.2005
- RhinoScript 6. díl: Řízení toku - 20.07.2005
- RhinoScript 7. díl: Pole - 28.07.2005
- RhinoScript příloha A: Pokročilý podmíněný tok - 22.07.2005
- RhinoScript 8. dil: Uživatelské funkce - 29.08.2005
Diskuse k článku
[1] JJJ – 15. 09. 2007, 11:49
reagovat
Na tento dil o Rhino scriptu chybi odkazy v ostatnich clancich