Úvod

Toto cvičení má sloužit k demonstrování některých výkonných schopností programovacího prostředí AutoLISP® pro AutoCAD® a uvést některé nové funkce jazyka AutoLISP.

Cílem cvičení je nakreslit pomocí automatizovaného kreslicího nástroje zahradu a tím minimalizovat dobu potřebnou ke kreslení a zároveň ukázat výhody parametrického programování. Naučíte se vytvořit kreslicí proceduru, která automatizuje tvorbu složitého tvaru — jedná se tedy přesně o tu činnost, kterou byste jistě neradi prováděli znovu a znovu od začátku.

Témata v této části:

  • Práce ve Visual LISPu
  • Přehled cvičení
Připomínky?


Práce ve Visual LISPu

Úvod
Úvod
Práce ve Visual LISPu

Toto cvičení je určeno zkušeným uživatelům programu AutoCADa předpokládá, že již do určité míry znáte buď LISP, nebo AutoLISP. Dále se předpokládá, že rozumíte základním operacím správy souborů ve Windows®, například vytváření adresářů, kopírování souborů a orientace v rámci pevného disku nebo sítě.

V tomto cvičení

  • Představeno je prostředí Visual LISP® (VLISP). Toto prostředí nabízí nástroje pro editaci, odstraňování chyb a další operace specifické pro tvorbu aplikací AutoLISPu.
  • Budou demonstrovány funkce ActiveX® a Reactor, jakožto i několik dalších nástaveb jazyka AutoLISP poskytovaných jazykem VLISP.

Pro toto cvičení existují následující dvě metody spouštění:

  • Aplikace může běžet jako interpretovaný LISP v rozkouskovaných souborech nebo funkcích, které jsou načteny do jednoho dokumentu, nebo
  • Programový kód může být zkompilován do aplikace VLX se spustitelným souborem *.vlx. Aplikace VLX běží z vlastního prostoru názvů, který může spolupracovat s dokumentem načítání aplikace.


Přehled cvičení

Úvod
Úvod
Přehled cvičení

Vaším cílem v tomto cvičení je vytvořit nový příkaz pro AutoCAD, který nakreslí zahradu a vyplní ji kruhovými dlaždicemi. Cvičení je rozděleno do sedmi částí. Při postupu z jednotlivých dílčích cvičení budete mít k dispozici stále méně a méně podrobné instrukce. Nápověda je dostupná v dokumentaci k VLISPu.

Cvičení 4 a 5 jsou středně obtížná a vyžadují více než jen základní znalosti o AutoLISPu. Cvičení 6 a 7 obsahují pokročilé programovací úlohy a jsou určena velmi zkušeným vývojářům AutoLISPu.

Pokud zvolíte možnost plné instalace při instalaci programu AutoCAD, jsou soubory zdrojového kódu umístěny v následující složce:

<adresář programu AutoCAD>\Tutorial\VisualLISP\

Pokud již máte AutoCAD instalován a neinstalovali jste příklady, můžete instalaci znovu spustit, vybrat volbu Uživatelská a vybrat pouze položky Cvičení.

Doporučuje se neupravovat zdrojové soubory dodávané s programem AutoCAD. Pokud v programu něco nebude fungovat, budete moci zkopírovat tyto zdrojové soubory do pracovního adresáře. V rámci tohoto cvičení je pracovní adresář následující:

<adresář programu AutoCAD>\Tutorial\VisualLISP\MyPath

Pokud pro pracovní adresář vyberete jinou cestu, nahraďte příslušné názvy adresářů jinými podle potřeby.


Návrh a začátek tvorby programu

V tomto cvičení začnete tím, že definujete, co bude aplikace dělat. Pomocí vývojového prostředí Visual LISP® (VLISP) vytvoříte soubor LISP a začnete psát kód AutoLISPu® pro podporu vaší aplikace. V průběhu procesu začnete zjišťovat, jak VLISP usnadňuje vývoj aplikace.

Témata v této části:

  • Definování hlavních úkolů programu
  • Začínáme s Visual LISPem
  • Formátování kódu Visual LISPu
  • Analýza kódu
  • Vyplnění mezer v programu
  • Visual LISP zkontroluje váš kód
  • Spuštění programu s Visual LISPem
  • Shrnutí cvičení 1


Definování hlavních úkolů programu

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Definování hlavních úkolů programu

Vývoj programu AutoLISP začíná myšlenkou automatizace nějaké funkce programu AutoCAD®. Může se jednat o zrychlení opakované kreslicí funkce či zjednodušení složitých sérií operací. V tomto cvičení chcete pomocí vytvořeného programu nakreslit zahradní cestu tvořenou složitým tvarem s proměnným počtem součástí podle údajů zadaných na začátku uživatelem. Výsledek bude vypadat takto:

Váš program musí při kreslení zahradní cesty provést následující:

  • Nakreslit přímkovou hranici na základě zadaného počátečního bodu, koncového bodu a šířky. Tato hranice může mít libovolnou 2D orientaci. Velikost by měla být bez omezení.
  • Požádat uživatele o zadání velikosti dlaždic a vzdálenosti mezi nimi. Dlaždicemi jsou kružnice, které hranice vyplní, ale nepřesáhnou ani nepřekříží.
  • Umístit dlaždice do alternativních řad.

Chcete-li se podívat, jak bude celý proces vypadat, můžete si spustit hotovou verzi aplikace dodávanou s programem AutoCAD.

Jak provést spuštění hotové aplikace
  1. Z nabídky programu AutoCAD Nástroje vyberte položku Načíst aplikaci.
  2. Vyberte soubor gardenpath.vlx z adresáře Tutorial\VisualLISP a stiskněte tlačítko Načíst.
  3. Stiskněte tlačítko Uzavřít.
  4. Na výzvu Příkaz zadejte gpath.
  5. Zodpovězte první dvě výzvy zadáním počátečního a koncového bodu ve výkresovém okně programu AutoCAD.
  6. Na výzvu Half Width of Path zadejte 2.
  7. Při zobrazení dialogu Garden Path Tile Specifications stiskněte tlačítko OK.


Začínáme s Visual LISPem

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Začínáme s Visual LISPem

Nyní, když jste viděli, jak by měla aplikace pracovat, můžete ji začít vyvíjet ve VLISPu. Nejdříve však bude lepší demonstrovat, co se stane, když VLISP čeká na řízení návratu z programu AutoCAD. Možná jste se s tím již setkali.

Jak určit čekání Visual LISPu na předání řízení od programu AutoCAD
  1. Z nabídky programu AutoCAD Nástroje vyberte položku Načíst aplikaci.
  2. Vyberte soubor gardenpath.vlx z adresáře Tutorial\VisualLISP a stiskněte tlačítko Načíst.
  3. Stiskněte tlačítko Uzavřít.
  4. Na výzvu programu AutoCAD Příkaz zadejte vlisp pro spuštění Visual LISPu.
  5. Přepněte se zpět do okna programu AutoCAD (buď aktivujte AutoCAD pomocí hlavního panelu, nebo stiskněte kombinaci kláves ALT + TAB a vyberte AutoCAD) a zadejte gpath na výzvu programu AutoCAD Příkaz.
  6. Před zodpovězením výzev spojených s gpath se přepněte zpět do okna VLISPu.

    7. V okně VLISPu se ukazatel myši zobrazí jako symbol VLISPu, přičemž nikde v okně VLISPu nelze zadat žádný příkaz ani zadat text. Symbol ukazatele myši připomíná, že před pokračováním práce ve VLISPu je nutné dokončit nějakou činnost v programu AutoCAD. Kdykoliv uvidíte tento ukazatel myši, uvědomte si tuto situaci.

  7. Vraťte se do okna programu AutoCAD a zodpovězte všechny výzvy spojené s gpath.

Nyní jste připraveni zahájit vývoj aplikace pro tvorbu zahradní cesty.

Jak zahájit vývoj aplikace pomocí Visual LISPu
  1. Z nabídky VLISPu Soubor vyberte položku Nový soubor.
  2. Zadejte v textovém editoru následující kód (jedná se o okno nazvané “<Untitled-0>”); chcete-li, můžete komentáře vynechat:
    3. ;;; Funkce C:GPath je hlavní funkcí programu a definuje
    ;;; AutoCAD příkaz GPATH.
    (defun C:GPath ()
      Požádejte uživatele o vstup: nejdříve o umístění cesty a
      ;; směr, potom parametry cesty. Pokračuje pouze pokud máte platné
      ;; platný vstup.
      (if (gp:getPointInput) ;
        (if (gp:getDialogInput)
          (progn
            ;; V tomto bodě máte platné zadání od uživatele.
            ;; Nakreslete obrys a uložte výslednou křivku
            ;; "ukazatel" do proměnné PolylineName.
            (setq PolylineName (gp:drawOutline))
            (princ "\nFunkce gp:drawOutline vrátila <")
            (princ PolylineName)
            (princ ">")
            (Alert "Gratulujeme - váš program je hotov!")
          )
        (princ "\nFunkce byla zrušena.")
       )
       (princ "\nNedostatečné informace pro nakreslení hranice.")
      )
      (princ) ; tiše skončit
    )
    ;;; Zobrazí hlášení sdělující uživateli název příkazu.
    (princ "\nZahradní cestu nakreslíte zadáním příkazu gpath.")
    (princ)
  3. Vyberte položky Soubor [image] Uložit jako z nabídky a uložte tento kód do nového souboru jako <adresář programu AutoCAD>\Tutorial\VisualLISP\MyPath\gpmain.lsp.
  4. Projděte si svou práci.


Formátování kódu Visual LISPu

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Formátování kódu Visual LISPu

VLISP rozpoznává různé typy znaků a slov tvořící soubor programu AutoLISPu a zvýrazňuje znaky pomocí odlišných barev. Tím vám usnadňuje rychlé nalezení nesprávné položky v kódu. Pokud například zapomenete uvést za řetězcem znak uvozovek, bude se veškerý další kód psát fialovou barvou, která je vyhrazena pro řetězce. Jakmile chybějící uvozovky dopíšete na jejich místo, VLISP správně vybarví text následující za řetězcem podle daného jazykového prvku.

Při zadávání textu jej VLISP formátuje také přidáváním mezer a odsazení. Pokud budete chtít, aby VLISP zformátoval text, který zkopírujete do jeho textového editoru z jiného souboru, vyberte z nabídky VLISPu položky Nástroje [image] Zformátovat kód.


Analýza kódu

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Analýza kódu

V novém souboru zadejte následující příkaz: Všimněte si, že hlavní funkce se jmenuje C:GPath. Předpona C: udává, že tuto funkci lze vyvolat z příkazového řádku programu AutoCAD. GPath je název, který uživatel zadá při spuštění aplikace na výzvu programu AutoCAD Příkaz. Funkce, které vyžadují zadání od uživatele se nazývají gp:getPointInput a gp:getDialogInput. Funkce, která kreslí obrys zahradní cesty, je gp:drawOutline. Tyto názvy jsou uvedeny písmeny gp:, které označují, že jsou specifické pro aplikaci zahradní cesty. Toto označení není povinné, ale je dobrým zvykem odlišovat specifické funkce aplikací od obecných funkcí, které často používáte.

V hlavní funkci zobrazují výrazy princ výsledky programu, pokud běží správně, nebo varovné hlášení, pokud program narazí na neočekávanou událost. Jestliže například (jak uvidíte ve cvičení 2) uživatel stiskne klávesu ENTER místo vybrání bodu na obrazovce, volání funkce gp:getPointInput končí předčasně a vrací hlavní funkci hodnotu nil. To způsobí, že program zobrazí zprávu princ ve tvaru "Nedostatečné údaje pro nakreslení hranic".

Volání princ u konce programu slouží jako výzva. Při načtení aplikace informuje uživatele o tom, co musí zadat pro spuštění kreslení zahradní cesty. Na konci princ bez řetězcového argumentu donutí program tiše ukončit svou činnost, což znamená, že hodnota posledního výrazu hlavní funkce není vrácena. Pokud by koncové princ byly vypuštěny, výzva by se zobrazila dvakrát.


Vyplnění mezer v programu

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Vyplnění mezer v programu

Pokud má kód v tomto novém souboru pracovat správně, musíte použít ještě tři definice funkcí. Kód hlavní zahradní cesty obsahuje volání tří uživatelských funkcí:

  • gp:getPointInput
  • gp:getUserInput
  • gp:drawOutline

Nyní postačí, když zapíšete zástupné definice těchto funkcí. Zástupné definice funkce slouží jako výplňová funkce pro celou definici, která má následovat. Umožňuje vyzkoušet části kódu ještě před tím, než do něj vložíte všechny detaily nutné k dokončení aplikace.

Jak definovat zástupné funkce
  1. Umístěte kurzor do horní části kódu programu v okně textového editoru a stiskněte několikrát klávesu ENTER, čímž do kódu vložíte volné řádky.
  2. Zadejte následující kód začínající tam, kam jste vložili volné řádky:
    3. ;;; Funkce gp:getPointInput získá umístění a velikost cesty
    (defun gp:drawOutline ()
      (alert
        "Funkce gp:getPointInput získá zadání od uživatele"
      )
      ;;Nyní vrátíte T, jakoby funkce pracovala správně.
      T
    )
    ;;; Funkce gp:getDialogInput získá parametry cesty
    (defun gp:getDialogInput ()
      (alert
        "Funkce gp:getDialogInput nechá uživateli zadat data pomocí dialogu"
      )
      ;;Nyní vrátíte T, jakoby funkce pracovala správně.
      T
    )
    ;;; Funkce gp:drawOutline nakreslí hranici cesty
    (defun gp:drawOutline ()
      (alert
        (strcat "Tato funkce nakreslí obrys křivky "
         "\na vrátí název/ukazatel na entitu křivky."
        )
      )
      ;; Nyní vrátíte apostrofový symbol. Tato funkce případně
      vrátí název entity nebo ukazatel.
      'SomeEname
    )

Těsně před koncem každé vstupní funkce je řádek kódu obsahující pouze písmeno T. Ten slouží jako návratová hodnota volání funkce. Všechny funkce AutoLISPu vrací hodnotu funkci, která je volala. Písmeno T je v AutoLISPu symbol pro „true“ a pokud jej použijete, vrátí funkce hodnotu „true“. Soubor gpmain.lsp je strukturován tak, že každá vstupní funkce, kterou volá, musí vracet hodnotu různou od nil (což znamená „žádná hodnota“), aby program pokračoval dalším krokem.

Funkce AutoLISPu bude implicitně vracet hodnotu posledního výrazu v ní vyhodnoceného. V zástupných funkcích je jediným výrazem zavolání funkce alert. návratové hodnoty nil a Pokud je ponechána jako poslední výraz ve gp:getPointInput, bude vždy vracet hodnotu nil a program se nedostane přes if k funkci gp:getDialogInput.

Z podobného důvodu vrací konec funkce gp:DrawOutline apostrofový symbol ('SomeEname) jako výplňovou funkci. Apostrofový symbol je prvek LISPu, který není vyhodnocován. (Pokud vás zajímá, jak funguje jazyk LISP, máte k dispozici množství dobrých materiálů, z nichž některé jsou uvedeny i na konci tohoto cvičení.)


Visual LISP zkontroluje váš kód

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Visual LISP zkontroluje váš kód

VLISP má výkonnou funkci pro kontrolu vašeho kódu a vyhledání syntaktických chyb. Tento nástroj použijte před pokusy o spuštění programu. Můžete tak objevit běžné chyby vzniklé při psaní, jako jsou chybějící závorky či uvozovky, a další syntaktické chyby.

Jak provést kontrolu syntaxe kódu
  1. Ujistěte se, že aktivním oknem je okno textového editoru obsahující soubor gpmain.lsp. (Klepněte jednoduše na záhlaví okna.)
  2. Z nabídky VLISPu vyberte položky Nástroje [image] Zkontrolovat text v editoru.

    3. Zobrazí se dialog Výstup sestavení s výsledky kontroly syntaxe. Pokud VLISP nenašel žádné chyby, obsahuje dialog text podobný následujícímu:

    [KONTROLA TEXTU GPMAIN.LSP načítání...]
    ......
    ; Kontrola dokončena.

Pokud máte potíže a potřebujete pomoc, nahlédněte do tématu “Developing Programs with Visual LISP” v příručce AutoLISP Developer’s Guide. Zkuste zjistit, v čem problém spočívá. Pokud vám hledání problému bude trvat příliš dlouho, použijte soubor gpmain.lsp, který je v adresáři lesson1 a pokračujte ve cvičeních.

Použití dodaného programu gpmain.lsp (pokud je to nutné)
  1. Uzavřete okno textového editoru obsahující váš kód gpmain.lsp.
  2. Z nabídky VLISPu vyberte položky Soubor [image] Otevřít soubor a otevřete soubor gpmain.lsp v adresáři \Tutorial\VisualLISP\lesson1.
  3. Vyberte položky Soubor [image] Uložit jako a uložte tento soubor do adresáře \Tutorial\ VisualLISP\MyPath jako gpmain.lsp, čímž nahradíte původní vytvořený soubor.


Spuštění programu s Visual LISPem

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Spuštění programu s Visual LISPem

Spuštěním programů AutoLISPu ve VLISPu získáváte přístup k množství nástrojů pro odlaďování chyb a můžete tak zkoumat problémy, které mohou nastat ve vaší aplikaci.

Jak načíst a spustit program
  1. V aktivním okně textového editoru vyberte z nabídky VLISPu položky Nástroje [image] Načíst text v Editoru.
  2. Na výzvu _$ v okně konzole VLISPu zadejte (C:GPath).

    3. Okno konzole VLISPu vyžaduje zadávání příkazů v syntaxi AutoLISPu, takže všechny názvy funkcí musí být uzavřeny v závorkách.

  3. Stiskněte klávesu ENTER nebo klepněte na tlačítko OK ve všech dialozích s hlášeními, které se zobrazí. Poslední hlášení by mělo znít „Gratulujeme váš program je hotov!“

Poznámka Pokud je AutoCAD při spuštění programu gpath minimalizován, neuvidíte výzvy, dokud okno programu AutoCAD neobnovíte do původní velikosti (pomocí hlavního panelu nebo kombinace kláves ALT + TAB).


Shrnutí cvičení 1

Návrh a začátek tvorby programu
Návrh a začátek tvorby programu
Shrnutí cvičení 1

V tomto cvičení jste:

  • Definovali účel programu.
  • Poznali výhodu zástupných funkcí.
  • Poznali názvy funkcí a jejich identifikaci (specifické pro aplikaci i obecné funkce používané znovu a znovu).
  • Se dozvěděli, jak lze použít VLISP ke kontrole svého kódu.
  • Se dozvěděli, jak se načítá a spouští program ve VLISPu.

Toto cvičení máte za sebou. Uložte znovu svůj soubor s programem, abyste měli poslední verzi.


Použití nástrojů pro odladění chyb

Toto cvičení vás naučí používat několik užitečných nástrojů VLISPu® pro odladění chyb, které zrychlují vývoj programů AutoLISPu®. Dále se dozvíte o rozdílu mezi lokálními a globálními proměnnými a o jejich použití. Váš program začne být aktivnější a požádá uživatele o zadání údajů. Tyto údaje budou uloženy v seznamu a vy postupně pochopíte, v čem spočívá výhoda používání seznamů v programech AutoLISPu. Není divu, vždy˙ zkratka LISP označuje LISt Processing language.

Témata v této části:

  • Rozdíl mezi lokálními a globálními proměnnými
  • Použití asociovaných seznamů k seskupení dat
  • Sledování proměnných programu
  • Revize kódu programu
  • Komentáře ke kódu programu
  • Nastavení zarážek a použití více kukátek
  • Shrnutí cvičení 2


Rozdíl mezi lokálními a globálními proměnnými

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Rozdíl mezi lokálními a globálními proměnnými

Toto cvičení se zabývá použitím lokálních proměnných a globálních proměnných dokumentů. Globální proměnné jsou přístupné všem funkcím načteným v rámci dokumentu (výkresu programu AutoCAD®). Tyto proměnné si mohou ponechat svou hodnotu od programu, který je definoval. Někdy přesně tohle potřebujete. Později v tomto cvičení si takový příklad ukážeme.

Lokální proměnné si uchovávají svou hodnotu jen po dobu běhu funkce, která je definovala. Jakmile tato funkce skončí, hodnoty lokální proměnné jsou automaticky zrušeny a systém uvolní pamě˙, kterou tato proměnná používala. Tato činnost je známá jako automatické čištění paměti a je typická pro většinu vývojářských prostředí LISPu, například VLISP. Lokální proměnné využívají pamě˙ový prostor efektivněji než proměnné globální

Další velkou výhodou lokálních proměnných je, že pokud jsou použity, je snadnější odladit chyby a spravovat vaše aplikace. U globálních proměnných si nemůžete být nikdy jisti, kdy nebo ve které funkci může být hodnota proměnné změněna; s lokálními proměnnými můžete změny sledovat. Obyčejně naleznete méně vedlejších účinků (když jedna část programu ovlivňuje proměnnou z jiné části programu).

Vzhledem k výše uvedeným výhodám jsou v rámci tohoto cvičení používány téměř výhradně lokální proměnné.

Poznámka Pokud jste již někdy pracovali s AutoLISPem, možná jste si zvykli používat globální proměnné během vývoje aplikace kvůli zkoušení programu při jeho vývoji. Tato praktika nyní díky výkonným nástrojům VLISPu pro odladění chyb ztrácí opodstatnění.

Témata v této části:

  • Použití lokálních proměnných v programu
  • Sledování funkce gp:getPointInput


Použití lokálních proměnných v programu

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Použití lokálních proměnných v programu

Podívejme se na funkci gp:getPointInput, kterou jste vytvořili ve cvičení 1:

(defun gp:drawOutline ()
  (alert
    "Funkce gp:getPointInput získá zadání od uživatele"
  )
  ;;Nyní vrátíte T, jakoby funkce pracovala správně.
  T
)

Až dosud toho tato funkce příliš mnoho nedělala. Nyní ji dokončíte přidáním funkcí, které získají zadání uživatele definující počáteční bod, koncový bod a šířku zahradní cesty.

Při tvorbě programů AutoLISPu je dobrým zvykem emulovat chování programu AutoCAD. Z tohoto důvodu by měl program uživatele požádat o výběr hodnoty poloviční šířky (místo zadání šířky výběrem bodu ve výkresu vzhledem k ose lineárního tvaru).

Jakmile funkce gp:getPointInput skončí, proměnné a hodnoty k nim přiřazené přestanou existovat. Proto uložíte zadané hodnoty od uživatele do lokálních proměnných. Výsledná funkce by mohla vypadat takto:

(defun gp:getPointInput ( / StartPt EndPt HalfWidth )
  (if (setq StartPt (getpoint "\nPočáteční bod cesty:
    (if (setq EndPt (getpoint StartPt "\nKoncový bod cesty:
      (if (setq HalfWidth (getdist EndPt "\nnPoloviční šířka cesty: "))
          T
      )
    )
  )
)

Lokální proměnné jsou deklarovány za znakem obráceného lomítka v příkazu defun uvozujícím funkci. První volání getpoint požádá uživatele o výběr počátečního bodu. Koncový bod je potom určen vzhledem k tomuto počátečnímu bodu. Při výběru koncového bodu vidí uživatel dynamicky se měnící vlečenou úsečku začínající v počátečním bodě. Stejně tak při nastavení hodnoty poloviční šířky uvidí uživatel podobnou vlečenou úsečku, která tentokrát bude představovat vzdálenost od koncového bodu.

Jak provést vyzkoušení činnosti funkce gp:getPointInput
  1. Napište kód funkce gp:getPointInput do okna konzole VLISPu.
  2. Kurzor umístěte v okně konzole za poslední závorku bloku kódu (nebo na následující řádek), stiskněte klávesu ENTER a tím nahradíte jakoukoliv dříve načtenou verzi funkce gp:getPointInput.
  3. Spusťte funkci okna konzole VLISPu zadáním (gp:getPointInput) na výzvu okna konzole.
  4. Na výzvu vyberte body a zadejte hodnotu poloviční šířky.


Sledování funkce gp:getPointInput

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Sledování funkce gp:getPointInput

Když jste spustili funkci gp:getPointInput, bylo řízení automaticky předáno z VLISPu do programu AutoCAD. Zodpověděli jste tři zobrazené výzvy a řízení bylo předáno produktem AutoCAD zpět do VLISPu, přičemž v okně konzole se zobrazil symbol T.

V rámci programu se děje následující:

  1. VLISP čeká, až vyberete první bod.
  2. Když vyberete první bod, program uloží hodnotu vašeho výběru (seznam obsahující tři hodnoty souřadnic X, Y a Z) do proměnné StartPt.
  3. První funkce if přezkoumá výsledek a určí, zda byla zadána platná hodnota či nebyla zadána žádná hodnota. Jakmile vyberete počáteční bod, je řízení předáno další funkci getpoint.
  4. Jakmile vyberete koncový bod, je jeho hodnota uložena do proměnné Endpt.
  5. Výsledek tohoto příkazu je ověřen dalším příkazem if a řízení je předáno funkci getdist.
  6. Funkce getdist funguje podobně, jako když vyberete bod na obrazovce nebo zadáte číselnou hodnotu. Uchovává střed pohledu v aktuálním výřezu.
  7. Program pokračuje dál a narazí na symbol T vnořený hluboko v rámci funkce. Dále nenásleduje žádná další funkce, činnost funkce je proto ukončena a je vrácena hodnota T. Toto T vidíte v okně konzole.

Nyní potřebujete nějaký prostředek pro vrácení hodnot z jedné funkce do druhé. Jedním možným řešením je sestavit seznam hodnot získaných od funkce gp:getPointInput, jaký je zvýrazněn v následujícícm kódu:

(defun gp:getPointInput ( / StartPt EndPt HalfWidth )
  (if (setq StartPt (getpoint "\nPočáteční bod cesty:
     (if (setq EndPt (getpoint StartPt "\nKoncový bod cesty:
       (if (setq HalfWidth (getdist EndPt "\nnPoloviční šířka cesty: "))
 (list StartPt EndPt HalfWidth)
             )
     )
  )
)

Zkopírujte si tuto verzi funkce gp:getPointInput do okna konzole a stiskněte klávesu ENTER. Nyní máme příležitost vyzkoušet si další nástroj okna konzole.

Jak použít nástroje historie okna konzole VLISPu ke spuštění funkce gp:getPointInput
  1. Stiskněte klávesu TAB.

    2. Tím se vyvolá příkaz historie okna konzole VLISPu, což je cyklování mezi příkazy zadanými dříve v okně konzole VLISPu. Pokud požadovaný příkaz přejdete, můžete cyklovat zpět pomocí kombinace kláves SHIFT+TAB.

  2. Jakmile uvidíte na výzvě okna konzole příkaz (gp:getPointInput), stiskněte klávesu ENTER a spusťte znovu funkci.
  3. Zodpovězte výzvy stejně jako předtím.

Funkce vrací seznam obsahující dva vnořené seznamy a reálnou hodnotu (s plovoucí desetinnou čárkou). Vrácené hodnoty vypadají takto:

((4.46207 4.62318 0.0) (7.66688 4.62318 0.0) 0.509124)

Tyto hodnoty odpovídají proměnným StartPt,EndPt a HalfWidth.


Použití asociovaných seznamů k seskupení dat

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Použití asociovaných seznamů k seskupení dat

Předchozí příklad sice funguje, ale je možné použít ještě lepší způsob. V dalším cvičení sestavíte asociovaný seznam, (neboli assoc list, podle funkce LISPu pracující s asociovanými seznamy). V asociovaném seznamu jsou hodnoty, které vás zajímají, asociovány s klíčovými hodnotami. Zde je příklad asociovaného seznamu:

((10 4.46207 4.62318 0.0) (11 7.66688 4.62318 0.0) (40 . 1.018248))

V tomto asociovaném seznamu jsou klíčovými hodnotami čísla 10, 11 a 40. Tyto klíčové hodnoty slouží jako jedinečný index v rámci seznamu. Toto je právě mechanismus, který AutoCAD používá při vracení dat entity AutoLISPu, pokud v rámci svého programu přistupujete k entitě. Klíčová hodnota 10 indikuje počáteční bod, klíčová hodnota 11 je obvykle koncový bod.

Jaké jsou výhody asociovaného seznamu? Na rozdíl od běžných seznamů zde nezáleží na pořadí vrácených hodnot. Podívejte se znovu na první seznam:

((4.46207 4.62318 0.0) (7.66688 4.62318 0.0) 0.509124)

Podívejte se na vrácené hodnoty; není zřejmé, který dílčí seznam je počátečním bodem a který je koncovým. Navíc pokud v budoucnosti danou funkci upravíte, může to ovlivnit všechny funkce, u nichž je důležité pořadí vrácených hodnot.

U asociovaného seznamu na pořadí hodnot nezáleží. Pokud se pořadí v asociovaném seznamu změní, nadále bude zřejmé, co která hodnota definuje. Například hodnota 11 je stále koncový bod bez ohledu na to, co se stane s hlavním seznamem:

((11 7.66688 4.62318 0.0) ; pořadí seznamu
 (40 . 1.018248) ; bylo
 (10 4.46207 4.62318 0.0)) ; upraveno

Témata v této části:

  • Praktické použití asociovaných seznamů
  • Uložení návratové hodnoty funkce gp:getPointInput do proměnné


Praktické použití asociovaných seznamů

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Praktické použití asociovaných seznamů

Když použijete asociované seznamy, měli byste si ujasnit, co označují jednotlivé klíčové hodnoty. U zahradní cesty znamenají klíčové hodnoty 00, 11, 40, 41 a 50 toto:

  • 10 značí 3D souřadnici počátečního bodu zahradní cesty.
  • 11 značí 3D souřadnice počátečního bodu zahradní cesty.
  • 40 značí šířku (nikoliv poloviční šířku) zahradní cesty.
  • 41 značí délku zahradní cesty od začátku do konce.
  • 50 značí primární vektor (úhel) zahradní cesty.

Následuje aktualizovaná verze funkce gp:getPointInput. V rámci ní je funkce AutoLISPu s názvem cons (zkratka pro „construct a list“), která sestaví dílčí seznamy s klíčovými slovy patřící do daného asociovaného seznamu. Zkopírujte si tuto verzi do okna konzole VLISPu, stiskněte klávesu ENTER a spusťte znovu funkci (gp:getPointInput):

(defun gp:getPointInput ( / StartPt EndPt HalfWidth )
  (if (setq StartPt (getpoint "\nPočáteční bod cesty:
    (if (setq EndPt (getpoint StartPt "\nKoncový bod cesty:
      (if (setq HalfWidth (getdist EndPt "\nnPoloviční šířka cesty: "))
            ;; pokud jste se dostali až sem, vytvořte seznam asociací
            ;; jak je popsáno výše. Toto bude návratová hodnota
            ;; funkce.
            (list
              (cons 10 StartPt)
              (cons 11 EndPt)
              (cons 40 (* HalfWidth 2.0))
              (cons 50 (angle StartPt EndPt))
              (cons 41 (distance StartPt EndPt))
                    )
      )
    )
  )
)

Všimněte si, že při vytváření seznamu převádí program poloviční šířku zadanou uživatelem na celou šířku vynásobením zadané hodnoty 2.

Okno konzole VLISPu obsahuje nyní podobný výstup:

_$ (gp:getPointInput)

((10 2.16098 1.60116 0.0) (11 12.7126 7.11963 0.0) (40 . 0.592604) (50 . 0.481876) (41 . 11.9076))
_$


Uložení návratové hodnoty funkce gp:getPointInput do proměnné

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Uložení návratové hodnoty funkce gp:getPointInput do proměnné

Nyní vyzkoušejte něco jiného. Zavolejte znovu danou funkci, ale tentokrát uložte návratovou hodnotu do proměnné nazvané gp_PathData. Na výzvu okna konzole VLISPu zadejte následující:

(setq gp_PathData (gp:getPointInput))

Chcete-li si prohlédnout hodnotu proměnné, kterou jste právě nastavili, zadejte její název na výzvu okna konzole VLISPu:

_$ gp_PathData

VLISP vrátí údaj podobný následujícímu:

((10 2.17742 1.15771 0.0) (11 13.2057 7.00466 0.0) (40 . 1.12747) (50 . 0.487498) (41 . 12.4824))


Sledování proměnných programu

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Sledování proměnných programu

VLISP nabízí ucelenou sadu programovacích a odlaďovacích nástrojů. Jedním z nejužitečnějších je nástroj Kukátko, který umožňuje zkoumat proměnné podrobněji než okno konzole VLISPu. Kukátkem můžete sledovat i lokální proměnné v rámci funkcí, a to přímo při spouštění funkce.

Jak docílit sledování hodnoty proměnné
  1. Z nabídky VLISPu vyberte položky Ladění [image] Přidat kukátko. VLISP zobrazí dialog „Přidat kukátko”.

    2. Zadejte název proměnné, kterou chcete sledovat. V tomto příkladu zadejte gp_PathData, což je proměnná, kterou jste právě nastavili z okna konzole VLISPu. VLISP zobrazí okno Kukátko:

    VLISP zobrazí hodnotu proměnné na jednom řádku v rámci okna Kukátko, což je základní okno zobrazené na obrázku. V tomto případě je hodnotou proměnné dlouhý seznam a nelze přehlédnout celou hodnotu. Okno Kukátko můžete zvětšit nebo zmenšit tažením jeho okraje, ale nabízí se lepší možnost.

  2. Poklepejte na název proměnné v okně kukátka. Otevře se okno Inspektor:

    3. Okno Inspektor sděluje datový typ proměnné (v tomto případě seznam) a hodnotu proměnné. U seznamů zobrazí okno Inspektor každou položku na jednom řádku.

  3. Poklepejte na řádek s klíčem 11. VLISP otevře další okno Inspektor:

  4. Až ukončíte zkoumání proměnných, zavřete všechna okna Inspektor a okno Kukátko ponechte otevřené.


Revize kódu programu

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Revize kódu programu

Nyní, když víte, jak se v kódu AutoLISPu používají asociované seznamy, můžete tuto metodu použít při psaní finální verze funkce gp:getPointInput. Pomocí následujícího kódu nahraďte nebo opravte verzi funkce gp:getPointInput uloženou v souboru gpmain.lsp.

Poznámka Pokud potřebujete nebo chcete kód napsat přímo do souboru gpmain.lsp, místo jeho kopírování z jiného souboru, můžete ušetřit čas vynecháním komentářů (řádky začínající středníky). Příliš si ale na psaní kódu bez komentářů nezvykejte

;;;--------------------------------------------------------------;
;;; Funkce: gp:getPointInput ;
;;;--------------------------------------------------------------;
;;; Popis: Tato funkce vyzve uživatele, aby vybral tři ;
;;; body ve výkresu, které určí ;
;;; umístění, směr a velikost cesty. ;
;;;--------------------------------------------------------------;
;;; Pokud uživatel zadá platná data, ;
;;; použijte funkce startPt a endPt pro určení pozice, délky, ;
;;; a úhlu kreslené cesty. ;
;;;--------------------------------------------------------------;
;;; Návratová hodnota této funkce je seznam obsahující: ;
;;; (10 . Počáteční bod) - Seznam 3 reálných hodnot (bod) určujících ;
;;; ;; počáteční bod zahradní cesty. ;
;;; (11 . Koncový bod) - Seznam 3 reálných hodnot (bod) určujících ;
;;; ;; koncový bod zahradní cesty. ;
;;; (40 . Šířka) ;; Reálné číslo určující šířku ;
;;; ;; šířka. ;
;;; (41 . Délka) ;; Reálné číslo určující délku ;
;;; ;; hranice. ;
;;; (50 . Úhel cesty) ;; Reálné číslo určující úhel ;
;;; ;; cesty, v radiánech. ;
;;;--------------------------------------------------------------;
(defun gp:getPointInput ( / StartPt EndPt HalfWidth )
  (if (setq StartPt (getpoint "\nPočáteční bod cesty:
    (if (setq EndPt (getpoint StartPt "\nKoncový bod cesty:
      (if (setq HalfWidth (getdist EndPt "\nnPoloviční šířka cesty: "))
         ;; pokud jste se dostali až sem, vytvořte seznam asociací
         ;; jak je popsáno výše. Toto bude návratová hodnota
         ;; funkce.
         (list
           (cons 10 StartPt)
           (cons 11 EndPt)
           (cons 40 (* HalfWidth 2.0))
           (cons 50 (angle StartPt EndPt))
           (cons 41 (distance StartPt EndPt))
) ) ) ) )

Nyní je třeba aktualizovat hlavní funkci C:GPath v souboru gpmain.lsp. Upravte ji tak, aby vypadala následovně:

(defun C:GPath (/ gp_PathData)
  Požádejte uživatele o vstup: nejdříve o umístění cesty a
  ;; směr, potom parametry cesty. Pokračuje pouze pokud má platné
  ;; zadání. Uloží data do proměnné gp_PathData.
  (if (setq gp_PathData (gp:getPointInput))
    (if (gp:getDialogInput)
      (progn
            ;; V tomto bodě máte platné zadání od uživatele.
            ;; Nakreslete obrys a uložte výslednou křivku
            ;; do proměnné PolylineName.
            (setq PolylineName (gp:drawOutline))
            (princ "\nFunkce gp:drawOutline vrátila <")
            (princ PolylineName)
            (princ ">")
            (Alert "Gratulujeme - váš program je hotov!")
        ) ;_ end of progn
       (princ "\nFunkce byla zrušena.")
    ) ;_ konec if
    (princ "\nNedostatečné informace pro nakreslení hranice.")
  ) ;_ konec if
 (princ) ; tiše skončit
) ;_ end of defun

Pokud kopírujete a vkládáte kód, přidejte k němu ještě následující komentáře jako záhlaví před C:GPath:

;;;**************************************************************;
;;; Funkce: C:GPath Hlavní funkce kreslení zahradní cesty ;
;;;--------------------------------------------------------------;
;;; Popis: Toto je hlavní funkce programu zahradní cesty. Je to ;
;;; funkce C:, což znamená, že se změní na ;
;;; příkaz programu AutoCAD nazvaný GPATH. Tato funkce ;
;;; určuje celkový běh zahradní cesty ;
;;; (program). ;
;;;**************************************************************;
;;; Proměnná gp_PathData je asociovaný seznam: ;
;;; (10 . Počáteční bod) - Seznam 3 reálných hodnot (bod) určujících ;
;;; počáteční bod zahradní cesty. ;
;;; (11 . Koncový bod) - Seznam 3 reálných hodnot (bod) určujících ;
;;; koncový bod zahradní cesty. ;
;;; (40 . Šířka) ;; Reálné číslo určující šířku ;
;;; šířka. ;
;;; (41 . Délka) ;; Reálné číslo určující hranici ;
;;; hranice. ;
;;; (50 . Úhel cesty) ;; Reálné číslo určující úhel ;
;;; ;; cesty, v radiánech. ;
;;; (42 . Velikost dlaždice) - Reálné číslo určující velikost ;
;;; (poloměr) dlaždic zahradní cesty. ;
;;; (43 . Odsazení dlaždic) - Vzdálenost dlaždic, od okraje k okraji. ;
;;; ( 3 . Styl vytvoření objektu) ;
;;; - Styl vytvoření objektu určuje, jak;
;;; budou dlaždice nakresleny. Instalace produktu
;;; očekávaná hodnota je řetězec a ;
;;; jedna ze tří hodnot (písmo řetězce ;
;;; není důležité): ;
;;; "ActiveX" ;
;;; "Entmake" ;
;;; "Command" ;
;;; ( 4 . Styl okraje křivky) ;
;;; - Styl okrajové křivky určuje ;
;;; typ křivky určený pro ;
;;; hranice cesty. Očekávaná hodnota ;
;;; jedna z následujících (písmo řetězce;
;;; není důležité): ;
;;; "Pline" ;
;;; "Light" ;
;;;**************************************************************;
Jak provést prověření revize kódu
  1. Uložte aktualizovaný soubor.
  2. Použijte funkci Zkontrolovat a vyhledejte syntaktické chyby kódu.
  3. Formátujte kód, aby byl čitelnější.
  4. Načtěte kód, aby VLISP předefinoval starší verze funkcí.
  5. Spusťte program a na výzvu okna konzoly zadejte (c:gpath).

Pokud program neběží úspěšně, pokuste se kód opravit a spustit znovu. Tento postup zopakujte podle potřeby. Pokud vše zklame, můžete zkopírovat správný kód z adresáře Tutorial\VisualLISP\Lesson2.


Komentáře ke kódu programu

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Komentáře ke kódu programu

VLISP považuje každý příkaz AutoLISPu začínající středníkem za komentář. Poslední dva příklady kódu obsahovaly spoustu komentářů. Komentář v programu AutoLISPu je poznámka, kterou si napíšete do kódu pro sebe, ne program samotný. Komentáře kódu jsou dobrým programovacím návykem. Proč byste si komentáře měli psát?

  • Vysvětlí vám kód při pozdějších úpravách, kdy budete přidávat funkce požadované uživateli. Pamě˙ neslouží vždy dokonale a i nejjednodušší posloupnost funkcí se může za nějaký čas snadno stát nejasnou změtí závorek.
  • Vysvětlíte kód těm, kdo budou po vás s kódem programu pracovat. Číst cizí kód může být někdy frustrující, obzvláště pokud neobsahuje skoro žádné komentáře.

VLISP obsahuje některé pomocné programy, které vám tvorbu komentářů kódu usnadní. Všimněte si, že některé komentáře v příkladu začínají třemi středníky (;;;), někdy dvěma (;;) a někdy pouze jedním (;). Viz “Applying Visual LISP Comment Styles” v příručce AutoLISP Developer’s Guide s informacemi o tom, jak VLISP pracuje s různými komentáři.

Abychom ušetřili prostor, zbývající kódy v tomto cvičení neobsahují veškeré komentáře uložené ve zdrojových souborech. Předpokládáme, že jste si již na používání komentářů zvykli a budete tak činit bez dalších upozorněn.


Nastavení zarážek a použití více kukátek

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Nastavení zarážek a použití více kukátek

Zarážka (bod přerušení) je symbol (bod), který umístíte do zdrojového kódu a který označuje místo, kde se má program dočasně zastavit. Při spuštění kódu pracuje VLISP normálně až do nalezení zarážky. V tom místě přeruší VLISP vykonávání kódu a čeká na pokyn, co dál. Program tedy není úplně zastaven — je jen dočasně přerušen.

Když je váš program přerušen, můžete:

  • Procházet kód funkci po funkci nebo výraz po výrazu.
  • Obnovit v kterémkoliv bodě znovu normální běh programu.
  • Dynamicky měnit hodnoty proměnných a tak měnit výsledky programu.
  • Přidávat proměnné do okna Kukátko.

Témata v této části:

  • Použití panelu nástrojů Ladění
  • Krokování v rámci kódu
  • Sledování proměnných při krokování programem
  • Přechod z funkce gp:getPointInput do C:Gpmain


Použití panelu nástrojů Ladění

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Použití panelu nástrojů Ladění

Panel nástrojů Ladění obsahuje několik nástrojů, které se naučíte používat v tomto cvičení. Implicitně je tento panel nástrojů připojen k panelům nástrojů Zobrazit a Nástroje a zobrazí se jako samostatný panel nástrojů VLISPu.

Panel nástrojů Ladění je soubor ikon nejvíce vlevo. Většina tlačítek tohoto panelu je neaktivní až do okamžiku, kdy spustíte svůj program v režimu odlaďování chyb (to znamená s jedním nebo více definovanými zarážkami).

Pokud jste tak dosud neučinili, přesuňte panel nástrojů Ladění z jeho pozice u horního okraje obrazovky. Uchopte jej a táhněte za dva svislé uzly v levé části panelu. Kterýkoliv z panelů nástrojů VLISPu si můžete takto přesunout na obrazovce tak, aby jejich umístění co nejlépe vyhovovalo vaší práci.

Panel nástrojů Ladění je rozdělen do tří hlavních skupin po třech tlačítkách. Při spuštění programu v režimu odlaďování chyb vypadá panel nástrojů Ladění takto:

  • První tři tlačítka slouží ke krokování (pohybu) v rámci kódu.
  • Další tři tlačítka určují, jak má VLISP pokračovat, když narazí na zarážku nebo chybu.
  • Poslední tři tlačítka umis˙ují nebo odstraňují zarážku, přidávají okno Kukátko a umožňují skok na pozici v rámci kódu, kde se vyskytla poslední zarážka.

Poslední tlačítko v panelu nástrojů Ladění je „Indikátor kroku (Step Indicator)“. To nespouští žádnou funkci, ale nabízí vizuální pomůcku: ukazuje, kde se při procházení kódu nachází kurzor. Když nejste v režimu odladění chyb, toto tlačítko je prázdné.

Jak provést umístění zarážky
  1. V okně editoru VLISPu obsahujícím kód gpmain.lsp, umístěte kurzor před úvodní závorku funkce setq v rámci funkce gp:getPointInput:
    2. (setq HalfWidth (getdist EndPt "\nPoloviční šířka cesty: "))
  2. Klepněte jednou tlačítkem myši. Situace je zobrazena na následujícím obrázku:

  3. Nastavte bod vložení textu a klepněte na tlačítko Přepnout zarážku v panelu nástrojů Ladění.

    4. Tlačítko Přepnout zarážku funguje jako přepínač mezi stavem vypnutí a zapnutí. Pokud na pozici kurzoru není žádná zarážka, bude nastavena; pokud tam již zarážka je, odstraní ji.

  4. Stiskněte tlačítko Načíst aktivní editační okno v panelu nástrojů Nástroje a načtěte soubor.
  5. Spusťte funkci (C:GPath) na výzvu okna konzole VLISPu.

    6. VLISP provede program normálně až do zarážky. V tomto případě vás požádá o zadání prvních dvou bodů — počátečního a koncového bodu cesty.

  6. Na výzvu zadejte počáteční a koncový bod.

    7. Po zadání bodů pozastaví VLISP provádění programu a v okně editoru zvýrazní řádek kódu na pozici zarážky:

Zde si povšimněte několika věcí:

  • Kurzor se nachází přímo v zarážce. Mohli byste to snadno přehlédnout, proto VLISP nabízí ještě jednu pomůcku.
  • V panelu nástrojů Ladění zobrazuje ikona „Indikátor kroku (Step Indicator)“ červený kurzor pro editaci textu před párem závorek. To naznačuje, že proces odladění chyb VLISPu se zastavil před daným výrazem.


Krokování v rámci kódu

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Krokování v rámci kódu

Ke krokování v rámci kódu můžete použít tři tlačítka. Jedná se o tři tlačítka nejvíce nalevo v panelu nástrojů Ladění. Mají následující funkce:

  • Krok ke zvýrazněnému výrazu.
  • Posun na konec zvýrazněného výrazu.
  • Posun na konec funkce, kde se aktuálně nacházíte.

Před provedením výběru se ještě jednou podívejte na zvýrazněný kód, pozici kurzoru a tlačítko „Indikátor kroku (Step Indicator)“. Shrnutí: Výraz je zvýrazněn, obsahuje funkci getdist vnořenou v rámci funkce setq a kurzor se nachází na samém začátku zvýrazněného bloku.

Jak používat krokování v rámci kódu od zarážky
  1. Stiskněte tlačítko Krokovat bez vnoření.

    2. Po stisku tlačítka Krokovat bez vnoření je řízení předáno programu AutoCAD a jste požádáni o zadání šířky cesty.

  2. Zodpovězte výzvu.

    3. Po zadání šířky je řízení vráceno VLISPu. Povšimněte si, kde se nachází kurzor, a jaký indikátor krokování je na tlačítku.

    VLISP vyhodnotí celý zvýrazněný výraz a zastaví se na jeho konci.

  3. Znovu stiskněte tlačítko Krokovat bez vnoření. VLISP skočí na začátek dalšího bloku kódu a zvýrazní celý blok.
  4. Stiskněte tlačítko Krokovat s vnořením (nikoli Krokovat bez vnoření).

Poznámka Pokud v průběhu tohoto cvičení provedete nesprávný výběr a přeskočíte jeden nebo dva kroky, můžete cvičení snadno restartovat. Nejprve stiskněte tlačítko Reset v panelu nástrojů Ladění. Tím ukončíte vykonávání veškerého kódu VLISPu a resetujete systém VLISPu na nejvyšší úroveň. Potom začněte bodem 1.

Nyní je zvýrazněna první funkce cons a VLISP se zastavil přímo před ní (povšimněte si vzhledu tlačítka „Indikátor kroku (Step Indicator)“.


Sledování proměnných při krokování programem

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Sledování proměnných při krokování programem

Při krokování programem můžete proměnné přidávat do okna Kukátko a měnit jejich hodnoty.

Pokud nevidíte na obrazovce okno Kukátko, jednoduše stiskněte tlačítko Okno kukátka v panelu nástrojů.

Pokud je ve vašem okně Kukátko stále zobrazena proměnná gp_PathData, stiskněte tlačítko Vymazat okno nacházející se v horní části okna Kukátko.

Jak přidat proměnné do okna Kukátko
  1. Poklepejte na jakýkoliv výskyt StartPt v okně textového editoru VLISPu. Stejně postupujte u proměnné, jejíž hodnotu chcete sledovat.
  2. Stiskněte tlačítko Přidat kukátko v okně Kukátko nebo klepněte pravým tlačítkem a z místní nabídky vyberte položku Přidat kukátko.
  3. Vypisuje nebo mění hodnoty systémových proměnných Vaše okno Kukátko by mělo vypadat následovně:

Jestliže odlaďujete program, který nepracuje správně, můžete pomocí zarážek v kombinaci s kukátky přesně sledovat, že vaše proměnné obsahují požadované hodnoty.

Pokud některá proměnná neobsahuje hodnotu, kterou by měla, můžete její hodnotu změnit a sledovat, jak to ovlivní program. Řekněme například, že hodnota halfwidth by měla být celé číslo. Jelikož jste však nevybírali body pozorně, dostali jste nakonec hodnotu 1.94818.

Jak změnit hodnoty proměnné při běhu programu
  1. Na výzvu konzole VLISPu zadejte:
    2. (setq halfwidth 2.0)

    Povšimněte si, že se mění hodnota v okně Kukátko. Můžete si však být jisti, že nová hodnota se použije, když bude v seznamu asociací vytvořen dílčí seznam šířky (40 . šířka)? Přidejte do okna Kukátko jeden nebo více výrazů a vyzkoušejte to.

  2. Z nabídky VLISPu vyberte položky Ladění [image] Kukátko posledního vyhodnocení.

    3. Tím se do okna Kukátko vloží proměnná s názvem *Last-Value*. *Last‑Value* je globální proměnná, do níž VLISP automaticky ukládá hodnotu posledního vyhodnoceného výrazu.

  3. Krokujte postupně programem (stiskem tlačítka Krokovat s vnořením nebo tlačítka Krokovat bez vnoření), dokud nebude vyhodnocen výraz vytvářející dílčí seznam width. Kód pro tuto operaci je následující:
    4. (cons 40 (* HalfWidth 2.0))

    Pokud jste podle předchozího návodu nastavili hodnotu HalfWidth,vyhodnocení tohoto výrazu by mělo v okně Kukátka vrátit (40 .4.0)


Přechod z funkce gp:getPointInput do C:Gpmain

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Přechod z funkce gp:getPointInput do C:Gpmain

Je zde ještě jeden problém, který je nutno zdůraznit: co se stane s hodnotami lokálních proměnných ve funkci gp:getPointInput po ukončení funkce.

Jak ukončit funkci gp:getPointInput a vrátit řízení funkci c:gpath
  1. Stiskněte tlačítko Krokovat ven.

    2. VLISP přejde na konec funkce gp:getPointInput a zastaví se těsně před ukončením.

  2. Stiskněte tlačítko Krokovat s vnořením.

Přechod z funkce gp:getPointInput do C:Gpmain

Prohlédněte si hodnoty proměnných v okně Kukátko. Jelikož se jedná o lokální proměnné funkce gp:getPointInput, endpt a StartPt, mají hodnotu nil. VLISP automaticky uvolnil pamě˙ obsazenou těmito proměnnými. Normálně obsahuje třetí lokální proměnná funkce HalfWidth také hodnotu nil, ale kvůli odlaďování chyb byla globálně přenastavena v okně konzole a stále obsahuje v okně Kukátko hodnotu 2.0. Také globální proměnná *Last-Value* zobrazuje asociovaný seznam sestavený funkcí gp:getPointInput.

Vaše první sezení věnované odladění chyb programu je u konce. Nezapomeňte však, že i nadále je váš program v pozastavené animaci .

Jak dokončit cvičení
  1. Stiskněte tlačítko Pokračovat v panelu nástrojů Ladění. Zodpovězte zobrazené výzvy. Tím se program uvede do stavu nutného pro další cvičení.
  2. Z nabídky VLISPu vyberte položky Ladění [image] Vymazat všechny zarážky. Na zobrazenou výzvu odpovězte „ano“. Tím se z kódu odstraní všechny zarážky.

    3. Nezapomeňte: jednotlivé zarážky můžete odstranit tak, že na ně umístíte kurzor a stisknete tlačítko Přepnout zarážku.


Shrnutí cvičení 2

Použití nástrojů pro odladění chyb
Použití nástrojů pro odladění chyb
Shrnutí cvičení 2

V tomto cvičení jste:

  • Se dozvěděli, co to jsou lokální a globální proměnné.
  • Do programu umístili a odstranili zarážky.
  • Krokováním postupovali běžícím programem.
  • Sledovali a dynamicky měnili hodnotu proměnných programu během vykonávání kódu.
  • Viděli, jak lze přenastavit lokální proměnné na hodnotu nil potom, co se ukončí funkce, která je definovala.

Nástroje, které jste poznali v tomto cvičení, budete při vývoji aplikací AutoLISP pomocí VLISP používat velmi často.


Kreslení hranice cesty

V tomto cvičení rozšíříte svůj program tak, že nakreslí něco v programu AutoCAD — křivkovou hranici zahradní cesty. Pro nakreslení hranice musíte použít některé pomůcky, které nejsou specifické pro určitou aplikaci, ale mají obecnější charakter a mohou být použity opakovaně v různých aplikacích. Dále se dozvíte o zapisování funkcí, přijímání argumentů (data zasílaná funkcím z vnějšího zdroje) a proč je používání argumentů tak výhodné. Na konci tohoto cvičení nakreslíte tvar programu AutoCAD parametricky, tedy dynamickým způsobem na základě jedinečných parametrů zadaných uživatelem.

Témata v této části:

  • Plánování pomůcek
  • Kreslení entity programu AutoCAD
  • Použití funkce pro kreslení hranice
  • Shrnutí cvičení 3


Plánování pomůcek

Kreslení hranice cesty
Kreslení hranice cesty
Plánování pomůcek

Pomůcky s opakovaným použitím provádějí úlohy společné v mnoha psaných aplikacích. Tyto funkce jsou tedy nástrojem, který můžete používat znovu a znovu.

Když si vytvoříte funkci jako součást nástroje, důkladně ji okomentujte. V komentáři uveďte i prvky, které byste do funkce chtěli přidat v budoucnu.

Témata v této části:

  • Převod stupňů na radiány
  • Převod 3D bodů na 2D body


Převod stupňů na radiány

Kreslení hranice cesty
Kreslení hranice cesty
Převod stupňů na radiány

Nyní vytvoříte funkci, která vás zbaví nutnosti opakovaného převodu jednotek. Vypadá takto:

(defun Degrees->Radians (numberOfDegrees)
(* pi (/ numberOfDegrees 180.0)))

;;; Funkce: Stupně->Radiány ; Jméno funkce tedy naznačuje její účel.

Proč potřebujete funkci pro převod jednotek? Interně používá AutoCAD® radiány, většina uživatelů ovšem pracuje se stupni. Tato funkce vám tedy umožní i nadále myslet ve stupních a přitom AutoLISP® převede daná čísla na radiány.

Jak otestovat funkci pomůcky
  1. Na výzvu konzole VLISPu zadejte:
    2. (defun Degrees->Radians (numberOfDegrees)
    (* pi (/ numberOfDegrees 180.0)))
  2. Na výzvu konzole VLISPu zadejte:
    3. (degrees->radians 180)

    Funkce vrátí číslo 3.14159. Podle toho, jak tato funkce funguje, 180 stupňů odpovídá 3.14159 radiánu.

Budete-li chtít tuto funkci použít ve vašem programu, jednoduše zkopírujte její definici z okna konzole do souboru gpmain.lsp Můžete ji vložit kamkoliv do souboru, nikoliv však doprostřed existující funkce.

Pro zpřehlednění vaší práce vyberte vložený text a stiskněte tlačítko Zformátovat výběr; VLISP správně odsadí a zformátuje kód.

Nyní napište komentář popisující činnost funkce. Po okomentování funkce by váš kód měl vypadat asi takto:

;;;--------------------------------------------------------------;
;;; Funkce: Stupně->Radiány ;
;;;--------------------------------------------------------------;
;;; Popis: Tato funkce převede hodnotu představující hodnotu;
;;; úhlu ve stupních na radiány ;
;;; ekvivalentní. Nekontroluje se platnost parametru ;
;;; parametru numberOfDegrees -- vždy je očekávána ;
;;; platná hodnota. ;
;;;--------------------------------------------------------------;
(defun Degrees->Radians (numberOfDegrees)
  (* pi (/ numberOfDegrees 180.0))
)


Převod 3D bodů na 2D body

Kreslení hranice cesty
Kreslení hranice cesty
Převod 3D bodů na 2D body

Další užitečná funkce v programu na kreslení zahradní cesty převede 3D body na 2D body. AutoCAD obyčejně pracuje s 3D souřadnicemi, ale některé entity (například odlehčené křivky) jsou vždy definovány v 2D. Body vrácené funkcí getpoint jsou 3D, proto je třeba vytvořit funkci, která je převede.

Jak provést převod 3D bodu na 2D bod
  1. Na výzvu konzole VLISPu zadejte:
    2. (defun 3dPoint->2dPoint (3dpt)(list (car 3dpt) (cadr 3dpt)))
  2. Vyzkoušejte funkci - na výzvu konzole VLISPu zadejte:
    3. (3dpoint->2dpoint (list 10 20 0))

    Tohle zatím funguje, ale u aplikace zahradní cesty se nabízí ještě jeden aspekt. I když ve funkcích LISPu často nezáleží na tom, zda má číselná hodnota tvar celého nebo reálného čísla, u funkcí ActiveX, které použijete později v tomto cvičení, je tomu jinak. Funkce ActiveX vyžadují reálná čísla. Jednoduchou úpravou funkce dosáhnete toho, že bude místo celých čísel vracet čísla reálná.

  3. Ve výzvě konzoly zadejte následující kód:
    4. (defun 3dPoint->2dPoint (3dpt)(list (float(car 3dpt))
    (float(cadr 3dpt))))
  4. Spusťte funkci znovu:
    5. (3dpoint->2dpoint (list 10 20 0))

    Povšimněte si, že návratové hodnoty jsou nyní reálná čísla (mají číslice za desetinnou tečkou).

  5. Znovu testujte funkci, tentokrát pomocí funkce getpoint. Na výzvu konzole VLISPu zadejte:
    6. (setq myPoint(getpoint))
  6. Klepněte v kreslicí ploše programu AutoCAD.

    7. Funkce vrátí číslo 3.14159.

  7. Na výzvu konzole VLISPu zadejte:
    8. (3dPoint->2Dpoint myPoint)

    Povšimněte si, že nyní je vrácen 2D bod.

    Nyní přidejte funkci do souboru gpmain.lsp stejně, jako jste to udělali s funkcí Degrees‑>Radians. Nový kód by měl vypadat následovně:

    ;;;--------------------------------------------------------------;
    ;;; Funkce: 3dBod->2dBod ;
    ;;;--------------------------------------------------------------;
    ;;; Popis: Tato funkce používá jeden parametr představující;
    ;;; 3D bod (seznam tří celých nebo reálných hodnot), a ;
    ;;; převede jej na 2D bod (seznam dvou reálných hodnot).;
    ;;; Parametr 3D bod není kontrolován ;
    ;;; předpokládá se, že se jedná o platný bod. ;
    ;;;--------------------------------------------------------------;
    ;;; Úkoly: Přidat nějaký parametr, který by zkontroloval zadání ;
    ;;; a zaručil, že se funkce nezablokuje ;
    ;;; při zadání nulové hodnoty nebo jiného datového typu než ;
    ;;; je 3D bod. ;
    ;;;--------------------------------------------------------------;
    (defun 3dPoint->2dPoint (3dpt)
      (list (float(car 3dpt)) (float(cadr 3dpt)))
    )

    Povšimněte si, že záhlaví funkce obsahuje komentář týkající se budoucích úprav funkce. Pokud si chcete psaní funkcí procvičit, popřemýšlejte o tom, jak to udělat, aby její běh neohrozila neplatná data.

    Doporučení: funkce numberp a listp …

    (listp '(1 1 0)) => T
    (numberp 3.4) => T


Kreslení entity programu AutoCAD

Kreslení hranice cesty
Kreslení hranice cesty
Kreslení entity programu AutoCAD

Většina programů AutoLISPu kreslí entity pomocí jednoho z následujících způsobů:

  • funkce ActiveX,
  • funkce entmake
  • funkce command

Toto cvičení popisuje tvorbu entit prostřednictvím funkce ActiveX®. Ve cvičení 5 použijete funkci entmake a příkazy programu AutoCAD.

Témata v této části:

  • Vytváření entit pomocí funkcí ActiveX
  • Vytváření entit pomocí funkce entmake
  • Vytváření entit pomocí příkazového řádku programu AutoCAD


Vytváření entit pomocí funkcí ActiveX

Kreslení hranice cesty
Kreslení hranice cesty
Vytváření entit pomocí funkcí ActiveX

Nejnovější způsob vytváření entit je pomocí funkcí ActiveX v rámci VLISPu. Funkce ActiveX má oproti funkcím entmake a command několik výhod.

  • Funkce ActiveX jsou rychlejší.
  • Názvy funkcí ActiveX naznačují operaci, kterou funkce provádí, proto se tyto funkce vyznačují lepší čitelností, správou a odladěním chyb.

Příklady funkcí ActiveX uvidíte později v tomto cvičení.


Vytváření entit pomocí funkce entmake

Kreslení hranice cesty
Kreslení hranice cesty
Vytváření entit pomocí funkce entmake

Funkce entmake umožňuje tvorbu entit tak, že shromáždí rozmanité hodnoty, například souřadnice polohy, informace o orientaci, hladině či barvě do asociovaného seznamu, a potom nechá AutoCAD, aby podle těchto dat entitu vytvořil. Asociativní seznam funkce entmake vypadá podobně jako asociovaný seznam vrácený funkcí entget. Rozdíl je v tom, že funkce entget jen vrací informace o entitě, zatímco funkce entmake vytvoří z dat novou entitu.


Vytváření entit pomocí příkazového řádku programu AutoCAD

Kreslení hranice cesty
Kreslení hranice cesty
Vytváření entit pomocí příkazového řádku programu AutoCAD

Když se v programu AutoCAD poprvé objevil jazyk AutoLISP, byla pro vytváření entit k dispozici pouze jediná metoda, a to funkce command. Ta umožňuje programátorovi AutoLISPu, aby v kódu použil libovolný příkaz, který může být spuštěn pomocí výzvy Příkaz programu AutoCAD. Jedná se o spolehlivý způsob, který však není tak rychlý jako metody ActiveX a nenabízí takovou pružnost, jako funkce entmake.


Použití funkce pro kreslení hranice

Kreslení hranice cesty
Kreslení hranice cesty
Použití funkce pro kreslení hranice

Po posledním cvičení vypadala funkce gp:drawOutline asi takto:

;;;--------------------------------------------------------------;
;;; Funkce: gp:drawOutline ;
;;;--------------------------------------------------------------;
;;; Popis: Tato funkce nakreslí obrys ;
;;; zahradní cesty. ;
;;;--------------------------------------------------------------;
(defun gp:drawOutline ()
  (alert
    (strcat "Tato funkce nakreslí obrys křivky "
      "\na vrátí název/ukazatel na entitu křivky."
    )
  )
  ;; Nyní vrátíte apostrofový symbol. Tato funkce případně
  vrátí název entity nebo ukazatel.
  'SomeEname
)

V tomto stavu toho kód příliš mnoho nedělá. Pomocí asociovaného seznamu uloženého v proměnné gp_PathData však již máte dostatek informací pro výpočet jednotlivých bodů hranice cesty. Nyní je nutné určit, jak mají být hodnoty této proměnné do funkce gp:drawOutline.

Vzpomeňte si, že gp_PathData je lokální proměnná definovaná v rámci funkce C:GPath. V AutoLISPu jsou lokální proměnné, deklarované v jedné funkci, viditelné pro jakoukoliv jinou funkci volanou z této funkce (pro vyjasnění viz Rozdíl mezi lokálními a globálními proměnnými). Základní funkce C:GPath. Není to sice dobrý programátorský návyk, ale je možné odkazovat proměnnou gp_PathData ve funkci gp:drawOutline.

Proč? Když budou v jednom souboru definovány dvě funkce používající stejnou proměnnou (jako v předcházejících příkladech), není těžké zjistit, kde je tato proměnná definována a k čemu slouží. Pokud jsou však ony dvě funkce definovány v různých souborech (což je častý případ), bylo by nutné projít oba soubory a tak zjistit, k čemu proměnná gp_PathData slouží.

Témata v této části:

  • Předání parametrů funkcím
  • Práce s asociovanými seznamy
  • Použití úhlů a nastavení bodů
  • Kód ActiveX ve funkci gp:drawOutline
  • Ověření načtení ActiveX
  • Použití ukazatele na modelový prostor
  • Vytvoření pole bodů křivky
  • Sestavení typu variant ze seznamu bodů
  • Dokončení operace


Předání parametrů funkcím

Kreslení hranice cesty
Kreslení hranice cesty
Předání parametrů funkcím

Lepší metodou, jak převádět údaje z jedné funkce do druhé, je předat volané funkci parametry. Napíšete funkci tak, že bude očekávat zadání určitého počtu hodnot. funkce Degrees->Radians ;;; Popis: Tato funkce používá jeden parametr představující;

(defun Degrees->Radians (numberOfDegrees)
(* pi (/ numberOfDegrees 180.0)))

Když zavoláte tuto funkci, funkce předpokládá zadání číselné hodnoty. Ta je v rámci funkce Degrees->Radians deklarována jako parametr s názvem numberOfDegrees. Například:

_$ (degrees->radians 90)

1.5708

V tomto případě je parametru numberOfDegrees přiřazena hodnota 90.

Předat můžete funkci také proměnnou. Například uvažujme, že máte proměnnou s názvem aDegreeValue obsahující hodnotu 90. Následující příkaz nastaví hodnotu proměnné aDegreeValue a předá tuto proměnnou funkci Degrees->Radians:

_$ (setq aDegreeValue 90)

90
_$ (degrees->radians aDegreeValue)

1.5708


Práce s asociovanými seznamy

Kreslení hranice cesty
Kreslení hranice cesty
Práce s asociovanými seznamy

Asociovaný seznam uložený v proměnné gp_PathData můžete předat funkci gp:drawOutline tím, že vyvoláte funkci takto:

(gp:drawOutline gp_PathData)

Je to jednoduché, ale je také třeba, abyste věděli, jakým způsobem se mají zpracovat informace uložené v asociovaném seznamu. Funkce VLISPu Inspektor vám pomůže určit, co máte dělat.

Jak použít funkci VLISPu Inspektor k analýze asociovaného seznamu
  1. Načtěte kód, který se nachází v okně textového editoru.
  2. Na výzvu konzole zadejte následující výraz:
    3. (setq BoundaryData (gp:getPointInput))

    VLISP uloží zadané informace do proměnné s názvem BoundaryData.

  3. Zodpovězte výzvy zadáním počátečního bodu, koncového bodu a poloviční šířky.
  4. Vyberte poklepáním název proměnné BoundaryData v okně konzole.
  5. Z nabídky VLISPu vyberte položky Zobrazit [image] Inspektor.

    6. VLISP zobrazí okno podobné tomuto:

    Okno Inspektor zobrazuje každý dílčí seznam v rámci proměnné BoundaryData.

  6. Na výzvu konzole VLISPu zadejte:
    7. (assoc 50 BoundaryData)

    Funkce assoc vrací položku v asociovaném seznamu určenou daným klíčem. V tomto příkladu je zadaná hodnota 50; ta je asociovaná s úhlem zahradní cesty (viz Praktické použití asociovaných seznamů s informacemi o zobrazení párů klíčových hodnot definovaných pro tuto aplikaci).

  7. Na výzvu konzole VLISPu zadejte:
    8. (cdr(assoc 50 BoundaryData))

    Funkce cdr vrací druhý prvek a veškeré zbývající prvky ze seznamu. V tomto příkladu načte funkce cdr hodnotu úhlu, což je druhý a poslední prvek v údaji vráceném funkcí assoc.

    V tomto okamžiku byste již měli rozumět následujícímu kódu:

      (setq PathAngle (cdr (assoc 50 BoundaryData))
            Width (cdr (assoc 40 BoundaryData))
            HalfWidth (/ Width 2.00)
            StartPt (cdr (assoc 10 BoundaryData))
            PathLength (cdr (assoc 41 BoundaryData))


Použití úhlů a nastavení bodů

Kreslení hranice cesty
Kreslení hranice cesty
Použití úhlů a nastavení bodů

Zbývá vysvětlit několik dalších věcí. Nejprve je třeba vyřešit, jak nakreslit cestu pod libovolným úhlem zadaným uživatelem. Pomocí funkce gp:getPointInput můžete snadno stanovit primární úhel cesty. K nakreslení cesty pak potřebujete pár dalších vektorů kolmých k primárnímu úhlu.

Zde nám bude užitečná funkce Degrees->Radians. Následující část kódu demonstruje nastavení dvou kolmých vektorů pomocí proměnné PathAngle jako argument předaný funkci Degrees‑>Radians:

(setq angp90 (+ PathAngle (Degrees->Radians 90))
      angm90 (- PathAngle (Degrees->Radians 90)))

S údaji, které nyní máte k dispozici, můžete zadat čtyři rohové body cesty pomocí funkce polar:

(setq p1 (polar StartPt angm90 HalfWidth)
      p2 (polar p1 PathAngle PathLength)
      p3 (polar p2 angp90 Width)
      p4 (polar p3 (+ PathAngle (Degrees->Radians 180))

Funkce polar vrací 3D bod nacházející se pod daným úhlem a v dané vzdálenosti od určitého bodu. Například polohu bodu polar určí funkce p2 promítnutím bodu p1 na vzdálenost PathLength ve směru vektoru orientovaného pod úhlem PathAngle, měřeným proti směru pohybu hodinových ručiček od osy X.


Kód ActiveX ve funkci gp:drawOutline

Kreslení hranice cesty
Kreslení hranice cesty
Kód ActiveX ve funkci gp:drawOutline

Funkce gp:drawOutline využívá volání prvku ActiveX při zobrazení hraniční křivky cesty v programu AutoCAD. V následujícím kódu je prvek ActiveX použit ke kreslení hranice:

;; Přidat křivku do modelového prostoru pomocí technologie ActiveX.
(setq pline (vla-addLightweightPolyline
*ModelSpace*; Globální definice pro modelový prostor
VLADataPts ; vrcholy hranic cesty
) ;_ end of vla-addLightweightPolyline
 ) ;_ end of setq
(vla-put-closed pline T)

Co znamená tento kód? Nejvíc informací o metodách a vlastnostech dostupných klientům ActiveX (jakým je i vaše aplikace pro kreslení zahradní cesty) naleznete v ActiveX and VBA Reference. Část “Working with ActiveX” dokumentace AutoLISP Developer’s Guide vysvětluje, jak přeložit syntaxi VBA™ do volání ActiveX v syntaxi ActiveX and VBA Reference AutoLISPu.

V tuto chvíli však bude stačit, když si pozorně prohlédnete strukturu dvou volání vla- v minulém příkladu. Názvy všech funkcí ActiveX v AutoLISPu, které lze použít u programu AutoCAD začínají předponou vla-. Například addLightweightPolyline je název metody ActiveX a vla-addLightweightPolyline je funkce AutoLISPu vyvolávající tuto metodu. Volání vla-put-closed aktualizuje vlastnost uzavření objektu pline, což je křivka nakreslená funkcí vla‑addLightweightPolyline.

Pro objekty Automation, které hrají roli ve volání prvků ActiveX AutoLISPu, platí následující obecná pravidla:

  • První argument volání metody vla-put, vla-get, nebo vla- je objekt, který je upravován nebo dotazován, například, *ModelSpace* ve volání první funkce a pline ve volání druhé funkce.
  • Návratová hodnota volání metody vla- je VLA-object, který může být použit v následujících voláních. Například metoda vla-addLightweightPolyline získá návratový objekt pline, který je použit ve volání dalšího prvku ActiveX.
  • Model objektů ActiveX je strukturován hierarchicky. Objekty jsou převáděny z objektu aplikace od nejvyšší úrovně k jednotlivým výkresovým primitivům (křivkám a kružnicím). To znamená, že funkce gp:drawOutline není dosud dokončena, protože objekt *ModelSpace* musí být nejdříve zpřístupněn přes kořenový objekt aplikace.


Ověření načtení ActiveX

Kreslení hranice cesty
Kreslení hranice cesty
Ověření načtení ActiveX

Funkčnost prvků ActiveX není automaticky zapnuta ani při spuštění programu AutoCAD ani VLISPu, proto je třeba zajistit, aby byl prvek ActiveX načten. K tomu slouží volání následující funkce:

(vl-load-com)

Pokud podpora ActiveX není dostupná, spuštění funkce vl-load-com provede inicializaci prostředí ActiveX AutoLISPu. V případě, že je prostředí ActiveX již načteno, funkce vl-load-com neprovede nic.


Použití ukazatele na modelový prostor

Kreslení hranice cesty
Kreslení hranice cesty
Použití ukazatele na modelový prostor

Při přidávání entit pomocí funkcí ActiveX je nutné určit, kam mají být nové entity vloženy (modelový nebo výkresový prostor). (V terminologii ActiveX jsou entity objects, ale v tomto cvičení budeme i nadále používat pojem entita.) Chcete-li sdělit programu AutoCAD, do kterého prostoru budou nové entity umístěny, je nutné použít ukazatel na daný prostor. Naneštěstí není použití ukazatele na modelový prostor příliš snadná jednorázová funkce. Následující ukázka kódu ilustruje celou operaci:

(vla-get-ModelSpace (vla-get-ActiveDocument
  (vlax-get-Acad-Object)

Postupujme směrem zevnitř kódu: funkce vlax-get-Acad-Object načte ukazatel do programu AutoCAD. Tento ukazatel je předán funkci vla‑get‑ActiveDocument, která načte ukazatel do aktivního výkresu (dokumentu) v rámci programu AutoCAD. Ukazatel na aktivní dokument je potom předán funkci vla‑get‑ModelSpace, která načte ukazatel do modelového prostoru aktuálního výkresu.

Jak vidíte, nejedná se o výraz, který byste chtěli psát znovu a znovu. Podívejte se, jak vypadá celý kód pro vložení křivky do modelového prostoru křivky pomocí ActiveX:

(setq pline (vla-addLightweightPolyline
               (vla-get-ModelSpace
                 (vla-get-ActiveDocument
                    (vlax-get-Acad-Object)
                 )
               )
               VLADataPts)
)
(vla-put-closed pline T)

Funkce je zcela jistě hůře pochopitelná. Kromě toho se v každém výrazu kódu, kde dochází k vytvoření entity, zopakuje stejná skupina vnořených funkcí. Nyní uvidíte vynikající příklad použití globálních proměnných. Aplikace zahradní cesty může do modelového prostoru vkládat množství entit (vzpomeňte si na všechny dlaždice v rámci cesty), proto nastavte globální proměnnou, do níž se ukazatel do modelového prostoru uloží:

(setq *ModelSpace* (vla-get-ModelSpace (vla-get-ActiveDocument
                 (vlax-get-Acad-Object))))

Proměnnou *ModelSpace* můžete použít při každém volání funkce ActiveX pro tvorbu entit. Jediným slabým místem tohoto schématu je to, že proměnná *ModelSpace* musí být připravena k činnosti již před otevřením výkresu. Z tohoto důvodu bude funkce setq, definující tuto proměnnou, volána při načtení aplikace, okamžitě po volání funkce vl-load-com. Tato volání tedy proběhnou před zpracováním všech příkazů defun v souboru programu. Výsledkem bude, že budou spuštěna při načtení souboru.


Vytvoření pole bodů křivky

Kreslení hranice cesty
Kreslení hranice cesty
Vytvoření pole bodů křivky

Posledním úkolem je převod jednotlivých proměnných bodů (p1, p2, p3, a p4) do formátu vyžadovaného funkcí vla‑addLightweightpolyline. Nejprve se podíváme do nápovědy.

Jak získat informace o funkci
  1. Stiskněte tlačítko Nápověda v panelu nástrojů VLISPu.
  2. V dialogu Zadejte název položky zadejte vla‑addLightweightpolyline a stiskněte tlačítko OK. (Nápověda nerozlišuje velká a malá písmena, takže nemusíte psát název funkce velkými písmeny.)

Nápověda říká, že funkce AddLightWeightPolyline yžaduje zadání vrcholů křivky ve formě pole reálných čísel (typu double) ve formě typu variant. Nápověda popisuje tento parametr takto:

Pole 2D souřadnic GSS určující vrcholy křivky. Pro vytvoření odlehčené křivky je třeba nejméně dvou bodů (čtyř prvků). Velikost pole musí být násobek 2.

Typ variant je prvek ActiveX sloužící jako kontejner pro různé datové typy. Typy variant mohou obsahovat řetězce, celá čísla a pole. Typ variant ukládá data spolu s identifikujícími informacemi.

Zatím máte čtyři body ve formátu (x, y, z). TÚkolem bude převést tyto čtyři body na seznam vypadající následovně:

(x1 y1 x2 y2 x3 y3 x4 y4)

Funkce append přijme více seznamů a sloučí je. Chcete-li vytvořit seznam čtyř bodů ve správném formátu pro funkci ActiveX, můžete použít následující výraz:

(setq polypoints (append (3dPoint->2dPoint p1)
                              (3dBod->2dBod p2)
                              (3dBod->2dBod p3)
                              (3dBod->2dBod p4)))

Psaní čtyř funkcí 3dPoint‑>2dPoint je poněkud těžkopádné. Osu můžete posunout pomocí jezdců posuvníků. Při výběru spustí mapcar funkci na jednotlivých prvcích v jednom nebo více seznamech a apply předá seznam argumentů zadané funkci. Výsledný kód by měl vypadat následovně:

(setq polypoints (apply 'append (mapcar '3dPoint->2dPoint
(list p1 p2 p3 p4))))

Před voláním funkce mapcar vypadal seznam bodů takto:

((x1 y1 z1) (x2 y2 z2) (x3 y3 z3) (x4 y4 z4))

Po použití funkce mapcar máte následující seznam bodů:

((x1 y1) (x2 y2) (x3 y3) (x4 y4))

A konečně když použijete funkci append na seznam vrácený funkcí mapcar, dostanete toto:

(x1 y1 x2 y2 x3 y3 x4 y4)


Sestavení typu variant ze seznamu bodů

Kreslení hranice cesty
Kreslení hranice cesty
Sestavení typu variant ze seznamu bodů

Doposud jsou data v proměnné bodů uvedena ve formátu seznamu vhodném pro mnoho volání AutoLISPu. Při zadání údajů do funkce ActiveX ve formě vstupního parametru je třeba použít typ variant pole reálných čísel (typu double). Převod ze seznamu na typ variant můžete provést pomocí další pomůcky:

(defun gp:list->variantArray (ptsList / arraySpace sArray)
  ; alokuje prostor pro pole 2d bodů uložených jako reálná čísla (typ double)
  (setq arraySpace (vlax-make-safearray
              vlax-vbdouble ; typ prvku
              (cons 0
                    (- (length ptsList) 1)
                    ) ; rozměry pole
              )
)
  (setq sArray (vlax-safearray-fill arraySpace ptsList))
  ; vrací typ variant pole
  (vlax-make-variant sArray)
  )

Ve funkci gp:list->variantArray se provádí následující operace:

  • Funkce vlax‑make-safearray je volána, aby alokovala pole reálných čísel typu double (vlax-vbdouble). Funkce vlax‑make‑safearray vyžaduje zadání dolních a horních indexů hranic pole. Ve funkci gp:list->variantArray určuje volání vlax‑make‑safearray počáteční index 0 a nastavuje horní mez na hodnotu o jednu menší než je počet prvků předaných této funkci (ptsList).
  • Funkce vlax-safearray-fill je volána, aby naplnila pole hodnotami prvků v seznamu bodů.
  • Funkce vlax-make-variant je volána, aby převedla pole na typ variant. Poslední volání funkce gp:list->variantArray předá návratovou hodnotu volající funkci.

Následuje příklad volání funkce, která pomocí gp:list‑>variantArray převede seznam na typ variant pole reálných čísel typu double:

; převod dat ze seznamu na typ variant
(setq VLADataPts (gp:list->variantArray polypoints))


Dokončení operace

Kreslení hranice cesty
Kreslení hranice cesty
Dokončení operace

Nyní máte celý kód, který potřebujete k nakreslení obrysu zahradní cesty.

Jak provést aktualizaci kódu
  1. Nahraďte starý kód funkce gp:drawOutline novým:
    2. ;;;---------------------------------------------------------------
    ;;; Funkce: gp:drawOutline
    ;;;---------------------------------------------------------------
    ;;; Popis: This function will draw the outline of the garden
    ;;; zahradní cesty.
    ;;;---------------------------------------------------------------
    ;;; Poznámka: Není provedena kontrola chyb a platnosti parametru
    ;;; BoundaryData. Posloupnost položek v rámci tohoto parametru
    ;;; nehraje roli, ale předpokládá se, že všechny dílčí seznamy
    ;;; jsou přítomny a obsahují platná data.
    ;;; --------------------------------------------------------------
    (defun gp:drawOutline (BoundaryData / VLADataPts PathAngle
           Width HalfWidth StartPt PathLength
           angm90 angp90 p1 p2
           p3 p4 polypoints pline
          )
      ;; získá hodnoty ze seznamu BoundaryData
      (setq PathAngle (cdr (assoc 50 BoundaryData))
    Width (cdr (assoc 40 BoundaryData))
    HalfWidth (/ Width 2.00)
    StartPt (cdr (assoc 10 BoundaryData))
    PathLength (cdr (assoc 41 BoundaryData))
    angp90 (+ PathAngle (Degrees->Radians 90))
    angm90 (- PathAngle (Degrees->Radians 90))
    p1 (polar StartPt angm90 HalfWidth)
    p2 (polar p1 PathAngle PathLength)
    p3 (polar p2 angp90 Width)
    p4 (polar p3 (+ PathAngle (Degrees->Radians 180)) PathLength)
    polypoints (apply 'append
      (mapcar '3dPoint->2dPoint (list p1 p2 p3 p4))
       )
      )
      ;; ***** převod dat *****
      ;; Všimněte si zadání bodů ve formátu AutoLISPu, které je tvořeno
      ;; seznamem 4 rohových bodů zahradní cesty.
      ;; Proměnnou je nutné převést do formy vstupního parametru
      ;; přijatelného pro volání ActiveX.
      (setq VLADataPts (gp:list->variantArray polypoints))
      ;; Přidat křivku do modelového prostoru pomocí technologie ActiveX.
      (setq pline (vla-addLightweightPolyline
    *ModelSpace*; Globální definice pro modelový prostor
    VLADataPts
     ) ;_ end of vla-addLightweightPolyline
      ) ;_ end of setq
      (vla-put-closed pline T)
      ;; Vrací název objektu ActiveX pro obrysovou křivku
      ;; Návratová hodnota by měla vypadat asi následovně:
      ;; #<VLA-OBJECT IAcadLWPolyline 02351a34>
      pline
    ) ;_ end of defun

    Všimněte si, že funkce gp:drawOutline nyní vrací proměnnou pline, nikoliv apostrofový symbol 'SomeEname použitý v zástupné verzi funkce.

  2. Zformátujte kód, který jste právě napsali, tak, že jej vyberte a stiskněte tlačítko Zformátovat výběr v panelu nástrojů VLISPu.
  3. Zapněte použití objektů ActiveX a přidejte do kódu přiřazení globální proměnné pro ukazatel na modelový prostor (viz výše). Posuňte se do horní části okna textového editoru a vložte před první funkci defun:
    4. ;;;--------------------------------------------------------------
    ;;; První krok - načtení ActiveX. Pokud již podpora ActiveX
    ;;; v dokumentu existuje (může nastat při načtení nástrojů Bonus do
    ;;; programu AutoCAD), nic se nestane. V opačném případě se načte
    ;;; podpora ActiveX.
    ;;;---------------------------------------------------------------
    (vl-load-com)
    ;;; Ve cvičení 4 je zařazen do utils.lsp následující kód s komentářem
    ;;;---------------------------------------------------------------
    ;;; Pro funkce ActiveX potřebujeme definovat globální proměnnou
    ;;; která "ukazuje" na modelový prostor aktivního výkresu. Tato
    proměnná s názvem *ModelSpace* bude vytvořena v okamžiku načtení.
    ;;;---------------------------------------------------------------
    (setq *ModelSpace*
    (vla-get-ModelSpace
         (vla-get-ActiveDocument (vlax-get-acad-object))
    ) ;_ end of vla-get-ModelSpace
    ) ;_ end of setq

    Všimněte si, jak v tomto kódu není použit žádný výraz defun. Díky tomu VLISP automaticky provede kód v okamžiku načtení souboru.

  4. Vyhledejte ve funkci C:GPath následující řádek:
    5. (setq PolylineName (gp:drawOutline))

    Změňte jeho znění následovně:

    (setq PolylineName (gp:drawOutline gp_PathData))

    Funkce gp:drawOutline nyní očekává zadání parametru (seznamu obsahujícího údaje hraniční křivky) a tím je tento požadavek splněn.

  5. Přidejte na konec souboru gpmain.lsp funkci Sestavení typu variant ze seznamu bodůgp:list->variantArray uvedenou v tématu .

    6. Zkuste načíst a spustit upravený program. VLISP před skončením přebere řízení od programu AutoCAD takže až se přepnete do VLISPu, vraťte se do okna programu AutoCAD. Pokud program proběhl správně, měli byste vidět nakreslenou hranici zahradní cesty. V případě, že naleznete nějaké chyby, odlaďte je a zkuste spustit opravený program znovu.


Shrnutí cvičení 3

Kreslení hranice cesty
Kreslení hranice cesty
Shrnutí cvičení 3

V tomto cvičení jste:

  • napsali pomůcky s opakovaným použitím v jiných aplikacích,
  • doplnili program o logické postupy tvorby entit,
  • se dozvěděli o používání funkcí ActiveX,
  • poznali použití asociovaných seznamů,
  • upravili svůj program tak, aby nakreslil hranici zahradní cesty.

Pokud vám cokoliv z tohoto cvičení není zcela jasné, doporučujeme si jej projít ještě jednou a teprve potom pokračovat cvičením 4. (Pokud se tak rozhodnete, zkopírujte si dokončený kód z adresáře Lesson2, abyste začali cvičení ve správné fázi tvorby kódu.) Pokud vše ostatní zklame, můžete si kdykoliv zkopírovat původní kód z adresáře Tutorial\VisualLISP\Lesson3.


Tvorba projektu a přidání rozhraní

V této lekci provedete dva hlavní úkoly: vytvoříte projekt Visual LISPu® a přidáte k aplikaci rozhraní s dialogy. V postupu rozdělíte jeden soubor AutoLISPu®, se kterým pracujete (gpmain.lsp), do několika malých souborů a posílíte tak modularitu kódu.

Počínaje tímto cvičením budete v textu mimo nových témat nacházet více obecných popisů úkolů, které bude třeba udělat. Ukázky kódu budou kvůli úspoře místa dokumentovány jen minimálně.

Témata v této části:

  • Rozdělení kódu na více modulů
  • Použití projektů Visual LISPu
  • Přidání dialogového rozhraní
  • Interakce vytvořeného dialogu a AutoLISPu
  • Nabídnutí volby typu čáry hraniční křivky
  • Údržba kódu
  • Spuštění aplikace
  • Shrnutí cvičení 4


Rozdělení kódu na více modulů

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Rozdělení kódu na více modulů

Výsledkem práce v Lekci 3 bude značné zvětšení souboru gpmain.lsp. Pro VLISP to sice neznamená žádný problém, ale údržba kódu bude snadnější, pokud celý soubor rozdělíte na několik menších souborů obsahujících lokálně příbuzné funkce. Snadnější bude i odladění chyb v kódu. Pokud například budete mít jeden rozsáhlý soubor se 150 funkcemi, může být nalezení jedné chybějící závorky problém.

V rámci těchto cvičení budou soubory uspořádány následovně:

Uspořádání souborů v rámci cvičení
Název souboru | Obsah
gp-io.lsp | Veškeré vstupní a výstupní funkce, například zadání uživatele. Dále obsahuje kód AutoLISPu, potřebný k tvorbě dialogového rozhraní, které se chystáte použít.
utils.lsp | Všechny obecné funkce s opakovaným použitím v jiných projektech. Dále obsahuje inicializace při načítání.
gpdraw.lsp | Veškeré kreslící procedury — kód, který vytváří entity AutoCAD.
gpmain.lsp | Základní funkce C:GPath.
Jak rozdělit soubor gpmain.lsp na 4 soubory
  1. Vytvořte nový soubor, potom vyjměte a vložte do nového souboru následující funkce ze souboru gpmain.lsp:
    • gp:getPointInput
    • gp:getDialogInput

    Uložte soubor do pracovního adresáře pod názvem gp-io.lsp.

  2. Vytvořte nový soubor, potom vyjměte a vložte do nového souboru následující funkce ze souboru gpmain.lsp:
    • funkce Degrees->Radians
    • 3dBod->2dBod
    • (gp:list->variantArray poly2Dpoints)

    Na začátek souboru také vložte řádky kódy pro vytvoření funkce ActiveX (vl-load-com) a proveďte přiřazení globální proměnné (*ModelSpace*).

    příkaz Uložit jako (nabídka Soubor)

  3. Vytvořte nový soubor, potom vyjměte a vložte do nového souboru následující funkce ze souboru gpmain.lsp:
    • gp:drawOutline

    Uložte soubor pod názvem gpdraw.lsp.

  4. Po zápisu kódu ze souboru gpmain.lsp jej uložte a zkontrolujte. V souboru by měla zůstat pouze původní funkce C:GPath.

Na ploše VLISPu je nyní poněkud plno. Všechna okna v rámci VLISPu můžete minimalizovat, přičemž i nadále zůstanou dostupná. Chcete-li vybrat jedno z oken ze seznamu, stiskněte tlačítko Vyberte okno v panelu nástrojů nebo z nabídky Okno VLISPu vyberte okno, které chcete zobrazit.


Použití projektů Visual LISPu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Použití projektů Visual LISPu

Projekt VLISPu nabízí pohodlný způsob správy jednotlivých souborů tvořících aplikaci. Pomocí této funkce můžete otevřít jeden projektový soubor místo otevírání všech souborů LISPu dané aplikace. Jakmile je projekt otevřen, můžete se přesunout do jeho dílčích souborů pouhým poklepáním.

Jak vytvořit projekt VLISPu
  1. Z nabídky VLISPu vyberte položky Projekt [image] Nový projekt.
  2. Uložte soubor do adresáře Lesson4 pod názvem gpath.prj.

    3. Po uložení souboru zobrazí VLISP dialog Vlastnosti projektu.

  3. Stiskněte tlačítko Označit (odznačit) vše v levé části dialogu Vlastnosti projektu.
  4. Stiskněte tlačítko se šipkou doprava. Tím se všechny vybrané soubory přidají do projektu.

    5. V dialogu Vlastnosti projektu obsahuje seznam vlevo všechny soubory LISPu nacházející se ve stejném adresáři jako projektový soubor a nejsou vloženy v tomto projektu. V pravém seznamu jsou soubory tvořící projekt. Když přidáte vybrané soubory do projektu, jejich názvy se přesunou z levého seznamu do pravého.

  5. V seznamu na pravé straně dialogu vybrete položku gpmain a potom klepněte na tlačítko Dolní. Soubor se přesune na konec seznamu.

    6. VLISP lnačítá projektové soubory v pořadí, v jakém jsou uvedeny v seznamu. Protože výzva oznamující uživatelům název příkazu je umístěna na konci souboru gpmain.lsp, je nutné přesunout tento soubor na konec seznamu. Když se tento soubor načte jako poslední, uživatelům se zobrazí příslušná výzva. Soubor utils.lsp by měl být načten jako první, jelikož obsahuje inicializační kód aplikace. Proto vyberte položku utils v seznamu dialogu a klepněte na tlačítko Horní.

  6. Stiskněte tlačítko OK.

VLISP umístí na pracovní plochu VLISPu malé okno projektu. V tomto okně se zobrazí soubory daného projektu. Poklepáním na soubor můžete tento soubor otevřít v aktivním okně textového editoru VLISPu (pokud již není otevřen).


Přidání dialogového rozhraní

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Přidání dialogového rozhraní

V další části tohoto cvičení přidáte do aplikace zahradní cesty dialogové rozhraní. Přitom budete pracovat s jazykem DCL (Dialog Control Language).

Aktuálně funkce gpath přijme pouze vstup z příkazového řádku. Vložili jste zástupnou funkci(gp:getDialogInput) se záměrem přidání rozhraní s dialogy. Nyní je čas přidat toto rozhraní do aplikace.

Vytvoření funkčního dialogového rozhraní se skládá ze dvou kroků:

  • Definování vzhledu a obsahu použitých dialogů.
  • Napsání obslužného programového kódu určujícího chování dialogů.

Popis a formát dialogu je definován v souborusoubor dcl. V průvodci AutoLISP Developer’s Guide je DCL popsáno v kapitole 11 “Tvorba dialogů”, kapitole 12 “Správa dialogů” a kapitole 13, “Reference programovatelného dialogu”.

Kód programu spouštějící výchozí nastavení a reagující na vstup uživatele bude přidán k funkci gp:getDialogInput.

Témata v této části:

  • Definování dialogů pomocí jazyka DCL
  • Uložení souboru DCL
  • Zobrazení náhledu vytvořeného dialogu


Definování dialogů pomocí jazyka DCL

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Definování dialogů pomocí jazyka DCL

Nejdříve se podívejte na hotový dialog, který se chystáte vytvořit.

Dialog obsahuje následující prvky:

  • Dvě skupiny voleb.

    • Jedna skupina voleb určuje styl hraniční křivky, druhá určuje použitý způsob vytváření entit (ActiveX, entmake nebo příkazová). Vždy je možné vybrat pouze jednu volbu v rámci skupiny.

  • Textová pole pro zadání poloměru dlaždic a vzdálenosti mezi dlaždicemi.
  • Standardní tlačítka OK a Storno (Cancel).

Komponenty dialogu se v DCL nazývají dlaždice. Napsání celého kódu pro dialog může vypadat jako složitý úkon. Trik spočívá v tom, že si ujasníte své požadavky, rozdělíte je na několik částí a potom pro každou část napíšete příslušný kód.

Jak definovat dialog
  1. Otevřete v okně textového editoru VLISPu nový soubor.
  2. V novém souboru zadejte následující příkaz:
    3. label = "Definování dlaždic zahradní cesty";

    Tento příkaz DCL definuje záhlaví okna dialogu.

  3. Definujte volby pro zadání typu křivky pomocí následujícího kódu:
    4. : boxed_radio_column { // definuje oblasti voleb
      label = "Typ hraniční křivky";
      : radio_button { // definuje volbu odlehčené
        label = "&Odlehčená";
        key = "gp_lw";
        value = "1";
       }
    : radio_button { // definuje starý typ volby klasické křivky
      label = "&Původní";
      key = "gp_hw";
     }
    }

    Funkce boxed_radio_column definuje hranice pole a umožňuje zadání popisu pro skupinu voleb. V rámci ohraničení pole pak zadáte volby pomocí příkazů radio_button. Každá volba vyžaduje zadání popisu a klíč. Klíč je název, podle kterého může kód AutoLISPu odkazovat na tlačítko.

    Povšimněte si, že přepínací tlačítko s názvem „odlehčené“ má přiřazenou hodnotu 1. Hodnota 1 (řetězec, nikoliv celé číslo) označuje výchozí volbu ve skupině voleb. Jinými slovy, při zobrazení dialogu bude vybrána tato volba. Dále si povšimněte, že v souborech DCL jsou komentáře uvozeny dvěma znaky lomítka, nikoliv středníky jako v AutoLISPu.

  4. Definujte volby pro výběr metody tvorby objektů pomocí následujícího kódu:
    5. : boxed_radio_column { // definuje oblasti voleb
      label = "Metoda tvorby dlaždic";
      : radio_button { // definuje volby ActiveX
        label = "Pomocí &ActiveX";
        key = "gp_actx";
        value = "1";
       }
    : radio_button { // definuje (entmake) volbu
      label = "Pomocí &Entmake";
      key = "gp_emake";
     }
    : radio_button { // definuje (command) volbu
      label = "Pomocí &Command";
      key = "gp_cmd";
     }
    }
  5. Pomocí následujícího kódu definujte textová pole, do nichž uživatelé budou moci zadat počet dlaždic a vzdálenost mezi nimi:
    6. : edit_box { // definuje textové pole Poloměr dlaždic
      label = "&Poloměr dlaždice";
      key = "gp_trad";
      edit_width = 6;
    }
    : edit_box { // definuje textové pole Vzdálenost mezi dlaždicemi
      label = "Vzdálenost mezi dlaždicemi";
      key = "gp_spac";
      edit_width = 6;
    }

    Povšimněte si, že tato definice nenastavuje pro vytvářená textová pole žádné počáteční hodnoty. Výchozí hodnoty pro každé textové pole totiž nastavíte v programu AutoLISPu.

  6. Pomocí následujícího kódu definujte tlačítka OK a Storno:
    7. : row { // definuje řádek pro tlačítka OK/Storno
      : spacer { width = 1; }
      : button { // definuje tlačítko OK
        label = "OK";
        is_default = true;
        key = "accept";
        width = 8;
        fixed_width = true;
      }
      : button { // definuje tlačítko Storno
        label = "Storno";
        is_cancel = true;
        key = "cancel";
        width = 8;
        fixed_width = true;
      }
      : spacer { width = 1;}
    }

    Obě tlačítka jsou definována v rámci stejného řádku, proto jsou zarovnána vedle sebe.

  7. Zobrazte si začátek okna textového editoru a vložte na první řádek svého souboru DCL následující příkaz:
    8. gp_mainDialog : dialog {
  8. Dialog vyžaduje použití ukončovací závorky, proto se přesuňte na konec souboru a vložte ji na poslední řádek kódu DCL:
    9. }


Uložení souboru DCL

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Uložení souboru DCL

Před uložením souboru s DCL, nezapomeňte, že produkt AutoCAD® musí být schopen vyhledat soubor DCL během spouštění. Z tohoto důvodu musí být soubor umístěn v jednom z podpůrných adresářů programu AutoCAD. (Pokud si nejste jisti umístěním těchto adresářů, vyberte v nabídce Nástroje [image] Možnosti nabídky programu AutoCAD a na kartě Soubory si prohlédněte cesty v rámci položky Cesta k podpůrným souborům.)

Nyní můžete soubor uložit do adresáře AutoCAD Support.

Jak uložit soubor DCL
  1. Z nabídky VLISPu Soubor vyberte položku Uložit jako.
  2. V poli Uložit jako typ dialogu Uložit jako vyberte z nabídky položku DCL zdrojové soubory.
  3. Změňte cestu Uložit do na <AutoCAD adresář>\Support.
  4. Zadejte název souboru gpdialog.dcl.
  5. Stiskněte tlačítko Uložit.

Povšimněte si, že VLISP změní po uložení souboru barevné schéma syntaxe. VLISP je navržen tak, aby rozpoznal soubory DCL a zvýraznil odlišné typy syntaktických prvků.


Zobrazení náhledu vytvořeného dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Zobrazení náhledu vytvořeného dialogu

VLISP nabízí funkci náhledu, pomocí níž si můžete prohlédnout výsledek kódu DCL.

Jak zobrazit náhled dialogu definovaného pomocí DCL
  1. Z nabídky VLISPu vyberte položky Nástroje [image] Nástroje pro rozhraní [image] Náhled DCL v editoru.
  2. Na výzvu pro zadání názvu dialogu stiskněte tlačítko OK.

    3. V tomto případě je pomocí jazyka DCL definován pouze jeden dialog, takže nemáte možnost výběru. Při tvorbě rozsáhlejších aplikací však budete často mít soubory DCL obsahující více dialogů. V takovém případě pak vyberete ten, jehož náhled chcete zobrazit.

  3. Pokud se dialog zobrazí v pořádku, uzavřete jej libovolným tlačítkem.

VLISP předá při zobrazení hotového dialogu řízení AutoCAD. Pokud AutoCAD nalezne nějaké syntaktické chyby, zobrazí jedno nebo více oken s chybovým hlášením.

Pokud AutoCAD nahlásí chyby DCL a nebudete schopni je opravit, zkopírujte soubor gpdialog.dcl v adresáři Tutorial\VisualLISP\Lesson4 a uložte jej do adresáře Support.


Interakce vytvořeného dialogu a AutoLISPu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Interakce vytvořeného dialogu a AutoLISPu

Nyní potřebujete naprogramovat svou funkci AutoLISPu tak, aby s dialogem spolupracovala. Zástupná funkce gp:getDialogInput, je tam, kde bude tato aktivita provedena. Tato funkce je nyní v souboru gp-io.lsp, který jste dříve extrahovali ze souboru gpmain.lsp.

Vývoj dialogového rozhraní vám může zpočátku připadat poněkud nepřehledný. Je při něm nutno vše dopředu plánovat a pokládat si otázky typu:

  • Je nutno nastavit v dialogu výchozí hodnoty?
  • Co se stane, když uživatel stiskne tlačítko, nebo zadá hodnotu?
  • Co se stane, když uživatel stiskne tlačítko Storno?
  • Co se má stát, když chybí soubor dialogu (.Soubor dcl) chybí, co se más stát?

Témata v této části:

  • Nastavení hodnot dialogu
  • Načtení souboru dialogu
  • Načtení určitého dialogu do paměti
  • Inicializace počátečních hodnot dialogu
  • Přiřazení akcí k elementům
  • Spuštění dialogu
  • Uvolnění dialogu z paměti
  • Určení dalšího postupu
  • Dokončení kódu dialogu
  • Aktualizace zástupné funkce


Nastavení hodnot dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Nastavení hodnot dialogu

Až spustíte hotovou aplikaci zahradní cesty, povšimněte si, že vytvořený dialog se vždy zobrazí s výchozí metodou ActiveX a výchozím typem křivky Odlehčená. U výchozí velikosti dlaždic je situace zajímavější - hodnoty se mění podle šířky cesty. Následující úsek kódu ilustruje nastavení výchozích hodnot zobrazených v dialogu:

(setq objectCreateMethod "ACTIVEX"
        plineStyle "LIGHT"
        tilerad (/ pathWidth 15.0)
        tilespace (/ tilerad 5.0)
        dialogLoaded T
        dialogShow T
  ) ;_ konec setq

Nyní se nastarejte o to, k jakému účelu proměnné dialogLoaded a dialogShow slouží. Povíme si o něm až v následujících dvou částech.


Načtení souboru dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Načtení souboru dialogu

Váš program muí nejprve načíst soubor DCL pomocí funkce load_dialog. Tato funkce vyhledá soubory dialogů na základě zadané prohledávací cesty podpůrných souborů programu AutoCAD (pokud ovšem nezadáte celý název cesty).

U každé funkce load_dialog by měla být později v kódu odpovídající funkce unload_dialog. Ukážeme si to za malou chvíli. Prozatím se podívejte na to, jak bude váš dialog načten:

;; Načte dialog.. Nastaví kontrolu chyb (zajistí, že
;; dialog bude před pokračováním načten
(if (= -1 (setq dcl_id (load_dialog "gpdialog.dcl")))
    (progn
      ;; Je tu problém - zobrazí hlášení a nastaví
      ;; proměnnou dialogLoaded flag na hodnotu nil
      (princ "\nNelze načíst gpdialog.dcl")
      (setq dialogLoaded nil)
    ) ;_ end of progn
) ;_ konec if

Proměnná dialogLoaded indikuje, zda je dialog úspěšně načten. V kódu, v místě kde nastavujete počáteční hodnoty dialogu, nastavte funkci dialogLoaded na počáteční hodnotu T. Jak můžete vidět ve výše uvedeném úryvku kódu, funkce dialogLoaded je nastavena na nil, je-li problém s načtením.


Načtení určitého dialogu do paměti

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Načtení určitého dialogu do paměti

Jak již bylo řečeno, jeden soubor DCL může obsahovat definice více dialogů. Dalším krokem tedy bude určit, která definice dialogu má být použita. Tuto operaci demonstruje následující kód:

(if (and dialogLoaded
        (not (new_dialog "gp_mainDialog" dcl_id))
     ) ;_ konec and
    (progn
      ;; Vyskytl se problém...
      (princ "\nNelze zobrazit dialog gp_mainDialog")
      (setq dialogShow nil)
    ) ;_ end of progn
) ;_ konec if

Všimněte si, jak je použita funkce and k testování načtení dialogu a zdali bylo volání funkce new_dialog úspěšné. Jestliže je v rámci volání funkce and vyhodnoceno více výrazů, vyhodnocení následujících výrazů je ukončeno s prvním výrazem s hodnotou nil. Pokud má v takovém případě příznak funkce dialogLoaded hodnotu nil (znamená to, že funkce load v předchozí části selhala), VLISP se nepokusí provést funkci new_dialog.

Všimněte si, že kód také obsluhuje událost, že něco nebude fungovat správně se souborem DCL a nastavuje proměnnou dialogShow na hodnotu nil, když k takovému případu dojde.

Funkce new_dialog pouze načte daný dialog do paměti — nezobrazí jej. Funkce start_dialog zobrazí dialog. Spuštění dialogu, například nastavení hodnot, tvorba obrázků nebo seznamů pro seznamy a asociování akcí s určitými dlaždicemi, je nutné provést po volání funkce new_dialog a před voláním funkce start_dialog .


Inicializace počátečních hodnot dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Inicializace počátečních hodnot dialogu

Pokud při načtení dialogu vše fungovalo normálně, můžete nyní nastavit hodnoty, které se zobrazí uživateli. Úspěšné načtení je, jestliže jsou příznaky proměnných dialogLoadedadialogShow nastaveny na T (true).

Nyní nastavíte výchozí hodnoty pro poloměr dlaždic a jejich vzdálenost. Funkce set_tile přiřazuje hodnotu dlaždici. Jelikož textová pole pracují spíše s řetězci a nikoliv s čísly, je nutné použít funkci rtos (převod reálného čísla na řetězec - Real TO String) a převést proměnnou velikosti dlaždic na řetězec v desetinném formátu s přesností na 2 desetinná místa. Převod bude proveden pomocí následujícího kódu:

(if (and dialogLoaded dialogShow)
    (progn
      ;; Nastaví počáteční stav dlaždic
      (set_tile "gp_trad" (rtos tileRad 2 2))
      (set_tile "gp_spac" (rtos tileSpace 2 2))


Přiřazení akcí k elementům

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Přiřazení akcí k elementům

Definice jazyka DCL neumí nic víc, než jen vytvořit „neživý“ dialog. Tento dialog připojíte k dynamickému kódu AutoLISPu pomocí funkce action_tile, jak je uvedeno v následujícím kódu:

;; Přiřazení akcí (vyvolaných funkcí) k tlačítkům dialogu
(action_tile
  "gp_lw"
  "(setq plineStyle \"Light\")"
)
(action_tile
  "gp_hw"
  "(setq plineStyle \"Pline\")"
)
(action_tile
  "gp_actx"
  "(setq objectCreateMethod \"ActiveX\")"
)
(action_tile
  "gp_emake"
  "(setq objectCreateMethod \"Entmake\")"
)
(action_tile
  "gp_cmd"
  "(setq objectCreateMethod \"Command\")"
)
(action_tile "cancel" "(done_dialog) (setq UserClick nil)")
(action_tile
  "accept"
  (strcat "(progn (setq tileRad (atof (get_tile \"gp_trad\")))"
       "(setq tileSpace (atof (get_tile \"gp_spac\")))"
       "(done_dialog) (setq UserClick T))"
  )
)

Všimněte si všech těch uvozovek kolem kódu AutoLISPu. Při zápisu funkce AutoLISPu action_tile, váš kód vlastně říká prvku dialogu:"tady, zapamatuj si tento řetězec a až tě uživatel vybere, pošli mi jej zpět.” Řetězec (vše uvnitř uvozovek) není používán, dokud uživatel prvek nevybere. Nyní dlaždice pošle řetězec do programu AutoCAD, který jej převede na funkční kód AutoLISPu a provede jej.

Například následující výraz action_tile, který je připojen k volbě tloušťky čáry křivky:

(action_tile
   "gp_lw"
   "(setq plineStyle \"Light\")"
)

Kód přiřazuje řetězec "(setq plineStyle \"Light\")" k volbě. Když uživatel volbu vybere, řetězec je předán zpět programu AutoCAD a převeden přímo do následujícího výrazu AutoLISPu:

(setq plineStyle "Light")

Podívejte se ještě na jeden úsek kódu. Následující výraz action_tile je přiřazen k tlačítku OK:

(action_tile
    "accept"
    (strcat "(progn (setq tileRad (atof (get_tile \"gp_trad\")))"
      "(setq tileSpace (atof (get_tile \"gp_spac\")))"
      "(done_dialog) (setq UserClick T))"
)

Když uživatel stiskne tlačítko OK, celý řetězec přiřazený tomuto tlačítku je předán programu AutoCAD a převeden na následující kód AutoLISPu:

(progn
   (setq tileRad (atof (get_tile "gp_trad")))
   (setq tileSpace (atof (get_tile "gp_spac")))
   (done_dialog)
   (setq UserClick T)
)

Tento kód provádí několi věcí: Načte aktuální hodnoty z dlaždic, jejichž klíčové hodnoty jsou gp_trad (poloměr dlaždice) a gp_spac (hodnota rozteče mezi dlaždicemi). Potom funkce atof převede číselný řetězec na reálné číslo. Dialog je ukončen funkcí done_dialog a hodnota T nebo true bude přiřazena k proměnné UserClick.

Tím je přiřazení akcí k tlačítkům dokončeno. Dále je třeba nově provedená nastavení zprovoznit.


Spuštění dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Spuštění dialogu

Funkce start_dialog zobrazuje dialog a přijímá vstup uživatele. Funkce start_dialog nevyžaduje žádné argumenty.

(start_dialog)

Řízení je při spuštění funkce start_dialog. Uživatelé mohou v dialogu provádět různá nastavení až do okamžiku, kdy stisknou tlačítko OK nebo Storno.


Uvolnění dialogu z paměti

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Uvolnění dialogu z paměti

Když uživatel stiskne tlačítko OK nebo Storno, je nutné uvolnit dialog z paměti počítače. Podobně jako funkce start_dialog, je unload_dialog další jednoduchou funkcí.

(unload_dialog dcl_id)


Určení dalšího postupu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Určení dalšího postupu

Jestliže uživatel stisknul tlačítko OK, je nutné sestavit seznam obsahující hodnoty generované na základě interakce uživatele a dialogu. Tento seznam vrátí funkce gp:getDialogInput své volající funkci. V případě, že by uživatel stisknul tlačítko Storno, funkce vrací hodnotu nil:

(if UserClick ; Uživatel klepnul na tlačítko OK
  ;; Sestavení výsledných dat
  (progn
    (setq Result (list
        (cons 42 tileRad)
        (cons 43 TileSpace)
        (cons 3 objectCreateMethod)
        (cons 4 plineStyle)
        )
     )
  )
)


Dokončení kódu dialogu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Dokončení kódu dialogu

Ve výše uvedených příkladech (s několika řádky navíc) je kód, který potřebujete k dokončení funkce gp:getDialogInput.

Jak dokončit funkci gp:getDialogInput
  1. Zobrazte kopii souboru gp-io.lsp v okně textového editoru VLISPu.
  2. Odstraňte kód v příkazu gp:getDialogInput (příkaz defun gp:getDialogInput a vše po něm).
  3. Zadejte následující příkaz defun jako první řádek kódu ve funkci gp:getDialogInput:
    4. (defun gp:getDialogInput (pathWidth / dcl_id objectCreateMethod
                   plineStyle tilerad tilespace result UserClick
                   dialogLoaded dialogShow)

    Funkce očekává jeden argument (pathwidth) a vytvoří několik lokálních proměnných.

  4. Za kód přidaný v bodě 3 vložte příklady kódu z následujících částí:
    • Nastavení hodnot dialogu
    • Načtení souboru dialogu
    • Načtení určitého dialogu do paměti
    • Inicializace počátečních hodnot dialogu
    • Přiřazení akcí k elementům

    Poznámka Zadejte pouze první příklad kódu Přiřazení akcí k elementům ne části v následujcícm vysvětlení. Dále se totiž vyskytují jen opakující se úseky stejného kódu.

    • Spuštění dialogu
    • Uvolnění dialogu z paměti
    • Určení dalšího postupu
  5. Za poslední řádek vložte následující kód:
    6.    )
     )
      Result;
    ) ;_ end of defun
  6. Formátujte zadaný kód výběrem položek Nástroje [image] Zformátovat kód v Editoru z nabídky VLISPu.


Aktualizace zástupné funkce

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Aktualizace zástupné funkce

Nyní jste opravili funkci gp:getDialogInput. Při každé úpravě zástupné funkce byste měli vždy překontrolovat několik věcí:

  • Změnil se příkaz defun? Jinými slovy, zpracovává funkce stále stejný počet argumentů?
  • Vrací funkce něco jiného

V případě funkce gp:getDialogInput je odpověď na obě otázky ano. Funkce nyní přijímá parametr šířky cesty (kvůli nastavení výchozí velikosti a vzdálenosti dlaždic). A namísto vrácení hodnoty T, která je vrácena hodnotou zástupné funkce, nyní funkce gp:getDialogInput vrátí seznam asociací se čtyřmi novými hodnotami.

Obě změny ovlivní kód, který funkci volá a kód, který zpracuje návratové hodnoty funkcí. Nahraďte čtyři předchozí verze funkce C:GPath v souboru gpmain.lsp následujícím kódem:

(defun C:GPath (/ gp_PathData gp_dialogResults)
  Požádejte uživatele o vstup: nejdříve o umístění cesty a
  ;; směr, potom parametry cesty. Pokračuje pouze pokud má platné
  ;; zadání. Uloží data do proměnné gp_PathData.
  (if (setq gp_PathData (gp:getPointInput))
    (if (setq gp_dialogResults (gp:getDialogInput (cdr(assoc 40
                               gp_PathData))))
      (progn
       ;; Nyní vezme výsledky funkce gp:getPointInput a přidá je
       ;; k informacím od funkce gp:getDialogInput.
       (setq gp_PathData (append gp_PathData gp_DialogResults))
       ;; V tomto bodě máte platné zadání od uživatele.
       ;; Nakreslete obrys a uložte výslednou křivku
       ;; "ukazatel" do proměnné PolylineName.
       (setq PolylineName (gp:drawOutline gp_PathData))
      ) ;_ end of progn
     (princ "\nFunkce byla zrušena.")
     ) ;_ konec if
    (princ "\nNedostatečné informace pro nakreslení hranice.")
  ) ;_ konec if
  (princ) ; tiše skončit
) ;_ end of defun

Podívejte se na řádky psané v opraveném kódu hlavní funkce C:GPathtučným písmem. Jsou zde dvě hlavní změny nutné pro správný chod programu:

  • Když je vyvolána funkce gp:getDialogInput, cesta je do něj vložena. Tato operace je provedena pomocí hodnoty asociované s klíčovým indexem 40 asociovaného seznamu proměnné gp_PathData.
  • Seznam asociací vrácený funkcí gp:getPointInput je přiřazen k proměnné s názvem gp_dialogResults. Pokud tato proměnná obsahuje hodnotu, její obsah je připojen k hodnotám asociovaného seznamu uloženého v proměnné gp_PathData.

V kódu se vyskytuje ještě několik změn spojených s nahrazením výplňových funkcí v zástupné verzi. Nejsnadnější způsob jejich zapracování je zkopírovat si daný kód z online cvičení a vložit jej do souboru.


Nabídnutí volby typu čáry hraniční křivky

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Nabídnutí volby typu čáry hraniční křivky

Jedním z požadavků kladených na aplikaci zahradní cesty bylo, aby se uživatel mohl při kreslení hranice rozhodnout mezi původní a odlehčenou křivkou. První verze napsané funkce gp:drawOutline vždy používá tloušťku čáry křivky k nakreslení hranice. Nyní, když máte připraveno dialogové rozhraní, můžete použít i volbu kreslení hranice pomocí původní křivky. Chcete-li toho dosáhnout, je nutné, aby funkce gp:drawOutline určovala, jaký druh křivky nakreslit a potom je nutné ji nakreslit.

Důležité změny funkce gp:drawOutline jsou vloženy v následujcí části kódu. Proveďte úpravy v souboru gpdraw.lsp označené tučně:

(setq PathAngle (cdr (assoc 50 BoundaryData))
    Width (cdr (assoc 40 BoundaryData))
    HalfWidth (/ Width 2.00)
    StartPt (cdr (assoc 10 BoundaryData))
    PathLength (cdr (assoc 41 BoundaryData))
    angp90 (+ PathAngle (Degrees->Radians 90))
    angm90 (- PathAngle (Degrees->Radians 90))
    p1 (polar StartPt angm90 HalfWidth)
    p2 (polar p1 PathAngle PathLength)
    p3 (polar p2 angp90 Width)
    p4 (polar p3 (+ PathAngle (Degrees->Radians 180))
              PathLength)
    poly2Dpoints (apply 'append
                (mapcar '3dPoint->2dPoint (list p1 p2 p3 p4))
             )
    poly3Dpoints (mapcar 'float (append p1 p2 p3 p4))
    ;; získá styl křivky
    plineStyle (strcase (cdr (assoc 4 BoundaryData)))
) ;_ konec setq
;; vložení křivky do modelového prostoru pomocí objektů ActiveX
(setq pline (if (= plineStyle "LIGHT")
     ;; vytvoří odlehčenou křivku
     (vla-addLightweightPolyline
          *ModelSpace*; Globální definice pro modelový prostor
          (gp:list->variantArray poly2Dpoints) ;převod dat
      ) ;_ konec vla-addLightweightPolyline
     ;; nebo vytvoří původní křivku
     (vla-addPolyline
          proměnná *ModelSpace*
          (gp:list->variantArray poly3Dpoints) ;převod dat
     ) ;_ konec vla-addPolyline
    ) ;_ konec if
) ;_ konec setq

Vpisování změn do kódu může být problém, protože zde kód nejen přidáváte, ale i odstraňujete a přeuspořádáváte. Doporučujeme zkopírovat celý příkaz setq z online cvičení a vložit do kódu.


Údržba kódu

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Údržba kódu

Pokud jste tak již neučinili, odsraňte následujcí kód z funkce C:GPath v souboru gpmain.lsp:

(princ "\nFunkce gp:drawOutline vrátila <")
(princ PolylineName)
(princ ">")
(Alert "Gratulujeme - váš program je hotov!")

Tento kód jste používali jako zástupce, ale nyní, když je gp:drawOutline funkční, již ji nepotřebujete.


Spuštění aplikace

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Spuštění aplikace

Před spuštěním svého programu uložte veškeré změněné soubory (pokud jste tak již neučinili). ++Vybrat můžete položky Soubor [image] Uložit vše nebo stisknete kombinaci kláves ALT + SHIFT + S, uloží se všechny otevřené soubory.

Další věcí, kterou je třeba provést, je znovu načíst všechny soubory ve VLISPu.

Jak načíst a spustit všechny soubory programu
  1. Pokud není projektový soubor vytvořený dříve v tomto cvičení otevřen, vyberte z nabídky VLISPu položky Projekt [image] Otevřít projekt, potom zadejte název projektu gpath; nedopisujte příponu .prj. Pokud VLISP nenalezne zadaný soubor, stiskněte tlačítko Procházet a vyberte soubor v dialogu Otevřít projekt. Stiskněte tlačítko Otevřít.
  2. Stiskněte tlačítko Načíst zdrojové soubory v okně projektu.
  3. Zadáním příkazu (C:GPath) do příkazového řádku ve VLISP konzole spusťte program. Pokud potřebujete provést odladění chyb programu, zkuste použít nástroje popsané ve cvičení 2 a 3. Přitom pamatujte na to, že pokud se vám nepodaří chyby odstranit, můžete si kód kdykoliv zkopírovat z adresáře Tutorial\VisualLISP\Lesson4.

Vyzkoušejte si také kreslení hranice pomocí odlehčené i původní křivky. Po nakreslení cest určete pomocí příkazu programu AutoCAD list, zdali program nakreslil správné typy entit.


Shrnutí cvičení 4

Tvorba projektu a přidání rozhraní
Tvorba projektu a přidání rozhraní
Shrnutí cvičení 4

V tomto cvičení jste:

  • Rozdělili kód na více modulů uložených ve 4 samostatných souborech.
  • Uspořádali moduly kódu do projektu VLISPu.
  • Naučili se definovat dialog pomocí jazyka DCL (Dialog Control Language).
  • Vytvořili kód AutoLISPu zpracovávající zadání provedená v dialogu.
  • Upravili kód tak, aby program nabídl volbu typu čáry hranice.

Nyní máte program, který umí nakreslit hranici zahradní cesty. V dalším cvičení nakreslíte v zahradní cestě dlaždice. Postupně se tak seznámíte s dalšími programovacími nástroji VLISPu.


Kreslení dlaždic

Na konci tohoto cvičení bude vaše aplikace splňovat požadavky uvedené ve cvičení 1. Přidáte do ní funkce pro kreslení dlaždic uvnitř hranice zahradní cesty a této funkci nabídnete několik odlišných způsobů tvorby entit. Dozvíte se dále o některých klávesových zkratkách a nových editačních nástrojích.

Témata v této části:

  • Představení dalších editačních nástrojů Visual LISPu
  • Nakreslení dlaždic zahradní cesty
  • Testování kódu
  • Shrnutí cvičení 5


Představení dalších editačních nástrojů Visual LISPu

Kreslení dlaždic
Kreslení dlaždic
Představení dalších editačních nástrojů Visual LISPu

Otevřete kopii souboru gpdraw.lsp v okně textového editoru Visual LISPu®, není-li již otevřen. V tomto kódu je několik věcí typických pro většinu kódů, s nimiž se budete při programování ve VLISPu setkávat. První takovou věcí je přítomnost množství závorek a v nich vnořených závorek. Druhým výrazným rysem jsou četná volání funkcí, z nichž některé mají velmi dlouhé názvy (například vla‑addLightweightPolyline). VLISP nabízí některé editační nástroje, pomocí nichž budete s těmito obecnými prvky kódu AutoLISPu®.

Témata v této části:

  • Funkce vyhledání odpovídajících závorek
  • Funkce Automatické doplnění výrazu
  • Funkce Dokončit slovo podle seznamu (Apropo)
  • Zobrazení nápovědy pro určitou funkci


Funkce vyhledání odpovídajících závorek

Kreslení dlaždic
Kreslení dlaždic
Funkce vyhledání odpovídajících závorek

VLISP nabízí funkci vyhledání párových závorek, která vám pomůže nalézt uzavírací závorku odpovídající určité počáteční závorce.

Použití funkce vyhledání odpovídajících závorek
  1. Umístěte kurzor před počáteční závorku, která se nachází před voláním funkce setq.
  2. Stiskněte kombinaci kláves CTRL+SHIFT+]. (Můžete také poklepat myší.)

VLISP nalezne uzavírací závorku, která odpovídá vybrané počáteční závorce, a vybere kód ležící mezi nimi. Tím se přesvědčíte, že jste použili správný počet závorek, a zároveň budete moci snáze kopírovat nebo vyjímat vybraný text. To se vám bude hodit například v situaci, kdy jste aktualizovali volání funkce na konci cvičení 4.

Z jakého dalšího důvodu byste tuto funkci použili? Můžete zkopírovat část kódu do okna konzole VLISPu, vložit jej a vyzkoušet. Nebo se třeba rozhodnete nahradit 50 řádků kódu třemi skvělými řádky mnohem lepšího kódu. Původní kód snadno vyberete pomocí nástroje vyhledání závorek a potom jej odstraníte jediným stiskem klávesy. Je mnohem rychlejší nechat VLISP nalézt celý blok kódu, než sami dohledávat každou uzavírací závorku.

Existuje i kombinace kláves pro zpětné vyhledávání závorek. Chcete-li ji vyzkoušet, umístěte kurzor za koncovou závorku a potom poklepejte myší nebo stiskněte kombinaci kláves CTRL +SHIFT +[. VLISP vyhledá odpovídající počáteční závorku a vybere ji spolu s kódem mezi oběma závorkami.

Oba příkazy jsou dostupné také pomocí nabídky VLISPu, kde můžete vybrat Úpravy [image] Párování závorek.


Funkce Automatické doplnění výrazu

Kreslení dlaždic
Kreslení dlaždic
Funkce Automatické doplnění výrazu

Představte si, že v programu použijete následující kód:

ObjectCreationStyle (strcase (cdr (assoc 3 BoundaryData)))
(if (equal ObjectCreationStyle "COMMAND")
 (progn
  (setq firstCenterPt(polar rowCenterPt (Degrees->Radians 45) distanceOnPath))
    (gp:Create_activeX_Circle)
  )
)

(Prozatím se netrapte tím, co tento kód vlastně dělá. Je to jen příklad obsahující několik dlouhých názvů proměnných a funkcí.)

VLISP vám může ušetřit psaní na klávesnici tím, že sám doplní potřebné výrazy.

Použití funkce Automatické doplnění výrazu
  1. Přejděte na konec souboru gpdraw.lsp a zadejte následující kód:
    2. ObjectCreationStyle (strcase (cdr (assoc 3 BoundaryData)))
       (if (equal Ob
  2. Stiskněte kombinaci kláves CTRL+MEZERNÍK.

    3. VLISP vám právě ušetřil sedmnáct úhozů, protože prohledal aktuální soubor a nalezl odpovídající řetězec pro dva znaky, které jste napsali jako poslední.

  3. Dokončete řádek kódu tak, aby vypadal takto:
    4. (if (equal ObjectCreationStyle "COMMAND")
  4. Přidejte následující řádky:
    5.  (progn
      (setq firstCenterPt(p
  5. Stiskněte kombinaci kláves CTRL+MEZERNÍK.

    6. VLISP nalezne naposledy použitý výraz na „p“, což je progn. Vy však potřebujete výraz polar. Když několikrát stisknete kombinaci kláves CTRL + SPACEBAR, VLISP bude procházet možné návrhy výrazu nalezené v kódu. Postupně tak nalezne i požadovaný výraz polar.

  6. Odstraňte celý vložený kód, sloužil pouze pro demonstrační účely.

    7. Funkce Automatické doplnění výrazu je dostupná také z nabídky Najít ve VLISPu.Funkce.


Funkce Dokončit slovo podle seznamu (Apropo)

Kreslení dlaždic
Kreslení dlaždic
Funkce Dokončit slovo podle seznamu (Apropo)

Pokud jste již dříve pracovali s AutoLISPem, jistě jste někdy potřebovali napsat výraz podobný tomuto:

(setq myEnt (ssname mySelectionSet ssIndex))

Často je matoucí sledování všech funkcí pro výběr množin: ssname, ssget, sslength atd. VLISP vám v takovém případě může pomoci svou funkcí Dokončit slovo podle seznamu.

Použití funkce Dokončit slovo podle seznamu
  1. Přejděte na konec souboru gpdraw.lsp a zadejte na prázdný řádek toto:
    2. (setq myEnt (ent
  2. Stiskněte kombinaci kláves CTRL+SHIFT+MEZERNÍK.

    3. VLISP zobrazí seznam symbolů AutoLISPu začínajících ent.

    Pomocí kurzorových kláves (šipka nahoru a dolů) se můžete v seznamu pohybovat nahoru a dolů. Vyberte položku ENTGET, potom stiskněte klávesu ENTER.

    VLISP nahradí písmena ent výrazem ENTGET.

  3. Odstraňte napsaný kód.


Zobrazení nápovědy pro určitou funkci

Kreslení dlaždic
Kreslení dlaždic
Zobrazení nápovědy pro určitou funkci

Kód, který nakreslí odlehčenou křivku, volá funkci s názvem vla-addLightweightPolyline. Tento výraz je nejenom dosti dlouhý, ale navíc existuje několik funkcí, jejichž názvy začínají vla-add, které slouží k tvorbě entit. Místo hledání v příručce při každém psaní programu použijte nápovědu pro funkce VLISPu.

Použití nápovědy při psaní funkce
  1. Na prázdný řádek napište:
    2. (vla-add
  2. Stiskněte kombinaci kláves CTRL+SHIFT+MEZERNÍK.
  3. Posunujte se v seznamu, dokud nenaleznete funkci vla‑addLightweightPolyline.
  4. ) ;_ konec vla-addLightweightPolyline

    5. VLISP zobrazí dialog Služba symbolů pro vybranou funkci.

  5. Stiskněte tlačítko Nápověda v dialogu Služba symbolů. (U funkcí ActiveX® budete přesměrování na reference ActiveX a VBA.)
  6. Odstraňte změny provedené v souboru gpdraw.lsp; tyto byly pouze jako ukázka. Uzavřete také dialogy Služba symbolů a Apropo.


Nakreslení dlaždic zahradní cesty

Kreslení dlaždic
Kreslení dlaždic
Nakreslení dlaždic zahradní cesty

Nyní máte hranici zahradní cesty a jste připraveni vyplnit ji dlaždicemi. Budete přitom muset chvíli logicky plánovat a potom použít odpovídající geometrii.

Témata v této části:

  • Logické plánování
  • Použití geometrických vztahů
  • Kreslení řad
  • Kreslení dlaždic v řadě
  • Prohlédnutí kódu


Logické plánování

Kreslení dlaždic
Kreslení dlaždic
Logické plánování

Je třeba vymyslet, jak budou dlažice uspořádány a kresleny. Pokud se jednalo o jednoduchou přímočarou mřížku dlaždic, mohli byste pomocí příkazu programu AutoCAD® POLE vyplnit dlaždice. U zahradní cesty je však třeba každou řadu dlaždic posunout vůči sousední řadě o určitou vzdálenost.

Tento vzor posunutých řad se neustále opakuje. Představte si, jak byste postupovali při skutečném dláždění cesty. Asi byste začali na jednom konci a pokládali řady dlaždic tak dlouho, až byste vyplnili celou cestu.

Myšlený postup pokládání dlaždic je shrnut v tomto pseudokódu:

V počátečním bodě cesty.
Rozmyslete si jak bude první řada odsazená od středu (buď vycentrovana
na cestě nebo odsazena o 1 "mezeru dlaždic").
Protože mezera vyplněné hranice je menší než mezera
výplň,
  Kreslení řady dlaždic.
  Nastavit nový počáteční bod (posunutý o jednu "velikost dlaždice").
  Přidejte vzdálenost s novou řadou do množství místa
  , které je vyplněno.
  Přepněte odsazení (pokud je vycentrováno, nastavte jej od středu nebo
  naopak).
  Přejít na začátek smyčky.


Použití geometrických vztahů

Kreslení dlaždic
Kreslení dlaždic
Použití geometrických vztahů

Pro nakreslení zahradní cesty je třeba znát několik rozměrů. Poloviční šířka je jednoduchá: je to polovina šířky cesty. Již jste definovali kód pro získání šířky od uživatele a uložili jej v asociovaném seznamu.

Mezera je také snadná; jedná se o dvojnásobek poloměru (čili průměr) plus prostor mezi dlaždicemi. Tyto rozměry jsou také zadány uživatelem.

Definování rozteče řad je již poněkud těžší a vyžaduje o něco rozsáhlejší znalosti trigonometrie. Je nutné použít následující vzorec:

Rozteč řad = (Průměr dlaždice + Vzdálenost mezi dlaždicemi) *
               (sinus 60 stupňů)


Kreslení řad

Kreslení dlaždic
Kreslení dlaždic
Kreslení řad

Podívejte se, zda rozumíte následující funkci. Srovnejte ji s pseudokódem a zkuste najít právě popsané geometrické výpočty. Možná, že zde najdete několik funkcí AutoLISPu, které dosud neznáte. Více informací o těchto funkcích naleznete v příručce AutoLISP Reference. Prozatím si přečtěte kód; nic nepište.

(defun gp:Calculate-and-Draw-Tiles (BoundaryData / PathLength
           TileSpace TileRadius SpaceFilled SpaceToFill
           RowSpacing offsetFromCenter
           rowStartPoint pathWidth pathAngle
           ObjectCreationStyle TileList)
  (setq PathLength (cdr (assoc 41 BoundaryData))
        TileSpace (cdr (assoc 43 BoundaryData))
        TileRadius (cdr (assoc 42 BoundaryData))
        SpaceToFill (- PathLength TileRadius)
        RowSpacing (* (+ TileSpace (* TileRadius 2.0))
                         (sin (Degrees->Radians 60))
                      ) ;_ konec *
        SpaceFilled RowSpacing
        offsetFromCenter 0.0
        offsetDistance (/ (+ (* TileRadius 2.0) TileSpace) 2.0)
        rowStartPoint (cdr (assoc 10 BoundaryData))
        pathWidth (cdr (assoc 40 BoundaryData))
        pathAngle (cdr (assoc 50 BoundaryData))
        ObjectCreationStyle (strcase (cdr (assoc 3 BoundaryData)))
  ) ;_ konec setq
  ;; Kompenzace prvního volání gp:calculate-Draw-tileRow
  ;; ve smyčce níže.
  (setq rowStartPoint
       (polar rowStartPoint
            (+ pathAngle pi)
            (/ TileRadius 2.0)
       ) ;_ konec polar
  ) ;_ konec setq
  ;; Kreslení každé řady dlaždic.
  (while (<= SpaceFilled SpaceToFill)
    ;; Získání seznamu vytvořených dlaždic, přidání do seznamu.
    (setq tileList (append tileList
              (gp:calculate-Draw-TileRow
                (setq rowStartPoint
                     (polar rowStartPoint
                            pathAngle
                            RowSpacing
                     ) ;_ konec polar
                ) ;_ konec setq
                TileRadius
                TileSpace
                pathWidth
                pathAngle
                offsetFromCenter
                ObjectCreationStyle
              ) ;_ konec gp:calculate-Draw-TileRow
            ) ;_ konec append
     ;; Výpočet vzdálenosti pro další řadu.
     SpaceFilled (+ SpaceFilled RowSpacing)
     ;; Rozhodnutí o nulovém či kladném odsazení
     ;; (způsobí odsazení řad).
     offsetFromCenter
           (if (= offsetFromCenter 0.0)
                  offsetDistance
                  0.0
           ) ;_ konec if
    ) ;_ konec setq
  ) ;_ konec while
  ;; Vrácení seznamu vytvořených dlaždic.
  tileList
) ;_ end of defun

Několik částí tohoto kódu vyžaduje bližší vysvětlení.

Následující úryvek kódu se provede před začátkem smyčky while:

;; Kompenzace prvního počátečního bodu!!
(setq rowStartPoint(polar rowStartPoint
(+ pathAngle pi)(/ TileRadius 2.0)))

Za tajemstvím funkce tohoto algoritmu stojí tři hlavní věci:

  • Proměnná rowStartPoint se začne provádět v rámci přiřazení funkce gp:Calculate‑and‑Draw-Tiles k bodu vybranému uživatelem jako počáteční bod trajektorie.
  • Úplně první argument vložený do funkce gp:calculate-Draw-TileRow provádí následující:

    • (setq rowStartPoint(polar rowStartPoint pathAngle RowSpacing))

    Jinak řečeno: V okamžiku volání funkce gp:calculate‑Draw‑TileRow je proměnná rowStartPoint nastavena na vzdálenost RowSpacing od aktuální hodnoty rowStartPoint.

  • Argument rowStartPoint se používá ve funkci gp:calculate-Draw-TileRow jako počáteční bod pro středy kružnic v řadě.

Kompenzace předčasného posunu bodu rowStartPoint během kreslení první řady (čili při prvním průchodu smyčky while), znamená posun bodu rowStartPoint poněkud v opačném směru. Cílem je zamezit vzniku širokého prázdného okraje mezi hranicí cesty a první řadou dlaždic. Polovina hodnoty TileRadius je právě vzdálenost, o kterou je třeba tento bod posunout. To se dá provést funkcí polar promítnutím bodu rowStartPoint podél vektoru orientovaného pod úhlem 180 stupňů od úhlu PathAngle. Když se nad tím zamyslíte, zjistíte, že tento bod je dočasně umístěn mimo hranice cesty.

Další fragment (upravený kvůli lepší čitelnosti) vypadá trochu jako hádanka:

(setq tileList (append tileList
                  (gp:calculate-Draw-TileRow
                    (setq rowStartPoint
                      (polar rowStartPoint pathAngle RowSpacing)
                    ) ;_ konec setq
                    TileRadius TileSpace pathWidth pathAngle
                    offsetFromCenter ObjectCreationStyle
                  )))

V podstatě je zde funkce setq uzavírající funkci append uzavírající volání funkce gp:calculate-Draw-TileRow.

Funkce gp:calculate-Draw-TileRow vrátí ID objektu pro každou nakreslenou dlaždici. (ID objektu ukazuje na objekt dlaždice v rámci výkresu.) Jelikož kreslíte řadu za řadou, funkce vrací ID objektu vždy pro jednu řadu. Funkce append přidá nové ID objektů do seznamu ID uložených v proměnné tileList.

Téměř u konce funkce se nachází následující fragment kódu:
(setq offsetFromCenter
  (if (= offsetFromCenter 0.0)
       offsetDistance
       0.0
  )
)

Toto je přepínač odsazení, který určuje, zda má právě kreslená řada začínat s kružnicí centrovanou nebo posunutou vzhledem ke středu cesty. Toto je pseudokód pro příslušný algoritmus:

Nastavení odsazení na následující hodnotu:
   Pokud je odsazení aktuálně nulové, je nastaveno na vzdálenost odsazení.
      Jinak je nastaveno na nulu.


Kreslení dlaždic v řadě

Kreslení dlaždic
Kreslení dlaždic
Kreslení dlaždic v řadě

Nyní, když jste si ujasnili, jakým způsobem bude kreslení dlaždic fungovat, je dalším krokem vymyslet, jak nakreslit dlaždice v jednotlivých řadách. V následujícím schématu jsou dva možné případy: řada s nulovým odsazením od středu cesty a řada, jejíž odsazení je nenulové. Podívejte se na diagram a potom si přečtěte pseudokód, který následuje za ním.

Nastavení proměnných pro StartPoint, angp90, angm90 atd.
Nastavení proměnné FirstCenterPoint na StartPoint + odsazení
    (což může být 0.0).
Nastavení proměnné TileCenterPt na FirstCenterPoint.
(Komentář: Zahájení kreslení kružnic ve směru angp90.)
Protože vzdálenost od StartPoint k TileCenterPt je menší než HalfWidth:
    Nakreslení kružnice (přidání do seznamu kružnic).
    Nastavení TileCenterPt na další přírůstek mezery mezi dlaždicemi na angp90
    .
End While
Opětné nastavení TileCenterPoint na the FirstCenterPoint + přírůstek dlaždic dle angm90.
Protože vzdálenost od StartPoint k TileCenterPt je menší než HalfWidth:
    Nakreslení kružnice (přidání do seznamu kružnic).
    Nastavení TileCenterPt na další přírůstek mezery mezi dlaždicemi na angp90
    .
End While
Vrácení seznamu kružnic.


Prohlédnutí kódu

Kreslení dlaždic
Kreslení dlaždic
Prohlédnutí kódu

Nyní se podívejte na kód funkce gp:calculate-Draw-TileRow:

(defun gp:calculate-Draw-TileRow (startPoint TileRadius
          TileSpace pathWidth pathAngle offsetFromCenter
          ObjectCreationStyle / HalfWidth TileDiameter
                        ObjectCreationFunction angp90 angm90
                        firstCenterPt TileCenterPt TileList)
  (setq HalfWidth (- (/ pathWidth 2.00) TileRadius)
     Tilespacing (+ (* TileRadius 2.0) TileSpace)
     TileDiameter (* TileRadius 2.0)
     angp90 (+ PathAngle (Degrees->Radians 90))
     angm90 (- PathAngle (Degrees->Radians 90))
     firstCenterPt (polar startPoint angp90 offsetFromCenter)
     tileCenterPt firstCenterPt
     ObjectCreationStyle(strcase ObjectCreationStyle)
     ObjectCreationFunction
     (cond
          ((equal ObjectCreationStyle "ACTIVEX")
            gp:Create_activeX_Circle
          )
          ((equal ObjectCreationStyle "ENTMAKE")
            gp:Create_entmake_Circle
          )
          ((equal ObjectCreationStyle "COMMAND")
            gp:Create_command_Circle
          )
          (T
            (alert (strcat "ObjectCreationStyle ve funkci
                   (gp:calculate-Draw-TileRow
                  "\nje neplatné. Kontaktujte programátora."
                  "\n ObjectCreationStyle nastaveno na ACTIVEX"
                   )
            )
             setq ObjectCreationStyle "ACTIVEX")
          )
        )
       )
       Nakreslí kružnice nalevo od středu.
       (while (< (distance startPoint tileCenterPt) HalfWidth)
         ;; Přidá každou hotovou dlaždici do seznamu pro vrácení.
        (setq tileList
             (cons
             (ObjectCreationFunction tileCenterPt TileRadius)
                   tileList
             )
        )
        ;; Vypočítá střed další dlaždice.
        (setq tileCenterPt
          (polar tileCenterPt angp90 TileSpacing)
        )
       ) ;_ konec while
       ;; Nakreslí kružnice nalevo od středu.
       (setq tileCenterPt
         (polar firstCenterPt angm90 TileSpacing))
       (while (< (distance startPoint tileCenterPt) HalfWidth)
          ;; Přidá každou hotovou dlaždici do seznamu pro vrácení.
          (setq tileList
               (cons
                  (ObjectCreationFunction tileCenterPt TileRadius)
                    tileList
               )
          )
        ;; Vypočítá střed další dlaždice.
         (setq tileCenterPt (polar tileCenterPt angm90 TileSpacing))
       ) ;_ konec while
       ;; Vrátí seznam dlaždic.
       tileList
) ;_ end of defun

Kód AutoLISPu sleduje uvedený pseudokód:

(setq ObjectCreationFunction
  (cond
     ((equal ObjectCreationStyle "ACTIVEX")
        gp:Create_activeX_Circle
     )
     ((equal ObjectCreationStyle "ENTMAKE")
       gp:Create_entmake_Circle
     )
     ((equal ObjectCreationStyle "COMMAND")
       gp:Create_command_Circle
     )
     (T
       (alert
         (strcat
          "ObjectCreationStyle ve funkci gp:calculate-Draw-TileRow"
          "\nje neplatné. Kontaktujte programátora."
          "\n ObjectCreationStyle nastaveno na ACTIVEX"
         ) ;_ konec strcat
       ) ;_ konec alert
      (setq ObjectCreationStyle "ACTIVEX")
     )
  ) ;_ konec cond
) ;_ konec setq

Vzpomínáte si na požadavek, aby uživatel mohl kreslit dlaždice pomocí funkce ActiveX, funkce entmake nebo funkce command? Proměnné ObjectCreationFunction je přiřazena jedna z těchto tří funkcí podle parametru ObjectCreationStyle (předaného od funkce C:GPath a přes gp:Calculate-and-Draw-Tiles). Všechny tři funkce budou definovány v souboru gpdraw.lsp:

(defun gp:Create_activeX_Circle (center radius)
  (vla-addCircle *ModelSpace*
    (vlax-3d-point center) ; převést na 3D bod kompatibilní s Active-X
    poloměr
  )
) ;_ end of defun
(defun gp:Create_activeX_Circle (center radius)
  (entmake
    (list (cons 0 "CIRCLE") (cons 10 center) (cons 40 radius))
  )
  (vlax-ename->vla-object (entlast))
)
(defun gp:Create_activeX_Circle (center radius)
  (command "_CIRCLE" center radius)
  (vlax-ename->vla-object (entlast))
)

První funkce kreslí kružnici pomocí funkce ActiveX a vrací objekt ActiveX.

Druhá funkce kreslí kružnici pomocí funkce entmake. Vrací název entity převedený na objekt ActiveX.

Třetí funkce kreslí kružnici pomocí funkce command. Vrací také název entity převedený na objekt ActiveX.


Testování kódu

Kreslení dlaždic
Kreslení dlaždic
Testování kódu

Pokud jste došli až sem, máte hlavní část práce za sebou.

Jak otestovat kód
  1. Uzavřete všechna aktivní okna v rámci VLISPu včetně otevřených oken projektu.
  2. Zkopírujte celý obsah adresáře Tutorial\VisualLISP\Lesson5 do adresáře cvičení MyPath.
  3. Projektový soubor gpath5.prj otevřete výběrem položek Vybrat projekt [image] Otevřít projekt z nabídky VLISPu.
  4. Načtěte zdrojové soubory projektu.
  5. Aktivujte (přepněte se) okno programu AutoCAD® a spusťte program příkazem gpath .
  6. Spusťte příkaz gpath třikrát a pokaždé nakreslete zahradní cestu pomocí jiné metody tvorby entit. Vidíte rozdíl v rychlosti nakreslení zahradní cesty u jednotlivých metod


Shrnutí cvičení 5

Kreslení dlaždic
Kreslení dlaždic
Shrnutí cvičení 5

Toto cvičení jste zahájili použitím editačních funkcí VLISPu, které vám pomohly:

  • Nalézt odpovídající závorky v rámci kódu.
  • Zjistit celý název funkce.
  • Nalézt informace o funkci v Nápovědě.

Na konci tohoto cvičení jste napsali kód, který nakreslí dlaždice zahradní cesty. Nyní máte program, který vyhovuje požadavkům ze začátku této příručky.

V tomto bodě byste již měli mít dostatek znalostí VLISPu na to, abyste mohli dále pokračovat sami. Před tím si však ještě projděte dvě následující cvičení demonstrující funkce reaktoru a další pokročilé funkce prostředí VLISPu.


Práce s reaktory

V tomto cvičení se dozvíte o reaktorech a o tom, jak se přiřazují k událostem a entitám ve výkresu. Reaktory slouží k tomu, aby program AutoCAD® upozornil vaši aplikaci v případě určité události. Pokud například uživatel přemístí entitu, ke které aplikace přiřadila reaktor, bude vaše aplikace na přesun entity upozorněna. Kód můžete naprogramovat tak, aby se v uvedeném případě spustily jiné operace, například posun jiných entit spojených s přesunutou entitou či aktualizace textů zaznamenávající revize upraveného prvku výkresu. V podstatě se jedná o stejný efekt, jako byste vaši aplikaci vybavili pagerem a sdělili programu AutoCAD, aby v případě nějaké změny poslal aplikaci zprávu.

Témata v této části:

  • Základy použití reaktorů
  • Tvorba reaktorů pro aplikaci zahradní cesty
  • Test spuštění reaktorů
  • Shrnutí cvičení 6


Základy použití reaktorů

Práce s reaktory
Práce s reaktory
Základy použití reaktorů

Reaktor je objekt připojený k editoru výkresu nebo specifickým entitám v rámci výkresu. Když budeme pokračovat v metafoře použití pageru, bude reaktor zařízením, které automaticky vytočí číslo vašeho pageru v okamžiku, kdy se něco děje. Stránkovač ve vaší aplikaci je funkce AutoLISPu® , volaná reaktorem; taková funkce se nazývá funkce zpětného volání.

Poznámka Složitost kódu aplikace a úroveň potřebných znalostí a zkušeností v posledních dvou cvičeních je mnohem vyšší než tomu bylo ve cvičeních 1 až 5. Naleznete zde mnoho informací, ne všechny jsou však vysvětleny tak podrobně, jako v předchozích cvičeních. Jste-li začátečník, netrapte se, pokud vám vše nebude jasné hned na první pokus. Berte tato cvičení jako nahlédnutí do sféry výkonných, avšak technicky náročnějších funkcí VLISPu®.

Témata v této části:

  • Typy reaktorů


Typy reaktorů

Práce s reaktory
Práce s reaktory
Typy reaktorů

Existuje mnoho typů reaktorů programu AutoCAD®. Každý typ reaktoru odpovídá jedné nebo více událostí programu AutoCAD. Reaktory jsou seskupeny do následujících kategorií:

Reaktory editoru

Upozorní vaši aplikaci pokaždé, když je vyvolán příkaz programu AutoCAD.

Reaktory propojení

Upozorní vaši aplikaci pokaždé, když je načtena nebo uvolněna z paměti aplikace ObjectARX® .

Reaktory databáze

Odpovídá specifickým entitám či objektům v rámci výkresové databáze.

Reaktory dokumentu

Upozorní vaši aplikaci v režimu MDI na změnu v aktuálním výkresovém dokumentu, například otevření nového výkresového dokumentu, aktivaci okna jiného dokumentu a změnu stavu uzamknutí dokumentu.

Reaktory objektu

Upozorní vás pokaždé, když bude určitý objekt změněn, kopírován či smazán.

Kromě reaktorů editoru obsahuje každá kategorie pouze jeden typ reaktoru. Editační reaktory obsahují širokou třídu reaktorů: například reaktory DXF™, které upozorní aplikaci na import či export souboru DXF a reaktory myši upozorňující na události spojené s myší - třeba poklepání.

V rámci kategorií reaktorů existuje mnoho událostí, k nimž lze reaktor připojit. AutoCAD umožňuje uživatelům provádět množství různých akcí a je na vás, abyste určili ty akce, které vás zajímají. Potom můžete k vybrané události připojit svůj reaktor „automatický hlásič“ a napsat funkci zpětného volání, která se spustí, jakmile daná událost nastane.


Tvorba reaktorů pro aplikaci zahradní cesty

Práce s reaktory
Práce s reaktory
Tvorba reaktorů pro aplikaci zahradní cesty

Při implementaci reaktorů do aplikace zahradní cesty začněte nejprve zpracováním několika málo událostí.

Témata v této části:

  • Výběr událostí reaktoru pro zahradní cestu
  • Plánování funkcí zpětného volání
  • Plánování použití více reaktorů
  • Připojení reaktorů
  • Ukládaní dat pomocí reaktoru
  • Základní funkce C:GPath.
  • Přidání funkcí zpětného volání reaktoru
  • Úklid po použití reaktorů


Výběr událostí reaktoru pro zahradní cestu

Práce s reaktory
Práce s reaktory
Výběr událostí reaktoru pro zahradní cestu

V tomto cvičení si stanovíte následující cíle:

  • Při přesunu rohového bodu (vrcholu) hranice zahradní cesty bude cesta překreslena tak, aby její obrys zůstal přímočarý. Navíc budou na základě nové velikosti a tvaru překresleny všechny dlaždice.
  • Při smazání hranice cesty se odstraní i dlaždice.


Plánování funkcí zpětného volání

Práce s reaktory
Práce s reaktory
Plánování funkcí zpětného volání

Pro každou událost reaktoru je třeba naplánovat funkci, která bude spuštěna, když daná událost nastane. Následující pseudokód nastiňuje logickou posloupnost událostí, která by měla proběhnout, když uživatel přetáhne jeden z vrcholů křivky do nové pozice:

Definování funkce gp:outline-changed
       Smazání dlaždic.
       Určení, jak se hranice změnila.
       Napřímení hranice.
       Překreslení dlaždic.
Konec funkce

Má to však háček. Když uživatel začne přetahovat obrys vrcholu křivky, AutoCAD upozorní vaši aplikaci pomocí události :vlr‑modified. V tomto okamžiku však uživatel teprve zahájil tažení jednoho z vrcholů křivky. Pokud okamžitě vyvoláte funkci gp:outline‑changed, přerušíte akci, kterou uživatel právě provádí. Nebudete vědět, kde je nová pozice vrcholu, jelikož uživatel ji ještě nestačil vybrat. A konečně AutoCAD neumožní vaší funkci úpravu křivky, dokud ji uživatel ještě přetahuje. AutoCAD má totiž objekt křivky otevřen pro úpravy a v tomto stavu jej ponechá až do okamžiku, kdy uživatel dokončí změnu pozice objektu.

Je třeba změnit přístup k problému. Zde je nová varianta řešení:

Když uživatel zahájí změnu pozice vrcholu křivky,
  Volání funkce gp:outline-changed
  Definování funkce gp:outline-changed
    Nastavení globální proměnné pro uložení ukazatele na křivku
    upravovanou uživatelem
  Konec funkce
Když je příkaz ukončen,
  Volání funkce gp:command-ended
  Definování funkce gp:command-ended
           Smazání dlaždic
           Získání informací o předchozích umístěních vrcholů křivky
           Získání informací o nových umístěních vrcholů křivky
           Předefinování křivky (napřímení)
           Překreslení dlaždic
  Konec funkce

Jakmile uživatel dokončí úpravu obrysu cesty, AutoCAD upozorní vaši aplikaci pomocí události :vlr‑commandEnded (v případě, že jste nastavili reaktor editoru).

Použití globální proměnné identifikující křivku změněnou uživatelem je nutné, protože mezi funkcemi gp:outline-changed a gp:command-ended. Ve vaší aplikaci jsou obě funkce vyvolány a provedeny nezávisle na sobě. Zmíněná globální proměnná tedy obsahuje důležitý údaj nastavený jednou funkcí a použitý druhou.

Nyní zvažte případ, kdy uživatel smaže hranici zahradní cesty. Jediným úkolem je zde odstranit i všechny dlaždice. Tento záměr nastiňuje následující pseudokód:

Jakmile uživatel začne mazat hranici,
  Volání funkce gp:outline-erased
  Definování funkce gp:outline-erased
     Nastavení globální proměnné s ukazatelem na reaktor připojený
     k mazané křivce
  Konec funkce
Jakmile je mazání dokončeno,
  Volání funkce gp:command-ended
  Definování funkce gp:command-ended
     Odstranění dlaždic, které patřili k nyní již smazané křivce
  Konec funkce


Plánování použití více reaktorů

Práce s reaktory
Práce s reaktory
Plánování použití více reaktorů

Uživatelé mohou mít na obrazovce více zahradních cest a mohou mazat více než jednu z nich. Musíte vymyslet řešení i pro tuto eventualitu.

Reaktor spojený s určitou entitou je reaktorem objektu. Pokud ve výkresu existuje několik entit, může v něm existovat i několik reaktorů objektu - každý pro jednu entitu. Určitá editační operace (například použití příkazu vymaž může spustit množství reakcí podle toho, kolik z vybraných entit obsahuje připojený reaktor. Reaktory editoru jsou na druhé straně používány jednotlivě. Vaše aplikace by měla připojit pouze jeden reaktor události :vlr-commandEnded.

Posloupnost událostí pro obě úpravy-změnu vrcholu a smazání křivky končí akcemi, které je třeba provést v rámci funkce gp:command-ended. Určete, která sada akcí má být provedena pro každou variantu. Tento záměr nastiňuje následující pseudokód:

Definování funkce gp:command-ended (druhá verze)
  Získání ukazatele na křivku (z globální proměnné)
      Podmínka:
        Pokud byla křivka upravena, pak:
           Smazání dlaždic
           Získání informací o předchozích umístěních vrcholů křivky
           Získání informací o nových umístěních vrcholů křivky
           Předefinování křivky (napřímení)
           Překreslení dlaždic
        Konec podmínečného výrazu
        Pokud byla křivka smazána, potom:
           Smazání dlaždic
        Konec podmínečného výrazu
      Konec podmínky
Konec funkce


Připojení reaktorů

Práce s reaktory
Práce s reaktory
Připojení reaktorů

Dalším krokem při plánování aplikace s reaktory je určit, jak a kdy budou reaktory připojeny. Je třeba připojit dva reaktory objektu pro hraniční křivku každé zahradní cesty (jeden bude reagovat na událost úpravy a druhý na událost smazání) a jeden reaktor editoru, který upozorní vaši aplikaci, až uživatelé dokončí úpravu křivky. Reaktory objektu jsou připojeny k entitám, zatímco reaktory editoru jsou registrovány v rámci programu AutoCAD.

Je třeba promyslet ještě jednu věc. Při přepočítání obrysu křivky (napřímení) po provedení úpravy uživatelem je nutné vědět, jaká byla konfigurace vrcholů před úpravou. Tato informace nemůže být zjištěna po úpravě křivky. V té době jsou k dispozici jen údaje o nové konfiguraci. Jak na to? Požadovaný údaj si můžete uchovat v globální proměnné, ale je tu jeden problém. Uživatelé mohou kreslit libovolný počet zahradních cest, přičemž každá z nich by vyžadovala novou globální proměnnou.


Ukládaní dat pomocí reaktoru

Práce s reaktory
Práce s reaktory
Ukládaní dat pomocí reaktoru

Problém uložení původní konfigurace můžete vyřešit pomocí další vlastnosti reaktorů VLISPu - schopnosti ukládat data přímo v reaktoru. Když uživatel poprvé kreslí hranici cesty, můžete k této hranici připojit reaktor spolu s údaji, které chcete uložit. V takovém případě bude nutné upravit hlavní funkci programu C:GPath následovně:

Definování funkce C:GPath
   Provedení všeho, co je dosud nastaveno v aplikaci zahradní cesty
   Připojení reaktoru objektu ke křivce pomocí těchto parametrů:
   Ukazatel na právě nakreslenou křivku
      Seznam dat, která chcete do reaktoru uložit
      Seznam dat, které má reaktor nahrát,
      Seznam určitých událostí křivkového objektu, které budou sledovány,
      spolu s funkcemi zpětného volání LISPu, které budou vyvolány
   Konec tvorby reaktoru objektu
   Připojení reaktoru editoru k výkresovému editoru pomocí
   následujících parametrů:
      Veškerá data, která chcete připojit k reaktoru (v tomto případě žádná)
      Seznam specifických událostí editoru, které chcete sledovat
      spolu s funkcemi zpětného volání LISPu, které budou vyvolány
   Konec tvorby reaktoru editoru
Konec funkce


Základní funkce C:GPath.

Práce s reaktory
Práce s reaktory
Základní funkce C:GPath.

Aktualizujte funkci C:GPath přidáním kódu pro tvorbu reaktoru.

Jak přidat tvorbu reaktoru do aplikace C:GPath
  1. Nahraďte svou verzi souboru gpmain.lsp aktualizovanou verzí uvedenou níže. Zkopírujte tento kód z adresáře <adresář programu AutoCAD>\Tutorial\VisualLISP\Lesson6:
    2. (defun C:GPath (/
            gp_PathData
            gp_dialogResults
            PolylineName
            tileList
               )
      (setvar "OSMODE" 0) ;; Vypne uchopení objektu
    ;|
    ;; Cvičení 6 přidá zkrácený příkazový reaktor do programu AutoCAD
      ;;Není však žádoucí, aby při každém kreslení kružnice
      ;; bylo vybráno uživatelem kreslení dlaždic metodou COMMAND
      ;; metoda vybraná uživatelem. Takže vypněte
      ;; *commandReactor* (pokud existuje).
      |;
    (if *commandReactor*
        (progn
          (setq *commandReactor* nil)
          (vlr-remove-all :VLR-Command-Reactor)
        )
      )
      Požádejte uživatele o vstup: nejdříve o umístění cesty a
      ;; směr, potom parametry cesty. Pokračuje pouze pokud má platné
      ;; zadání. Uloží data do proměnné gp_PathData.
      (if (setq gp_PathData (gp:getPointInput))
        (if (setq gp_dialogResults
               (gp:getDialogInput
             (cdr (assoc 40 gp_PathData))
               ) ;_ konec gp:getDialogInput
        ) ;_ end of setq
          (progn
        ;; Nyní vezme výsledky funkce gp:getPointInput a přidá je
        ;; k informacím od funkce gp:getDialogInput
        (setq gp_PathData (append gp_PathData gp_DialogResults))
        ;; V tomto bodě máte platné zadání od uživatele
        ;; Nakreslete obrys a uložte výsledný křivkový "ukazatel"
        ;; do proměnné PolylineName
        (setq PolylineName (gp:drawOutline gp_PathData))
        ;; Nyní je čas nakreslit dlaždice v rámci hranic.
        ;; Proměnná gp_tileList obsahuje seznam ukazatelů na objekty pro
        ;; dlaždice. Po spočítání počtu bodů (pomocí funkce
        ;; length), je možné zobrazit výsledný
        ;; počet nakreslených dlaždic.
        (princ "\nCesta obsahuje ")
        (princ
          (hranice
            (setq tileList (gp:Calculate-and-Draw-Tiles gp_PathData))
          ) ;_ konec length
        ) ;_ konec princ
        (princ " dlaždic.")
    ;; Přidá seznam ukazatelů na dlaždice (vráceno
        ;; funkcí gp:Calculate-and-Draw-Tiles) do funkce gp_PathData. Ty budou
        ;; uloženy v datech reaktoru pro reaktor připojený
        ;; k hraniční křivce. Díky těmto údajům křivka
        ;; "ví", které dlaždice (kružnice) k ní náleží.
        (setq gp_PathData
               (append (list (cons 100 tileList))
                        ; všechny dlaždice
                   gp_PathData
               ) ;_ konec append
        ) ;_ end of setq
    ;; Před připojením dat reaktoru k objektu se nejprve podívejme
        ;; na funkci vlr-object-reactor
        ;; vlr-object-reactor má následující argumenty:
        ;; (data zpětného volání vlastníka vlr-object-reactor)
        ;; Argument zpětného volání je seznam
        ;; '(event_name . callback_function)
        ;;
        ;; V rámci tohoto cvičení použijeme všechny argumenty
        ;; asociované s vlr-object-reactor
        ;; Tyto reaktorové funkce budou spuštěny pouze, pokud
        ;; bude křivka PolylineName upravena nebo smazána
        (vlr-object-reactor
          ;; První argument pro vlr-object-reactor je
          ;; argument the "Owner’s List". Sem bude umístěn objekt,
          ;; který bude asociován s
          ;; reaktorem. V tomto případě se jedná o vlaObject
          ;; uložený v proměnné PolylineName.
          (list PolylineName)
          ;; Druhý argument obsahuje data pro cestu
          gp_PathData
          ;; Třetí argument je seznam specifických typů reaktorů
          ;; které hodláte použít
          '
           (
            ;; reaktor, který je volán při úpravě objektu
            (:vlr-modified . gp:outline-changed)
            ;; reaktor, který je volán při smazání objektu
            (:vlr-erased . gp:outline-erased)
           )
        ) ;_ konec vlr-object-reactor
        ;; Nyní zaregistrujeme reaktor příkazu, který upraví křivku
        ;; po dokončení příkazu změny
        (if (not *commandReactor*)
          (setq *commandReactor*
    (VLR-Command-Reactor
               nil ; Žádná data nejsou asociována s reaktorem příkazu
               '(
                 (:vlr-commandWillStart . gp:command-se spustí)
                 (:vlr-commandEnded . gp:command-ukončen)
                )
             ) ;_ konec příkazu vlr-command-reactor
          )
        )
     ;; Následující kód odstraní všechny reaktory při uzavření
     ;; výkresu. To je nesmírně důležité!!!!!!!!!
     ;; ;; Bez tohoto upozornění může AutoCAD při ukončení havarovat!
     (if (not *DrawingReactor*)
          (setq *DrawingReactor*
             (VLR-DWG-Reactor
               nil ; Žádná data nejsou asociována s reaktorem výkresu
               '((:vlr-beginClose . gp:clean-all-reactors)
                )
             ) ;_ konec vlr-DWG-reactor
         )
     )
          ) ;_ end of progn
          (princ "\nFunkce byla zrušena.")
        ) ;_ konec if
        (princ "\nNedostatečné informace pro nakreslení hranice.")
      ) ;_ konec if
      (princ) ; tiše skončit
    ) ;_ end of defun
    ;;; Zobrazí hlášení sdělující uživateli název příkazu.
    (princ "\nPro nakreslení zahradní cesty zadejte GPATH.")
    (princ)
  2. Projděte si změny a komentáře v kódu popisující jednotlivé nové příkazy. Veškerý upravený kód je v této příručce zobrazen tučným písmem.


Přidání funkcí zpětného volání reaktoru

Práce s reaktory
Práce s reaktory
Přidání funkcí zpětného volání reaktoru

Funkce zpětného volání reaktoru znamenají přidání značného množství kódu do vaší aplikace. Tento kód je pro vás připraven v adresáři Lesson6.

Jak přidat funkce zpětného volání reaktoru do programu
  1. Zkopírujte soubor gpreact.lsp z adresáře Tutorial\VisualLISP\Lesson6 do pracovního adresáře MyPath.
  2. Otevřete projekt GPath (pokud již není otevřen) a stiskněte tlačítko Vlastnosti projektu v okně projektu gpath.
  3. Přidejte soubor gpreact.lsp do svého projektu.
  4. Soubor gpreact.lsp se může nacházet kdekoliv mezi souborem utils.lsp, který musí být první, a gpmain.lsp, který musí zůstat poslední. Podle potřeby přesuňte požadované soubory a potom stiskněte tlačítko OK.
  5. Otevřete soubor gpreact.lsp poklepáním na jeho název v rámci okna projektu gpath.

Pročtěte si komentáře kódu, abyste lépe pochopili, co dělá. Všimněte si, že všechny návratové funkce jsou zástupné; jejich jediným úkolem je zobrazit při svém spuštění varovné hlášení.

Poslední funkce v souboru je tak důležitá že si zaslouží vlastní část.


Úklid po použití reaktorů

Práce s reaktory
Práce s reaktory
Úklid po použití reaktorů

Reaktory patří mezi velmi aktivní funkce. Při vytváření aplikace, která je využívá, byste mohli strávit spoustu času při věčných haváriích programu a případně i haváriích programu AutoCAD. Je proto dobré mít k dispozici nástroj pro případné odstranění všech přidaných reaktorů.

Soubor gpreact.lsp obsahuje funkci gp:clean-all-reactors , která sama o sobě nic nedělá. Místo toho volá funkci CleanReactors. Tuto funkci přidejte do souboru utils.lsp zkopírováním následujícího kódu na konec souboru:

;;;--------------------------------------------------------------;
;;; Funkce: CleanReactors ;
;;;--------------------------------------------------------------;
;;; Popis: Obecná pomůcka sloužící k čištění ;
;;; reaktorů. Může být použita během odladění chyb či ;
;;; při úklidu všech otevřených reaktorů před uzavřením ;
;;; výkresu. ;
;;;--------------------------------------------------------------;
(defun CleanReactors ()
  (mapcar 'vlr-remove-all
         '(:VLR-AcDb-reactor
           :VLR-Editor-reactor
           :VLR-Linker-reactor
           :VLR-Object-reactor
          )
  )
)


Test spuštění reaktorů

Práce s reaktory
Práce s reaktory
Test spuštění reaktorů

Nyní již byste měli mít všechno připraveno k použití reaktorů.

Jak otestovat kód reaktoru
  1. Načtěte celý zdrojový kód ze svého projektu. (Stiskněte tlačítko Načíst zdrojové soubory v okně projektu gpath.)
  2. Základní funkce C:GPath.

    3. Program nakreslí zahradní cestu stejně jako na konci cvičení 5. Nejdříve neuvidíte nic zajímavého.

  3. Po nakreslení cesty vyzkoušejte následující úkony:
    • Přesuňte vrchol křivky. Vyberte křivku, zobrazte její uzly a přetáhněte některý vrchol do nové pozice.
    • Protáhněte křivku.
    • Přesuňte křivku.
    • Smažte křivku.

Prohlédněte si zobrazená hlášení. Právě sledujete pozadí činnosti výkonné funkce.

(Pokud vaše aplikace nepracuje správně a vy nyní nechcete odlaďovat všechny chyby, můžete si spustit vzorový kód uložený v adresáři Tutorial\VisualLISP\Lesson6. Použijte projekt Gpath6 uložený v tomto adresáři.)

Poznámka Díky chování reaktoru si možná povšimnete, že po testování posloupnosti reaktorů v programu AutoCAD, nebude možný návrat do VLISPu stiskem ALT + TAB ani aktivací okna VLISPu. Pokud tento případ nastane, vraťte se do VLISPu jednoduše zadáním příkazu vlisp na výzvu programu AutoCAD Příkaz.

Témata v této části:

  • Podrobné zkoumání chování reaktorů


Podrobné zkoumání chování reaktorů

Práce s reaktory
Práce s reaktory
Podrobné zkoumání chování reaktorů

Na kousku papíru si zkuste vysledovat události reaktoru v rámci své aplikace. Zde jsou příklady věcí, které byste měli sledovat:

Nakreslete zahradní cesty a potom sledujte následující kombinace příkaz/objekt při postupném výběru křivek:

  • Vymaž / Hraniční křivka (cesta 1)
  • Vymaž / Kružnice v rámci křivky (cesta 2)
  • Vymaž / Dvě křivky (cesta 3 a 4)
  • Posun / Hraniční křivka (cesta 5)
  • Posun / Kružnice v rámci křivky (cesta 6)
  • Posun / Dvě křivky a několik kružnic (cesta 7 a 8)
  • Posun vrcholu (pomocí uzlů) / Hraniční křivka (cesta 9)
  • Protáhni / Hraniční křivka (cesta 10)

Toto cvičení vám pomůže snáze pochopit, co probíhá na pozadí. Kdykoliv v rámci cvičení 7 ztratíte přehled o chování reaktorů, nahlédněte do poznámek „sledování reaktorů“.


Shrnutí cvičení 6

Práce s reaktory
Práce s reaktory
Shrnutí cvičení 6

V tomto cvičení jste se seznámili s reaktory programu AutoCAD a jejich použití v rámci VLISPu. Navrhli jste plán přidání reaktorů do aplikace zahradní cesty a napsali kód nutný k provedení tohoto plánu.

Reaktory mohou do aplikace vnést výrazný prvek funkčnosti, ale nezapomeňte, že čím výkonnější je daný program, tím vážnější havárie mohou reaktory způsobit.

Další věcí, kterou byste měli mít na paměti, je způsob navržení vaší aplikace a to, že funkčnost reaktorů není trvalá z jednoho kreslicího sezení do druhého. Pokud uložíte výkres obsahující zahradní cestu navázanou na reaktory, při dalším otevření tohoto výkresu v něm již reaktory nebudou. Informace o použití trvalých reaktorů nabízí “Transient versus Persistent Reactors” v dokumentaci AutoLISP Developer’s Guide a popis odkazovaných funkcí naleznete v dokumentaci AutoLISP Reference.


Dokončení operace

V lekci 6 jste poznali základní mechanismy aplikací s reaktory. V lekci 7 vytvoříte zahradní cestu, která ví, jak a kdy se má změnit. Po testování aplikace a zajištění správné funkčnosti vytvoříte aplikaci Visual LISPu® z projektu VLISPu.

Tato část výuky patří do pokročilých témat. Pokud jste začátečník, možná nebudete všem zde uvedeným kódům AutoLISPu® rozumět. Na konci této lekce je seznam několika knih o AutoLISPu, které nabízí podrobnější informace o některých zde prezentovaných konceptech AutoLISPu.

Témata v této části:

  • Plánování použití reaktorů
  • Aktivace funkcí reaktorů
  • Předefinování hraniční křivky
  • Shrnutí hotového kódu
  • Vytvoření aplikace
  • Shrnutí celého cvičení
  • Publikace o LISPu a AutoLISPu


Plánování použití reaktorů

Dokončení operace
Dokončení operace
Plánování použití reaktorů

V tomto cvičení bude nutné definovat několik nových funkcí. Nejsou zde podrobně rozebírány všechny detaily kódu, důraz je kladen spíše na přehled principů, z nichž kód vychází. Na konci tohoto cvičení budete mít hotov veškerý zdrojový kód nutný k vytvoření aplikace zahradní cesty odpovídající vzorové aplikaci spouštěné ve cvičení 1.

Poznámka Při vývoji a odlaďování chyb aplikací s reaktory existuje nebezpečí zanechání programu AutoCAD® v nestabilním stavu. Příčin může být několik, například neúspěšné odstranění reaktoru ze smazaných entit. Před zahájením cvičení 7 je proto doporučeno uzavřít VLISP, uložit všechny otevřené soubory, ukončit AutoCAD a potom obě aplikace znovu spustit.

Začněte načtením projektu v podobě ze cvičení 6.

V rámci aplikace zahradní cesty je třeba provést ještě dvě hlavní věci:

  • Napsání zpětných volání reaktorů objektů.
  • Napsání zpětných volání reaktorů editoru.

Dále je třeba zvážit zpracování globálních proměnných v rámci programu. Často je žádoucí, aby si globální proměnné podržely určitou hodnotu po celou dobu kreslicího sezení programu AutoCAD. U reaktorů je však situace jiná. Představte si uživatele své aplikace zahradní cesty, kteří nakreslí v jediném výkresu několik zahradních cest. Potom je uživatel smaže - nejdříve jednu současně, potom dvě současně a tak dále, až zbude pouze jedna cesta.

Cvičení 5 uvedlo globální proměnnou *reactorsToRemove*, která je zodpovědná za uložení ukazatelů do reaktorů křivek, jež mají být vymazány. Když je reaktor *reactorsToRemove* deklarován v proměnné gp:outline-erased, událost vás upozorní, že křivka bude vymazána. Křivka není odstraněna, dokud není spuštěna událost gp:command-ended.

Když uživatel poprvé smaže křivku, vše funguje podle očekávání. Ve funkci gp:outline-erased uložíte ukazatel do rekatoru. Při spuštění funkce gp:command-ended odstraníte dlaždice spojené s křivkou, k níž je reaktor připojen, a vše je v pořádku.. Potom se uživatel rozhodne smazat dvě cesty. Nakonec aplikace dostane dvě volání funkce gp:outline‑erased, pro každou křivku, která má být vymazána. Přitom je třeba vyřešit dva možné problémy:

  • Když nastavíte proměnnou *reactorsToRemove*, musíte do této globální proměnné vložit ukazatel na reaktor, a vyhnout se přepsání libovolných hodnot zde uložených. To znamená, že reaktor *reactorsToRemove* musí mít strukturu seznamu, kam budete moci přidat ukazatele na reaktor. Potom můžete shromáždit několik ukazatelů na reaktory odpovídajících počtu cest vymazaných uživatelem v rámci jediného příkazu pro smazání qqq.
  • Při každém spuštění funkce gp:command-will-startindikující zahájení nové příkazové sekvence je nutné znovu inicializovat proměnnou *reactorsToRemove* na hodnotu nil.. To je nutné, aby globální proměnná neukládala ukazatele reaktoru z předchozího příkazu vymazat.

    • Pokud neprovedete novou inicializaci globální proměnné nebo nepoužijete nesprávnou strukturu dat (v tomto případě seznam), chování aplikace bude nepředvídatelné. V případě reaktorů může takové nepředvídatelné chování ohrozit i celé sezení programu AutoCAD.

Zde je řetěz událostí, které musí nastat, když uživatel smaže v rámci jediného příkazu dvě cesty. Povšimněte si začlenění globálních proměnných:

  • Spusťte příkaz erase. funkce gp\:command-will-start (setq *reactorsToRemove* nil)
  • Vyberte dvě křivky; vaše aplikace dosud nebyla informována.
  • Stiskem klávesy ENTER vymažete obě vybrané křivky.

    • Aplikace obdrží zpětné volání funkce gp:outline-erased pro jednu z křivek. Její ukazatel na reaktor je uložen do prázdné globální proměnné *reactorsToRemove*.

    Aplikace obdrží zpětné volání funkce gp:outline-erased pro druhou z křivek. Její ukazatel na reaktor je přidán do globální proměnné *reactorsToRemove* obsahující již první ukazatel na reaktor.

  • AutoCAD odstraní křivky.
  • Volání funkce gp:command-ended Jsou odstraněny všechny dlaždice spojené s ukazateli na reaktory uloženými v proměnné *reactorsToRemove*.

Kromě globální proměnné *reactorsToRemove*obsahuje vaše aplikace také globální proměnnou *polyToChange*, obsahující ukazatel na jakoukoliv křivku, která bude upravena. Další dvě globální proměnné pro aplikaci budou popsány později v tomto cvičení.

Témata v této části:

  • Reakce na více příkazů vyvolaných uživatelem
  • Ukládání informací do objektů reaktoru


Reakce na více příkazů vyvolaných uživatelem

Dokončení operace
Dokončení operace
Reakce na více příkazů vyvolaných uživatelem

Při psaní aplikace s reaktory potřebujete obsloužit každý příkaz, který ovlivní podstatnějším způsobem vaše objekty. Při vývoji své aplikace byste měli projít všechny možné editovací příkazy programu AutoCAD a určit, jak by na ně měla vaše aplikace reagovat. Poznámky „sledování reaktorů“ sestavené na konci cvičení 6 vám nyní velmi dobře poslouží. Vyvolejte příkazy, které očekáváte, že uživatel použije, a zapište si, jakým způsobem by měla aplikace reagovat. Je třeba naplánovat zejména následující akce:

  • Určete, co se stane, když uživatelé spustí příkaz ZPĚT a ZNOVA.
  • Určete, co se stane, když uživatel spustí příkaz OBNOV po vymazání entiti spojených s reaktory.

Aby výklad témat v tomto cvičení nebyl neúměrně složítý, nebudou rozebrány všechny možnosti a popis funkčnosti je rozebrán pouze okrajově.

Ačkoliv nebudete psát kód pro zpracování všech příkazů, podívejte se, co by znamenalo použití dalších editačních funkcí:

  • Pokud uživatelé protáhnou hranici křivky (příkazem PROTÁHNI), může se stát několik událostí. Křivka může být protažena v libovolném směru, ne pouze podél hlavní či vedlejší osy, takže hranice cesty může nakonec mít velmi odlišný tvar. Navíc je nutné uvážit, kolik vrcholů bylo protaženo. V situaci, kdy je protažen pouze jeden vrchol, bude výsledkem křivka zcela odlišná od té, u níž byly přesunuty vrcholy dva. V každém případě musí být odstraněny původní dlaždice a vypočítány nové pozice po změně hranice.
  • Pokud uživatelé hraniční křivku přesunou, je nutné smazat všechny dlaždice a potom je znovu nakreslit v nové pozici. Toto je poměrně jednoduchá operace, jelikož hraniční křivka nezměnila svůj tvar ani velikost.
  • Pokud uživatelé změní měřítko hraniční křivky, je třeba rozhodnout se. Bude změněno také měřítko dlaždic tak, aby cesta obsahovala stejný počet dlaždic? Nebo má zůstat velikost dlaždic beze změny a aplikace přidá nebo odebere dlaždice podle toho, jestli se křivka zvětšila nebo zmenšila?
  • Pokud uživatelé hraniční křivku otočí, všechny dlaždice musí být smazány a potom překresleny v nové orientaci.

Pro začátek postačí, když naplánujete následující akce:

  • Varujte uživatele při spuštění editačního příkazu, který by mohl poškodit zahradní cestu (například stretch, move nebo rotate).
  • Pokud bude uživatel pokračovat, smažte dlaždice a nakreslete je.
  • Odstraňte reaktory z hraniční křivky.

Poznámka Entity mohou být upraveny či smazány nejen pomocí uživatelem spuštěných příkazů programu AutoCAD, ale také pomocí aplikace AutoLISP nebo ObjectARX®. Příklad zahradní cesty neuvažuje programové manipulace s hranicí cesty prováděné například pomocí (entdel <entita křivky>). V takovém případě nebudou události reaktoru:vlr-commandWillStart a :vlr-commandEnded spuštěny.


Ukládání informací do objektů reaktoru

Dokončení operace
Dokončení operace
Ukládání informací do objektů reaktoru

Dalším důležitým aspektem aplikace, který je nutno promyslet, je to, jaký druh informace připojíte k reaktoru objektu vytvořenému pro každou entitu křivky. Ve cvičení 6 přidáte kód, který připojí obsah gp_PathData (seznam asociací) k reaktoru. Údaje v proměnné gp_PathData jste rozšířili o nové klíčové pole (100) asociovaného seznamu. Tento nový dílčí seznam obsahuje ukazatele na všechny kružnice přiřazené k hraniční křivce.

Kvůli přepočítání hraniční křivky je nutné přidat do proměnné gp_pathData čtyři další klíčové hodnoty:

;;; StartingPoint ;
;;; (12 . BottomStartingPoint) 15------------------------14 ;
;;; (15 . TopStartingPoint) | | ;
;;; EndingPoint 10 ----pathAngle---> 11 ;
;;; (13 . BottomEndingPoint) | | ;
;;; (14 . TopEndingPoint) 12------------------------13 ;
;;; ;

Tyto seřazené body jsou nutné k přepočítání hraniční křivky pokaždé, když uživatel přetáhne uzel rohu do nové pozice. Tato informace již existuje ve funkci gp:drawOutline v souboru gpdraw.lsp. Podívejte se však na návratové hodnoty této funkce. Aktuálně je vracen ukazatel na objekt křivky. Proto je třeba provést tři věci:

  • Sestavit seznam bodů obvodu v požadovaném formátu.
  • Upravit funkci tak, aby vracela seznamy bodů obvodu a ukazatel na křivku.
  • Upravit funkci C:GPath tak, aby správně zpracovala nový formát hodnot vrácených funkcí gp:drawOutline.

Sestavení seznamu bodů obvodu je snadné. Kód ActiveX ve funkci gp:drawOutline Lokální proměnná p1 odpovídá klíčové hodnotě 12, p2 hodnotě 13, p3 hodnotě 14 a p4 hodnotě 15. Zmíněné hodnoty sestavíte dohromady následovně:

(setq Result (list
  (cons 12 p1)
  (cons 13 p2)
  (cons 14 p3)
  (cons 15 p4)
))

Snadná je i úprava funkce, aby vracela obvodové body křivky a ukazatel na křivku. Jako poslední výraz v rámci funkce gp:drawOutline, sestavte seznam dvou položek, které chcete vrátit.

(list pline polyPoints)
Programování uložení obvodových bodů křivky
  1. Upravte funkci gp:drawOutline pomocí kódu psaného tučným písmem (nepřehlédněte novou lokální proměnnou polyPoints u příkazu defun):
    2. (defun gp:drawOutline (BoundaryData / PathAngle
                   Width HalfWidth StartPt PathLength
                   angm90 angp90 p1 p2
                   p3 p4 poly2Dpoints
                   poly3Dpoints plineStyle pline
                   polyPoints
                   )
      ;; získá hodnoty ze seznamu BoundaryData.
      (setq PathAngle (cdr (assoc 50 BoundaryData))
        Width (cdr (assoc 40 BoundaryData))
        HalfWidth (/ Width 2.00)
        StartPt (cdr (assoc 10 BoundaryData))
        PathLength (cdr (assoc 41 BoundaryData))
        angp90 (+ PathAngle (Degrees->Radians 90))
        angm90 (- PathAngle (Degrees->Radians 90))
        p1 (polar StartPt angm90 HalfWidth)
        p2 (polar p1 PathAngle PathLength)
        p3 (polar p2 angp90 Width)
        p4 (polar p3 (+ PathAngle
                    (Degrees->Radians 180)) PathLength)
        poly2Dpoints (apply 'append
                    (mapcar '3dPoint->2dPoint (list p1 p2 p3 p4))
                    )
        poly3Dpoints (mapcar 'float (append p1 p2 p3 p4))
        ;; načte styl křivky
        plineStyle (strcase (cdr (assoc 4 BoundaryData)))
        ;; vložení křivky do modelového prostoru pomocí objektů ActiveX.
        pline (if (= plineStyle "LIGHT")
                   ;; vytvoří odlehčenou křivku.
                   (vla-addLightweightPolyline
                 *ModelSpace*; Globální definice pro modelový prostor
                 (gp:list->variantArray poly2Dpoints)
                        ;převod dat
                 ) ;_ konec vla-addLightweightPolyline
                  ;; nebo vytvoření původní křivky.
                   (vla-addPolyline
                 proměnná *ModelSpace*
                 (gp:list->variantArray poly3Dpoints)
                        ;převod dat
                 ) ;_ konec vla-addPolyline
                   ) ;_ konec if
    polyPoints (list
                   (cons 12 p1)
                   (cons 13 p2)
                   (cons 14 p3)
                   (cons 15 p4)
                   )
        ) ;_ konec setq
      (vla-put-closed pline T)
      (list pline polyPoints)
    ) ;_ end of defun
  2. Základní funkce C:GPath. Vyhledejte řádek kódu vypadající takto:
    3. (setq PolylineName (gp:drawOutline gp_PathData))

    Změňte jej takto:

    (setq PolylineList (gp:drawOutline gp_PathData)
          PolylineName (car PolylineList)
          gp_pathData (append gp_pathData (cadr PolylineList))
     ) ;_ konec setq

    Proměnná gp_PathData nyní nese všechny informace vyžadované funkcí reaktoru.

  3. Přidejte proměnnou PolylineList do oddílu s lokálními proměnnými definice funkce C:GPath.


Aktivace funkcí reaktorů

Dokončení operace
Dokončení operace
Aktivace funkcí reaktorů

Ve cvičení 6 jste připojili všechny funkce zpětného volání gp:command-will-start k události reaktoru :vlr-commandWillStart. Ve své aktuální podobě tato funkce zobrazí hlášení a inicializuje dvě globální proměnné *polyToChange* a *reactorsToRemove* na nil.

Aktivování funkce zpětného volání gp:command-will-start
  1. Otevřete soubor gpreact.lsp.
  2. Do funkce gp:command‑will‑start přidejte pomocí následující úpravy volání funkce setq dvě proměnné:
    3. ;; Resetování všech čtyř globálních proměnných reaktoru na hodnotu nil.
    (setq *lostAssociativity* nil
            *polyToChange* nil
            *reactorsToChange* nil
            *reactorsToRemove* nil)
  3. Nahraďte zbývající kód ve funkci gp:command‑will‑start, až po poslední volání funkce princ následujícím kódem:
    4. (if (member (setq currentCommandName (car command-list))
           '( "U" "UNDO" "STRETCH" "MOVE"
              "ROTATE" "SCALE" "BREAK" "GRIP_MOVE"
              "GRIP_ROTATE" "GRIP_SCALE" "GRIP_MIRROR")
        ) ;_ konec member
        (progn
          (setq *lostAssociativity* T)
          (princ "\nPOZNÁMKA: ")
          (princ currentCommandName)
          (princ " naruší asociativitu cesty .")
        ) ;_ end of progn
    ) ;_ konec if

    Tento kód zkontroluje, zda uživatel spustil příkaz narušující asociativitu mezi dlaždicemi a cestou. Pokud uživatel takový příkaz použije, program nastaví globální proměnnou *lostAssociativity* a zobrazí varovné hlášení.

    Při experimentování se zahradní cestou možná narazíte na další editační příkazy, které upraví cestu a mohou způsobit ztrátu asociativity. Přidejte je do seznamu, aby byl uživatel informován o tom, co se stane. Když se tato funkce spustí, uživatel spustil příkaz, ale dosud nestihl vybrat entity pro úpravu. Uživatel může ještě příkaz přerušit a ponechat vše beze změny.

Témata v této části:

  • Přidání aktivity funkcím zpětného volání objektového reaktoru
  • Navržení funkce zpětného volání gp:command-ended
  • Zpracování více typů entit
  • Použití metod ActiveX ve funkcích zpětného volání reaktoru
  • Zpracování nelineárních sekvencí reaktoru
  • Psaní kódu funkce command-ended
  • Aktualizace funkce gp:Calculate-and-Draw-Tiles
  • Úprava dalších volání funkce gp:Calculate-and-Draw-Tiles


Přidání aktivity funkcím zpětného volání objektového reaktoru

Dokončení operace
Dokončení operace
Přidání aktivity funkcím zpětného volání objektového reaktoru

V lekci 6 jste zaregistrovali dvě návrato Funkce gp:outline-erased byla asociována s událostí reaktoru:vlr-erased a funkce gp:outline-changed byla asociována s událostí :vlr‑modified. Nyní musíte tyto funkce přimět, aby dělaly to, k čemu jsou určeny.

Aktivace funkcí zpětného volání reaktoru objektu
  1. Změňte jej takto:
    2. (defun gp:outline-erased (outlinePoly reactor parameterList)
      (setq *reactorsToRemove*
           (cons reactor *reactorsToRemove*))
      (princ)
    ) ;_ end of defun

    Probíhá zde následující operace. Reaktor připojený ke křivce je uložen do seznamu všech reaktorů, které je třeba odstranit. (Nezapomeňte, že i když jsou reaktory připojeny k entitám, jedná se o samostatné objekty a jejich vztahy k entitám musí být spravovány stejně pozorně jako ostatní entity programu AutoCAD.)

  2. Změňte gp:outline-changed podle následujícícho kódu:
    3. (defun gp:outline-changed (outlinePoly reactor parameterList)
      (if *lostAssociativity*
        (setq *reactorsToRemove*
                 (cons reactor *reactorsToRemove*))
        (setq *polytochange* outlinePoly
                  *reactorsToChange* (cons reactor *reactorsToChange*))
        )
      (princ)
    )

    Existují dvě kategorie funkcí, které mohou změnit obrys křivky. První kategorie obsahuje příkazy, které přeruší asociativitu cesty a jejích dlaždic. Zkontrolujte podmínku ve funkci gp:command‑will‑start a podle toho nastavte globální proměnnou *lostAssociativity*. V tomto případě je nutné dlaždice smazat a cesta je pak zcela v rukou uživatele. Druhou kategorii představuje režim uzlů příkazu PROTÁHNI, kde je asociativita zachována a po dokončení tažení vrcholu křivky do nové pozice je třeba narovnat obrys cesty.

    Proměnná *polyToChange* obsahuje ukazatele VLA-Object na samotnou křivku. Toho bude využito ve funkcigp:command-ended v okamžiku, kdy bude třeba přepočítat hraniční křivku.


Navržení funkce zpětného volání gp:command-ended

Dokončení operace
Dokončení operace
Navržení funkce zpětného volání gp:command-ended

Funkce zpětného volání gp:command-ended reaktoru editoru je hybnou silou celé akce. Dokud není volána, jsou hraniční křivky zahradní cesty “otevřeny pro editaci;” to znamená, že uživatel může s hranicí cesty v programu AutoCAD manipulovat. V rámci sekvence reaktoru musíte počkat AutoCAD dokončí svou část práce a teprve potom můžete provést to, co chcete.

Následující pseudokód ilustruje princip funkce gp:command-ended :

Určení podmínky křivky.
  PODMÍNKA 1 - KŘIVKA SMAZÁNA (příkaz Vymaž)
    Smazání dlaždic
  PODMÍNKA 2 - ZTRÁTA ASOCIATIVITY (Posun, Otoč atd.)
    Smazání dlaždic
  PODMÍNKA 3 - GRIP_STRETCH - PŘEKRESLIT A NOVÉ DLAŽDICE
    Smazání dlaždic
    Získání aktuálních údajů o hranici z křivky
    Pokud se jedná o odlehčenou křivku,
       Zpracování dat hranice jako 2D
    Jinak
       Zpracování dat hranice jako 3D
    Konec podmínky
  Předefinování hraniční křivky (předání parametrů aktuální
         konfigurace hranice, spolu se starou konfigurací)
  Získání nových údajů hranice a jejich převod do formátu
         nutného k zpětnému nastavení entity křivky
  Regenerace křivky
  Překreslení dlaždic (vynucení kreslení ActiveX)
  Vložení opravených dat hranice zpět do reaktoru
         vyjmenovaného v proměnné *reactorsToChange*
Konec funkce

Tento pseudokód je relativně jasný, ale některé důležité detaily by měly být probrány, tím spíše, že byste si jich pravděpodobně ani nevšimli.


Zpracování více typů entit

Dokončení operace
Dokončení operace
Zpracování více typů entit

První detail je to, že vaše aplikace může nakreslit dva druhy křivky: klasickou a odlehčenou. Tyto dva odlišné typy křivek vrací data entit v různých formátech. Klasická křivka vrátí seznam dvanácti reálných čísel: tedy čtyři sady bodů X, Y a Z. Odlehčená křivka však vrátí seznam osmi reálných čísel: tedy čtyři sady bodů X a Y.

Pokud uživatel posune jeden z vrcholů křivky, je nutné provést výpočty a určit průběh opravené křivky. Provedení výpočtu bude mnohem snazší, pokud budou data křivky mít konzistentní formát.

Verze souboru utils.lsp z lekce 7 obsahuje funkce na provedení nezbytných převodů formátu: xyzList->ListOfPoints eextrahuje a formátuje seznam 3D bodů do seznamu dílčích seznamů a xyList->ListOfPoints extrahuje a formátuje seznam 2D bodů do seznamu dílčích seznamů.

Vložení kódu pro převod dat křivky do konzistentního formátu
  1. Pokud máte otevřenou kopii souboru utils.lsp otevřenou v okně textového editoru VLISPu, uzavřete ji.
  2. Zkopírujte verzi souboru utils.lsp z adresáře Tutorial\VisualLISP\Lesson7 do vašeho pracovního adresáře.

    3. Kromě obou funkcí formátujících data křivky obsahuje soubor utils.lsp další pomocné funkce pro obsloužení uživatelských změn zahradní cesty.

  3. Otevřete utils.lsp v okně textového editoru VLISPu a prohlédněte si nový kód.


Použití metod ActiveX ve funkcích zpětného volání reaktoru

Dokončení operace
Dokončení operace
Použití metod ActiveX ve funkcích zpětného volání reaktoru

Druhý detail se nachází u konce pseudokódu v části překreslení dlaždic. Zde je příslušný příkaz pseudokódu:

Překreslení dlaždic (vynucení kreslení ActiveX)

Fráze v závorkách mluví za vše: vynucení kreslení ActiveX. K čemu je tento požadavek? Proč nemůže aplikace použít preferenci tvorby objektu uloženou v dílčím asociovaném seznamu?

Odpověď zní: pro tvorbu entit v rámci funkce zpětného volání reaktoru nelze použít funkci command. Příčiny jsou spojeny s interními omezeními programu AutoCAD. Je proto nutné použít kreslicí proceduru využívající prvky ActiveX. O této záležitosti si povíme více později v tomto cvičení.


Zpracování nelineárních sekvencí reaktoru

Poslední důležitý detail se týká sekvence příkaz/reaktor v programu AutoCAD, když uživatel upraví křivku pomocí specializovaných příkazů pro uzly. Tyto příkazy, například GRIP_MOVE a GRIP_ROTATE, jsou dostupné z místní nabídky po výběru uzlu na objektu a klepnutí pravým tlačítkem. Sekvence reaktoru není tak lineární jako prostý příkaz POSUN či VYMAŽ. Výsledkem je, že uživatel se přepne do příkazu uprostřed jiného příkazu. Tuto situaci si můžete demonstrovat, když načtete kód ze cvičení 6, který vyhledává sekvence událostí reaktoru. Nebo si jednoduše prohlédněte následující výstup okna konzole VLISPu opatřený poznámkami a sledujte probíhající operace:

;; Chcete-li začít, vyberte křivku a některé z kružnic pomocí
;; výběrového okna křížení. Položky ve výběrové množině--
;; vybrané kružnice a křivka--jsou nyní zobrazeny se zapnutými uzly.
;; Pro zahájení sekvence klepněte na jeden z uzlů křivky:
(GP:COMMAND-WILL-START #<VLR-Command-reactor> (GRIP_STRETCH))
;; Nyní je možné změnit příkaz na posun klepnutím pravým tlačítkem
;; a výběrem položky POSUN z místní nabídky. Povšimněte si, že
;; reaktor se spustí za účelem ukončení příkazu GRIP_STRETCH
;; bez spuštění události reaktoru objektu:
(GP:COMMAND-ENDED #<VLR-Command-reactor> (GRIP_STRETCH))
(GP:COMMAND-WILL-START #<VLR-Command-reactor> (GRIP_MOVE))
;; Nyní přetáhněte obrys (a vybrané kružnice) do nové pozice.
(GP:OUTLINE-CHANGED #
                 #<VLR-Object-reactor> nil)
(GP:COMMAND-ENDED #<VLR-Command-reactor> (GRIP_MOVE))

Tento kód demonstruje, že není jisté, zda budou ve všech případech volány funkce zpětného volání vašeho reaktoru objektu.

Tato sekvence má jeden háček. I během posledního zpětného volání command-ended nemohou být kružnice, které jsou součástí výběrové množiny uzlů, smazány. Tyto kružnice jsou nadále otevřeny programem AutoCAD. Pokud se je pokusíte smazat během zpětného volání command-ended může program AutoCAD selhat. Abyste se tomu vyhnuli, můžete použít další globální proměnnou obsahující seznam ukazatelů na objekty dlaždic až do okamžiku, kdy mohou být smazány.

Zpracování nelineárních sekvencí reaktoru
  1. Přidejte k souboru gpreact.lsp následující funkci:
    2. (defun gp:erase-tiles (reactor / reactorData tiles tile)
      (if (setq reactorData (vlr-data reactor))
        (progn
          ;; Dlaždice v cestě jsou uloženy jako data do reaktoru.
          (setq tiles (cdr (assoc 100 reactorData)))
          ;; Smazání všech existujících dlaždic cesty.
          (foreach tile tiles
              (if (and (null (member tile *Safe-to-Delete*))
                     (not (vlax-erased-p tile))
                     )
                  (progn
                     (vla-put-visible tile 0)
                     (setq *Safe-to-Delete* (cons tile *Safe-to-Delete*))
                  )
              )
          )
          (vlr-data-set reactor nil)
          )
        )
      )

    Tato nová funkce bude sloužit v prvé řadě ke smazání dlaždic. Povšimněte si, že dlaždice ve skutečnosti nejsou vymazány: jsou jen nastaveny jako neviditelné a vloženy do globální proměnné pojmenované *Safe-to-Delete*.

  2. Přidejte k souboru gpreact.lsp následující funkci:
    3. (defun Gp:Safe-Delete (activeCommand)
      (if (not (equal
          (strcase (substr activeCommand 1 5))
            "GRIP_"
          )
      )
      (progn
         (if *Safe-to-Delete*
            (foreach Item *Safe-to-Delete*
              (if (not (vlax-erased-p Item))
                (vla-erase item)
              )
            )
          )
          (setq *Safe-to-Delete* nil)
          )
        )
      )

    Tato funkce může být vyvolána při neprovedení příkazu POSUN_NA_UZLY nebo PROTAŽENÍ_NA_UZLY.


Psaní kódu funkce command-ended

Dokončení operace
Dokončení operace
Psaní kódu funkce command-ended

Nyní, když jste si prohlédli pseudokód a prošli si některé důležité detaily, nahraďte zástupný kód ve zpětném volání reaktoru gp:command-ended tímto kódem:

(defun gp:command-ended (reactor command-list
             / objReactor
             reactorToChange reactorData
             coordinateValues currentPoints
             newReactorData newPts
             tileList
             )
  (cond
    ;; PODMÍNKA 1 - KŘIVKA SMAZÁNA (příkaz Vymaž)
    ;; Pokud je smazána jedna nebo více hraničních křivek (indikováno
    ;; přítomností *reactorsToRemove*), smažou se i dlaždice
    ;; v rámci dané hranice, potom je odstraněn i reaktor.
    (*reactorsToRemove*
     (foreach objReactor *reactorsToRemove*
       (gp:erase-tiles objReactor)
       )
     (setq *reactorsToRemove* nil)
     )
    ;; PODMÍNKA 2 - ZTRÁTA ASOCIATIVITY (Posun, Otoč atd.)
    ;; Pokud došlo ke ztrátě asociativity (příkazy Zpět, Posun atd.)
    ;; odstraňte dlaždice uvnitř každé hranice
    ;;
    ((and *lostassociativity* *reactorsToChange*)
     (foreach reactorToChange *reactorsToChange*
       (gp:erase-tiles reactorToChange)
       )
     (setq *reactorsToChange* nil)
     )
    ;; PODMÍNKA 3 - GRIP_STRETCH
    ;; V tomto případě je asociativita dlaždic a cesty
    ;; zachována, ale jak cestu, tak dlaždice bude nutné
    ;; přepočítat a překreslit. GRIP_STRETCH může být použit
    ;; současně pouze na jedné KŘIVCE.
    ((and (not *lostassociativity*)
      *polytochange*
      *reactorsToChange*
      (member "GRIP_STRETCH" command-list)
      ;; u GRIP_STRETCH bude použit pouze jeden reaktor
      ;; v globální proměnné *reactorsToChange*.
      (setq reactorData
         (vlr-data (setq reactorToChange
                  (car *reactorsToChange*)
                 )
               )
        )
      )
     ;; Nejdříve jsou smazány dlaždice v rámci hraniční křivky.
     (gp:erase-tiles reactorToChange)
     ;; Potom se získají aktuální hodnoty souřadnic vrcholů
     ;; vrcholy.
     (setq coordinateValues
        (vlax-safearray->list
          (vlax-variant-value
        (vla-get-coordinates *polyToChange*)
        )
          )
       )
     ;; Pokud je hranicí odlehčená křivka, máte
     ;; 2D body, takže je nutné použít pomůcku xyList->ListOfPoints
     ;; pro převedení dat souřadnic na seznam
     ;; ((x y) (x y) ...) Jinak se použije funkce
     ;; funkce xyzList->ListOfPoints
     ;; s 3D body, a převede data souřadnic
     ;; seznam bodů ((x y z) (x y z) ... ).
     (setq CurrentPoints
        (if (= (vla-get-ObjectName *polytochange*) "AcDbPolyline")
          (xyList->ListOfPoints coordinateValues)
          (xyzList->ListOfPoints coordinateValues)
          )
       )
     ;; Odeslání této nové informace funkci RedefinePolyBorder-- tím
     ;; bude vrácena nová hraniční křivka
     (setq NewReactorData
        (gp:RedefinePolyBorder CurrentPoints reactorData)
       )
     ;; Získání všech bodů hranice a ...
     (setq newpts (list (cdr (assoc 12 NewReactorData))
            (cdr (assoc 13 NewReactorData))
            (cdr (assoc 14 NewReactorData))
            (cdr (assoc 15 NewReactorData))
            )
       )
     ;; ...aktualizace obrysu křivky pomocí nových bodů
     ;; spočítaných výše. U odlehčené křivky
     ;; je nutné převést tyto body na 2D (jelikož všechny body v rámci
     ;; newpts jsou 3D), jinak se ponechají beze změny.
     (if (= (cdr (assoc 4 NewReactorData)) "LIGHT")
       (setq newpts (mapcar '(lambda (point)
                   (3dPoint->2dPoint Point)
                   )
                newpts
                )
         )
       )
     ;; Nyní proběhne aktualizace pomocí správných bodů.
     (vla-put-coordinates
      *polytochange*
     ;; Popis seznamu list->variantArray naleznete v souboru utils.lsp.
      (gp:list->variantArray (apply 'append newpts))
    )
     ;; Nyní použijte aktuální definici NewReactorData,
     ;; která je shodná s daty zahradní cesty
     ;; a jejich strukturou. Jedinou výjimkou je, že pole (100)
     ;; obsahující seznam dlaždic je rovno hodnotě nil. To je v pořádku, protože funkce
     ;; gp:Calculate-and-Draw-Tiles toto pole nepotřebují.
     ;; k nakreslení dlaždic. Ve skutečnosti tato funkce vytvoří dlaždice
     ;; a vrací seznam nakreslených dlaždic.
     (setq tileList (gp:Calculate-and-Draw-Tiles
              ;; data cesty bez správného seznamu dlaždic
              NewReactorData
              ;; Funkce pro tvorbu objektu
              ;; V rámci reaktoru se *MUSÍ* jednat o ActiveX
              gp:Calculate-and-Draw-Tiles
              )
       )
     ;; Nyní, když máte seznam všech nakreslených dlaždic, vytvořte
     ;; datovou strukturu se správnou hodnotou tileList
     ;; a resetujte vlastnost dat v reaktoru.
     ;; Aktualizujte dlaždice asociované s hraniční křivkou.
     (setq NewReactorData
        (subst (cons 100 tileList)
           (assoc 100 NewReactorData)
           NewReactorData
           )
       )
     ;; Nyní máte nová data asociovaná s křivkou.
     ;; Jediné, co zbývá, je asociovat je s reaktorem
     ;; pomocí funkce vlr-data-set.
     (vlr-data-set (car *reactorsToChange*) NewReactorData)
     ;; Odstranění všech odkazů na dočasné
     ;; proměnné *polytochange* a *reactorsToChange*.
     (setq *polytochange* nil
       *reactorsToChange* nil
       )
     )
    )
  ;; Pokud je to možné, vymažte veškeré položky v globální proměnné *Safe-to-Delete*!!
  (Gp:Safe-Delete (car command-list))
  (princ)
  )


Aktualizace funkce gp:Calculate-and-Draw-Tiles

Dokončení operace
Dokončení operace
Aktualizace funkce gp:Calculate-and-Draw-Tiles

Již dříve bylo v tomto cvičení zmíněno, že je nutné vynucením funkce gp:Calculate‑and‑Draw-Tiles použít ActiveX k tvorbě objektů při zpetném volání z reaktoru. To znamená přeprání stylu tvorby objektů (ActiveX, entmake nebo command) vybraných v případě potřeby uživatelem. Právě aktualizovaný kód ve funkci gp:command-ended obsahuje následující volání procedury kreslení dlaždice:

(setq tileList (gp:Calculate-and-Draw-Tiles
    ;; data cesty bez správného seznamu dlaždic
    NewReactorData
    ;; Funkce pro tvorbu objektu.
    ;; V rámci reaktoru se *MUSÍ* jednat o ActiveX.
    gp:Calculate-and-Draw-Tiles
   )
)

Dva parametry jsou přířazeny do gp:Calculate-and-Draw-Tiles: NewReactorData (což je seznam v podobě origináního seznamu asociací gp_PathData) a řetězec "ActiveX" (který nastavuje styl tvorby objektu). Podívejte se však na aktuální definici funkce gp:Calculate‑and‑Draw‑Tiles. (Pokud jste ji pozapomněli, naleznete ji v souboru gpdraw.lsp.) Zde je část funkce deklarující parametry a lokální proměnné.

(defun gp:Calculate-and-Draw-Tiles (BoundaryData /
     PathLength TileSpace
     TileRadius SpaceFilled
     SpaceToFill RowSpacing
     offsetFromCenter rowStartPoint
     pathWidth pathAngle
     ObjectCreationStyle TileList)

Povšimněte si, že jeden parametr je aktuálně zadán a proměnná ObjectCreationStyle je identifikována jako lokální proměnná. Podívejte o kousek dále, jak je proměnná ObjectCreationStyle nastavena:

(setq ObjectCreationStyle (strcase (cdr (assoc 3 BoundaryData))))

Proměnná ObjectCreationStyle je aktuálně interně nastavena v rámci funkce získáním hodnoty ukryté v proměnné BoundaryData (asociovaný seznam). Nyní je však třeba tuto hodnotu předefinovat.

Úprava funkce gp:Calculate-and-Draw-Tiles na přijmutí argumentu metody tvorby objektů
  1. Přidejte k argumentu funkce proměnnou ObjectCreationStyle.
  2. TileList) ; Odstranění proměnné ObjectCreationStyle z lokálních proměnných

    3. Příkaz defun dané funkce by nyní měl vypadat takto:

    (defun gp:Calculate-and-Draw-Tiles (BoundaryData
                             ObjectCreationStyle
        / PathLength TileSpace
          TileRadius SpaceFilled
          SpaceToFile RowSpacing
          offsetFromCenter rowStartPoint
          pathWidth pathAngle
          TileList) ; Odstranění proměnné ObjectCreationStyle z lokálních proměnných

    Povšimněte si, že když budete deklarovat proměnnou jako parametr (před lomítkem) i jako lokální proměnnou (za lomítkem), VLISP si toho povšimne. Pokud například zadáte ObjectCreationStyle jako parametr i proměnnou, potom pužijte nástroj pro kontrolu syntaxe VLISPu pro funkci gp:Calculate‑and‑Draw‑Tiles a v okně Výstup sestavení se zobrazí následující zpráva:

    ; *** UPOZORNĚNÍ: stejné symboly před a za / v seznamu argumentů: OBJECTCREATIONSTYLE
  3. Upravte první výraz setq ve funkci gp:Calculate-and-Draw-Tiles, aby vypadal následovně:
    4. (setq
       PathLength (cdr (assoc 41 BoundaryData))
       TileSpace (cdr (assoc 43 BoundaryData))
       TileRadius (cdr (assoc 42 BoundaryData))
       SpaceToFill (- PathLength TileRadius)
       RowSpacing (* (+ TileSpace (* TileRadius 2.0))
          (sin (Degrees->Radians 60))
       )
       SpaceFilled RowSpacing
       offsetFromCenter 0.0
       offsetDistance /(+(* TileRadius 2.0)TileSpace)2.0)
       rowStartPoint cdr (assoc 10 BoundaryData))
       pathWidth cdr (assoc 40 BoundaryData))
       pathAngle cdr (assoc 50 BoundaryData))
    ) ;_ konec setq
     (if (not ObjectCreationStyle)
       (setq ObjectCreationStyle (strcase (cdr (assoc 3 BoundaryData))))
    )

    Originální přiřazení příkazu pro ObjectCreationStyle bylo odstraněno. Kód nyní zkontroluje, zda byla pro ObjectCreationStyle zadána hodnota. Pokud není ObjectCreationStyle nastaven (to znamená, že hodnota je nil), funkce přiřadí hodnotu z proměnné BoundaryData.

    U funkce gp:Calculate‑and‑Draw-Tiles můžete provést jednu nebo více změn.


Úprava dalších volání funkce gp:Calculate-and-Draw-Tiles

Dokončení operace
Dokončení operace
Úprava dalších volání funkce gp:Calculate-and-Draw-Tiles

Ve zpětném volání reaktoru je řetězec pevného kódu "ActiveX" přiřazen k funkci gp:Calculate-and-Draw-Tiles jako argument ObjectCreationStyle. Ale co když je funkce gp:Calculate-and-Draw-Tiles volána jindy?

Pokud si vzpomínáte, ve cvičení 4 bylo řečeno, že při každé úpravě zástupné funkce byste si měli vždy položit tuto dvojici otázek:

  • Změnil se příkaz defun? Jinými slovy, zpracovává funkce stále stejný počet argumentů?
  • Vrací funkce něco jiného

Stejné otázky byste si měli položit při každé větší změně pracující funkce při vývoji, odladění a aktualizaci aplikací. V tomto případě je nutné nalézt všechny funkce v rámci projektu, které volají funkci gp:Calculate-and-Draw-Tiles. VLISP nabízí funkci, která vám tento úkol usnadní.

Nalezení volání funkce gp:Calculate-and-Draw-Tiles v rámci projektu
  1. V okně textového editoru VLISPu poklepejte na slovo gp:Calculate‑and-Draw-Tiles v souboru gpdraw.lsp.
  2. Z nabídky VLISPu vyberte položky Hledat [image] Najít.

    3. Jelikož jste název funkce již hledali, je již uveden jako cíl hledání.

  3. Stiskněte tlačítko Projekt v poli Hledání v dialogu Najít.

    4. Jakmile vyberete tuto volbu, dialog Najít se zvětší a můžete zadat název projektu, který chcete prohledat.

  4. Zadejte název aktuálního projektu a stiskněte tlačítko Najít.

    5. VLISP zobrazí výsledky v okně Výstup hledání:

  5. Podívejte se na výsledky v okně Výstup hledání a určete další výskyty volání funkce gp:Calculate‑and‑Draw-Tiles. Měla by se tam nacházet pouze jedna: v rámci souboru gpmain.lsp.
  6. V okně Výstup hledání poklepejte na řádek kódu volání gp:Calculate‑and‑Draw-Tiles.

    7. VLISP aktivuje okno textového editoru a zobrazí příslušný řádek kódu v souboru gpmain.lsp. Tento kód vypadá takto:

    (setq tilelist (gp:Calculate-and-Draw-Tiles gp_PathData))
  7. Nahraďte daný řádek následujícím kódem:
    8. (setq tilelist (gp:Calculate-and-Draw-Tiles gp_PathData nil))

    Proč? Podívejte se ještě jednou na pseudokód:

    Pokud je proměnná ObjectCreationStyle rovna nil, bude použito přiřazení pomocí BoundaryData.

    Předáním hodnoty nil jako parametru funkci gp:Calculate-and-Draw-Tiles způsobí, že funkce zkontroluje uživatelovu volbu metody tvorby dlaždic (zadanou v dialogu a uloženou v proměnné gp_PathData). Následující zpětná volání reaktoru command-ended však tuto hodnotu předefinují vynucením použití metody ActiveX.

Blahopřejeme! Máte za sebou základní nastavení funkcí reaktorů. Pokud chcete, zkopírujte si soubor gpmain.lsp a gpdraw.lsp z adresáře Tutorial\VisualLISP\Lesson7 do pracovního adresáře a prohlédněte si celý odladěný kód.

Ještě stále je před vámi spousta práce, přičemž vše se bude točit kolem fragmentu kódu v rámci funkce gp:Command-endedfunction:

(setq NewReactorData
    (gp:RedefinePolyBorder CurrentPoints reactorData)
) ;_ konec setq


Předefinování hraniční křivky

Dokončení operace
Dokončení operace
Předefinování hraniční křivky

Než jste došli až sem, odvedli jste kus práce a pravděpodobně již máte dost nových principů, termínů, příkazů a imperativů. Bude proto lepší, když si zkopírujete hotový vzorový kód cvičení místo toho, abyste jej celý psali.

Zkopírování kódu použitého k předefinování hraniční křivky
  1. Zkopírujte soubor gppoly.lsp z adresáře Tutorial\VisualLISP\Lesson7 do svého pracovního adresáře.
  2. V okně svého projektu klepněte na tlačítko Vlastnosti projektu.
  3. Přidejte soubor gppoly.lsp do projektu.
  4. Klepnutím na tlačítko OK potvrďte přidání souboru do projektu.
  5. V okně projektu poklepáním otevřete soubor gppoly.lsp.

Témata v této části:

  • Prohlídka funkcí v souboru gppoly.lsp
  • Tvorba funkce gp:RedefinePolyBorder
  • Funkce gp:FindMovedPoint
  • Funkce gp:FindPointInList
  • Funkce gp:recalcPolyCorners
  • Funkce gp:pointEqual, gp:rtos2 a gp:zeroSmallNum


Prohlídka funkcí v souboru gppoly.lsp

Dokončení operace
Dokončení operace
Prohlídka funkcí v souboru gppoly.lsp

Soubor gppoly.lsp obsahuje množství funkcí nutných k napřímení křivky při posunutí jediného uzlu. Podrobně budou vysvětleny pouze některé z nich.

Poznámka Tato část cvičení zahradní cesty obsahuje nejsložitější kódy a principy z celého cvičení. Jste-li začátečník, můžete přeskočit rovnou na část Vytvoření aplikace.

Funkce v souboru gppoly.lsp jsou uspořádány způsobem běžným v jiných zdrojových souborech AutoLISPu. Funkce nejvyšší úrovně, často hlavní, nebo funkce C: (v tomto případě gp:Redefine-PolyBorder), je umístěna v souboru dole. Funkce volané v rámci hlavní funkce jsou definovány nad ní ve zdrojovém kódu. Tato konvence pochází ještě z dřívějších časů, kdy některá vývojářská prostředí vyžadovala takovéto uspořádání. Ve VLISPu se jedná o věc osobního stylu; pořadí funkcí není nijak definováno ani vyžadováno.

Před podrobným rozborem se nejprve podívejte na to, co je třeba provést při přepočítání a překreslení hraniční křivky. Na následujícím obrázku je zahradní cesta spolu s klíčovými body asociovaného seznamu uloženými v reaktoru:

V tomto příkladu je klíčový bod 12 levý dolní roh, 13 je pravý dolní roh atd. Pokud uživatel posune pravý horní roh (klíčový bod 14), program bude muset přepočítat dva existující body - pravý dolní (13) a levý horní (15).


Tvorba funkce gp:RedefinePolyBorder

Dokončení operace
Dokončení operace
Tvorba funkce gp:RedefinePolyBorder

Následující pseudokód shrnuje nejdůležitější principy hlavní funkce gp:RedefinePolyBorder:

Funkce gp:RedefinePolyBorder
   Extrahujte předchozí rohové body křivky (12, 13, 14, a 15
     jako klíčové hodnoty).
   Nalezení posunutého rohového bodu srovnáním původních
     a aktuálních rohových bodů
     (Bod, který "nebude odpovídat" je posunutý roh)
   Nastavení nových rohových bodů přepočítáním dvou bodů
     přilehlých k posunutému bodu
   Aktualizace nových rohových bodů v údajích reaktoru (které budou uloženy zpět do
     reaktoru pro upravenou křivku)
   Aktualizace dalších informací v reaktoru. (Počáteční bod,
      šířku a délku cesty.)


Funkce gp:FindMovedPoint

Dokončení operace
Dokončení operace
Funkce gp:FindMovedPoint

Funkce gp:FindMovedPoint obsahuje některé výkonné výrazy LISPu pro manipulaci se seznamy. Tato funkce v podstatě srovnává seznam aktuálních bodů křivky (potom, co uživatel přetáhl jeden z nich do nové pozice) se seznamem původních bodů a vrací seznam s klíči (13 ) pro posunutý bod.

Nejlépe pochopíte činnost této funkce tak, že si projdete její kód a budete sledovat hodnoty, s nimiž manipuluje. Nastavte bod přerušení na první výraz (setq result . . .) a sledujte při procházení kódem následující proměnné:

  • KeyListToLookFor
  • PresentPoints
  • KeyedList
  • Result
  • KeyListStatus
  • MissingKey
  • MovedPoint

Funkce mapcar a lambda budou prozkoumány v další části. Nyní však sledujte komentáře v kódu a zkuste pochopit, co se děje v rámci těchto funkcí.


Funkce gp:FindPointInList

Dokončení operace
Dokončení operace
Funkce gp:FindPointInList

Záhlaví funkce ve zdrojovém kódu vysvětluje, jak funkce gp:FindPointInList převádí dané údaje. Podobně jako funkce Gp:FindMovedPoint, používá tato funkce schopnosti LISPu pro manipulaci se seznamy. Při práci se seznamy často uvidíte funkce mapcar a lambda použité společně tak jako zde. Nejprve se vám budou zdát podivné a matoucí (navíc jejich názvy nevypovídají nic o jejich účelu). Až se je však naučíte používat, zjistíte, že jsou to jedny z nejvýkonnějších funkcí AutoLISPu vůbec. Následuje krátký seznam známějších publikací o LISPu a AutoLISPu.

Funkce mapcar použije (mapuje) výraz na každou položku v seznamu. Pokud jí například zadáte seznam celých čísel 1, 2, 3 a 4, funkce mapcar může na tato čísla použít výraz 1+ a zvýšit každé číslo v seznamu o 1:

_$ (mapcar '1+ '(1 2 3 4))

(2 3 4 5)

Základní definice funkce mapcar je, že tato funkce použije funkci danou prvním parametrem na následující položky v druhém parametru - seznamu. Výsledná hodnota operace mapcar je seznam změněný pomocí použitého výrazu či funkce. (Funkce mapcar toho umí ještě více, ale tato definice nám zatím postačí.)

V uvedeném příkladu byla každá z hodnot seznamu '(1 2 3 4) předána funkci 1+. V podstatě tedy funkce mapcar provedla s hodnotami seznamu následující operace:

(1+ 1) -> 2
(1+ 2) -> 3
(1+ 3) -> 4
(1+ 4) -> 5

Zde je další příklad použití funkce mapcar, tentokrát se pomocí funkce null zjišťuje, zda hodnoty v seznamu jsou rovny hodnotě null (tedy ne true):

_$ (mapcar 'null (list 1 (= 3 "3") nil "Steve"))

(nil T T nil)

V kódu proběhlo toto:

(null 1) -> nil
(null (= 3 "3") -> T
(null nil) -> T
(null "Steve") -> nil

V rámci funkce mapcar můžete použít mnoho existujícících funkcí AutoLISPu. Je možné použít i vlastní funkce. Představte si například, že jste právě vytvořili velmi výkonnou funkci s názvem equals2:

_$ (defun equals2(num)(= num 2))

EQUALS2
_$ (mapcar 'equals2 '(1 2 3 4))

(nil T nil nil)

Dobře, funkce equals2 není zase až tak výkonná. Je však užitečná spolu s funkcí lambda. Funkci lambda je možné použít v situacích, kdy nechcete nebo nepotřebujete procházet celým definováním funkce. Někdy uvidíte funkci lambda definovanou jako anonymní funkci. Například místo definování funkce s názvem equals2 byste mohli napsat výraz lambda, který provede stejnou operaci bez nutnosti definice funkce:

_$ (mapcar '(lambda (num) (= num 2)) '(1 2 3 4))

(nil T nil nil)

V kódu proběhlo toto:

(= 1 2) -> nil
(= 2 2) -> T
(= 3 2) -> nil
(= 4 2) -> nil

S novými poznatky se nyní podívejte znovu na funkci gp:FindPointInList. Znovu si projděte komentáře v rámci zdrojového kódu.


Funkce gp:recalcPolyCorners

Dokončení operace
Dokončení operace
Funkce gp:recalcPolyCorners

Klíčem k pochopení činnosti funkce gp:recalcPolyCorners je podívat se znovu na diagram a uvědomit si, co představují klíčové hodnoty 12 až 15:

V diagramu uživatel posunul rohový bod asociovaný s klíčovou hodnotou 14. To znamená, že je třeba přepočítat rohové body asociované s klíčovými hodnotami 13 a 15.

Bod 15 je třeba posunout podél aktuálního vektoru linie bodu 12 a bodu 15 tak daleko, až bude zarovnán s novým bodem 14. Vektory ve směru od bodu 12 do bodu 15 a od bodu 14 do bodu 15 musí být k sobě navzájem kolmé. Stejnou operaci je třeba použít k přepočítání nové pozice bodu 13.

Nyní se podívejte znovu na kód, zda vám již dává smysl.


Funkce gp:pointEqual, gp:rtos2 a gp:zeroSmallNum

Dokončení operace
Dokončení operace
Funkce gp:pointEqual, gp:rtos2 a gp:zeroSmallNum

Tyto tři funkce usnadňují programování v programu AutoCAD, který, jak jistě víte, umožňuje použití vysoké přesnosti. Někdy však (díky použití zaokrouhlování hodnot s pohyblivou desetinnou čárkou definujících geometrické pozice) nejsou čísla dost přesná. Občas je nutné srovnat mezi sebou dvě množiny bodů, proto je třeba tento problém vyřešit.

Všimli jste si někdy, že při výpisu informací asociovaných s entitiou programu AutoCAD se zobrazí hodnota typu 1.0e-017? Toto číslo je téměř nula, ale při srovnání s nulovou hodnotou v rámci programu LISPu není žádné téměř přípustné.

V rámci zahradní cesty je třeba srovnávat čísla a nezabývat se faktem, že hodnota 1.0e-017 není zcela rovna nule. Funkce gp:pointEqual, gp:rtos2 a gp:zeroSmallNum umí při srovnávání seznamů bodů zpracovat veškeré nepřesnosti vzniklé zaokrouhlováním.

Tím končí přehlídky funkcí v souboru gppoly.lsp.


Shrnutí hotového kódu

Dokončení operace
Dokončení operace
Shrnutí hotového kódu

Zatím jste v tomto cvičení provedli následující:

  • Upravili jste funkci gp:drawOutline tak, aby vracela kromě ukazatele na křivku i obvodové body křivky. Tyto údaje jste přidali do proměnné gp_PathData. Tato proměnná je uložena spolu s údaji reaktoru v reaktoru objektu připojeném ke každé zahradní cestě.
  • Aktualizovali funkce reaktoru v souboru gpreact.lsp.
  • Přidali funkce xyzList->ListOfPoints, xyList‑>ListOfPoints a další pomůcky do souboru utils.lsp.
  • Aktualizovali funkci gp:Calculate-and-Draw-Tiles takovým způsobem, že ObjectCreationStyle je nyní spíše parametrem než lokální proměnnou.
  • Upravili volání gp:Calculate-and-Draw-Tiles ve funkc C:GPath v souboru gpmain.lsp.
  • Přidali soubor gppoly.lsp do svého projektu a prozkoumali funkce v něm uvedené.

Nyní můžete hotovou aplikaci vyzkoušet. Uložte svou práci, načtěte zdrojové soubory projektu, spusťte funkci Gpath a zkuste protáhnout a posunout hraniční křivku zahradní cesty. Nezapomeňte: pokud něco nefunguje a vám se nepodaří chyby odladit, můžete si načíst hotový kód z adresáře Tutorial\VisualLISP\Lesson7.


Vytvoření aplikace

Dokončení operace
Dokončení operace
Vytvoření aplikace

Posledním úkolem v tomto cvičení je vytvořit z hotového kódu zahradní cesty samostatnou aplikaci. Jako aplikace potom bude moci být distribuována libovolnému uživateli či zákazníkovi v podobě jediného spustitelného souboru. Naštěstí je tento poslední úkol asi nejsnadnější z celého cvičení, protože VLISP provede prakticky vše za vás.

Poznámka Je doporučeno, abyste převedli kód na aplikaci pouze v případě, že správně funguje. Otestujte si svou aplikaci s využitím původních zdrojových souborů a pokračujte teprve, až budete s výsledky spokojeni.

Témata v této části:

  • Spuštění průvodce Vytvořit aplikaci


Spuštění průvodce Vytvořit aplikaci

VLISP nabízí při sestavování samostatné aplikace průvodce Vytvořit aplikaci.

Spuštění průvodce Vytvořit aplikaci
  1. Průvodce spustíte tím, že z nabídky VLISPu vyberete položky Soubor [image] Vytvořit aplikaci [image] Průvodce novou aplikací.
  2. Vyberte volbu Režim expert a stiskněte tlačítko Další.

    3. Průvodce požádá o zadání adresáře, kam budou uloženy vytvořené soubory, a názvu aplikace. Funkce Vytvořit aplikaci vytvoří dva výstupní soubory: souborSoubor vlx obsahující váš program a soubor.soubor prv s volbami zadanými ve funkci Vytvořit aplikaci. .Soubor prv je také znám jako soubor make. Tento soubor můžete v případě potřeby použít k novému sestavení své aplikace.

  3. Zadejte jako umístění aplikace svůj adresář Tutorial\VisualLISP\MyPath a pojmenujte aplikaci gardenpath. VLISP použije název aplikace pro názvy výstupních souborů (v tomto případě gardenpath.vlx a gardenpath.prv.)

    4. Pokračujte stiskem tlačítka Další.

  4. Volby aplikace nejsou v tomto cvičení rozebírány. Potvrďte výchozí hodnoty a stiskněte tlačítko Další. (Více informací o samostatných aplikacích prostoru názvů naleznete v části “Running an Application in Its Own Namespace” v dokumentaci AutoLISP Developer’s Guide.)
  5. V tomto kroku průvodce požádá o zadání všech zdrojových souborů AutoLISPu, z nichž se vytvářená aplikace skládá. Můžete jednotlivě vybrat zdrojové soubory LISPu, ale existuje i jednodušší způsob. Změňte typ souboru v rozbalovacím seznamu na „Soubory projektu Visual LISP“ a potom stiskněte tlačítko Přidat. Vyberte projektový soubor Gpath a stiskněte tlačítko Otevřít.

    6. Poznámka Může se stát, že se zobrazí několik projektových souborů Gpath. Vyberte nejpozději uložený soubor. Pokud jste si zkopírovali hotový kód ze cvičení 7, měli byste vybrat soubor s názvem Gpath7.prj.

    Po vybrání souboru projektu pokračujte stiskem tlačítka Další.

    Jedna výhoda zkompilované aplikace VLX je ta, že můžete do kompletní aplikace zkompilovat vaše řídící soubory dialogu (.dcl) do hotové aplikace. Tím se sníží počet jednotlivých zdrojových souborů, s nimiž budou koncoví uživatelé muset pracovat, a odstraní se problémy s prohledávací cestou při načítání souboru DCL.

  6. Změňte typ souboru v roletovém seznamu na „DCL soubory“ a potom tiskněte tlačítko Přidat. Vyberte soubor gpdialog.dcl a potom stiskněte tlačítko Otevřít.

    7. Pokračujte v tvorbě aplikace stiskem tlačítka Další.

  7. Volby kompilace nejsou v tomto cvičení rozebírány. Potvrďte výchozí hodnoty a stiskněte tlačítko Další. (Více informací o volbách kompilace nabízí část “Optimizing Application Code” v dokumentaci AutoLISP Developer’s Guide.)
  8. Posledním krokem je prohlédnout si provedená nastavení. V tomto bodě můžete stisknout tlačítko Dokončit. VLISP zahájí proces kompilace a zobrazí výsledky v okně Výstup sestavení. Při převodu jednotlivých zdrojových souborů do formátu připojitelného k jediné aplikaci VLX bude vytvořeno několik přechodných souborů.

Až budete hotovi, získáte spustitelný soubor s názvem gardenpath.vlx. Otestujte jej následovně:

  • Z nabídky Nástroje v AutoCAD vyberte položku Načíst aplikaci.
  • Načtěte nově vytvořenou aplikaci gardenpath.vlx z adresáře Tutorial\VisualLISP\ MyPath.
  • příkaz Soubor.


Shrnutí celého cvičení

Dokončení operace
Dokončení operace
Shrnutí celého cvičení

Právě jste dospěli na konec cvičení zahradní cesty! Jak jste sami poznali, toto cvičení prezentovalo velké množství nové látky. Poznali jste principy a operace AutoLISPu i VLISPu. Cílem cvičení bylo nabídnout přehled množství témat a principů. Možná, že budete mít zájem ještě o další informace. Následuje krátký seznam známějších publikací o LISPu a AutoLISPu.


Publikace o LISPu a AutoLISPu

Dokončení operace
Dokončení operace
Publikace o LISPu a AutoLISPu

Výklad AutoLISPu: Programování pro produktivitu, William Kramer, Autodesk Press, ISBN 0-8273-5832-6.

AutoLISP obyčejným jazykem: Praktický průvodce pro neprogramátory, George O. Head, Ventana Press, ISBN: 1566041406.

LISP, 3. vydání, Patrick Henry Winston a Berthold Klaus Paul Horn, Addison-Wesley Publishing Company, ISBN 0-201-08319-1.

ANSI Common Lisp, Paul Graham, Prentice Hall, ISBN 0-13-370875-6.

Steele, Jr., Digital Press, ISBN 1-55558-041-6.


Comments?

Using this form sends your comments to the Autodesk Technical Publications group responsible for this documentation.

Topic title and location (do not edit):
Name (optional):
         Email (optional):
Comments:

Note: This form is not intended as a way for you to receive feedback or technical support. The information you provide will be used to enhance future updates to the documentation. Thanks!