Nawet najprostsze rzeczy można skomplikować, tak też jest w LISPie. Prostą kreskę można narysować na trzy sposoby, każdy z nich ma swoje wady, niektóre mają nawet zalety. A sposoby są następujące:
Używanie funkcji command jest najprostszym sposobem tworzenia obiektów. Nazwę funcji wpisujemy command, następnie nazwę polecenia ZWCADa np. "_LINE" a dalej parametry typowe dla wywołanego polecenia ZWCADa, w przykładzie linii, jako kolejne parametry wpisujemy współrzędne punktów jako listy, żeby zakończyć polecenie konieczne jest dodanie na końcu pustego tekstu co będzie równoznaczne z naciśnięciem [ENTER] czyli zakończeniem działania funkcji.
W podobny sposób możemy utworzyć np. warstwę
Na przykładzie tym zobaczyć możemy, że command może zawierać całą sekwencję czynności, tutaj wywołane jest polecenie -layer, a kolejne wywoływane opcje powodują:
"n" - utworzenie nowej warstwy, po czym wpisujemy nazwę naszej nowej warstwy
"c" - kolor warstwy, której nazwę podajemy dalej
"s" - ustawia jako aktualną warstwę, której nazwę podajemy po opcji s
"" - konieczne jest jeszcze tylko zamknięcie polecenia, i nasza warstwa jest utworzona i ustawiona jako aktualna
Jak już wspomniałem, każde rozwiązanie ma swoje wady i zalety, wśród zalet tworzenia elementów przez command wyróżnić należy prostotę tego rozwiązania. Jeśli znamy polecenia ZWCADa, nie ma problemu, z tworzeniem funkcji automatyzującej rysowanie.
Wadą tego rozwiązania jest brak kontroli nad tym co się dzieje w czasie wykonywania skryptu. Command zawsze zwraca nil, niezależnie od tego, czy uda się poprawnie wykonać polecenie, czy nie. Dodatkowo, w historii poleceń wyświetlane są wszystkie polecenia, które się wykonuje, co w pewnym sensie ujawnia strukturę naszego programu, a to prowokuje do dłubania w naszym kodzie osoby, które niekoniecznie powinny to robić.
W AutoLISP tworzenie elementów możemy przy użyciu funkcji entmake. jest bardziej skomplikowane od skryptów z użyciem poleceń, ale daje nam też większe możliwości. Spowodowane jest to tym, że używając tych mechanizmów mamy dostęp bezpośrednio do bazy danych rysunku. Każdy rysunek ma własną bazę danych zawierających narysowane elementy, warstwy, bloki, dane dodatkowe.
Drugą ważną zaletą entmake jest możliwość kontroli tego co się stanie. Jeśli polecenie się powiedzie, entmake zwróci listę definicji dla danego elementu, jeśli z jakichś przyczyn (najczęściej błędu programisty) nie uda się utworzyć takiego elementu, entmake zwróci nil.
Kod rysujący prostą linię wygląda następująco:
Efekt będzie równoważny naszemu przykładowi z tworzeniem takiej samej linii przez command. Entmake, daje nam o tyle większe możliwości, że można już teraz ustawić kolor, warstwę, typ linii, i wszystkie inne właściwości. Czego nie daje nam command.
Używając funkcji command musielibyśmy ustawić aktualną warstwę, aktualny styl linii, kolor, grubość linii itp. a entmeke, proszę bardzo:
Małe przypomnienie: Tworząc listę definicji możemy używać dwu sposobów konstruowania list asocjacyjnych: przez '(x . y) lub (cons x y). Różnica taka, że w przypadku cons, y może być zmienną, przy '(x .y) y musi być stałą wartością.
W powyższym przykładzie widzimy, że już w momencie utworzenia elementu możemy ustawić wszystkie własności. Warto wspomnieć, że warstwa, na której zostanie utworzony element w przypadku entmake nie musi być warstwą aktualną. A już bezczelnością jest utworzenie linii i ustawienie jej jako niewidocznej '(60 . 1) . Po co? np. po to, żeby posłużyć się nią jako linią pomocniczą z której można odczytać np. punkty styczności czy przecięcia, a zaraz potem ją usunąć, użytkownik naszej nakładki nie musi być świadomy wszystkiego co dzieje się w programie, jeszcze by się przestraszył.
Rodzi się pytanie "Skąd mam wiedzieć jaki numerek (kod DXF) na ta właściwość, którą chcę ustawić?" Pomoc ZWCAD nie ma tego rozpisanego, jedno takie oprogramowanie podobne do ZWCADa to ma, ale nie powiem jakie :). Może interesujące dla kogoś będą inne przykłady. Linia już była, więc kolejno:
Oczywiście można też dopisywać inne własności, warstwy, kolory itp. powyżej tylko to, co jest niezbędne do utworzenia okręgu
Jeśli ktoś ma jeszcze wątpliwości po co są listy, to teraz jest to najłatwiej wyjaśnić. W powyższym przykładzie wpisaliśmy stałe wartości narożników naszej polilinii. A może warto byłoby zrobić listę w której użytkownik wskazywałby cztery punkty i na ich podstawie tworzona byłaby polilinia. Wyglądałoby to tak:
Jeśli to jeszcze nie jest dość skomplikowane, to dodam, że nie tylko istotne jest który numer DXF oznacza jaką własność, ale jeszcze istna jest sekwencja ich ułożenia. po 10 po 72 to początek krawędzi, a 10 po 98 to współrzędne punktu wewnątrz pętli.
Przykład z kreskowaniem w kształcie kółka już jest, to dodam jeszcze przykład z trójkątem:
Funkcja entlast zwraca ostatnio utworzony obiekt, powinno nam zwrócić coś podobnego do:
<Entity name: 8838d90>
Jest to nazwa obiektu, na którym możemy dokonywać modyfikacji. Jednak aby te modyfikacje odniosły skutek, potrzebna jest nam pełna lista definicji, ją możemy odczytać z obiektu przez entget. nasz przykładowy entget zwróci nam:
((-1 . <Entity name: 8838d90>) (0 . "LINE") (5 . "144") (67 . 0) (8 . "0") (410 . "Model") (62 . 256) (6 . "ByLayer") (370 . -1) (48 . 1.00000) (60 . 0) (39 . 0.000000) (10 0.000000 0.000000 0.000000) (11 10.0000 10.0000 10.0000) (210 0.000000 0.000000 1.00000))
W kolejnym kroku zamieniamy elementy wewnątrz listy definicji.
(setq Ost_Popr_List (subst (cons 10 (list 0 20 0)) (assoc 10 Ost_List) Ost_List))
czytając kod LISP należy robić to od prawej strony do lewej, więc w kolejności wykonywało się będzie
(assoc 10 Ost_List) ; zwróci nam pierwsze wystąpienie 10 w liście definicji linii
(cons 10 (list 0 20 0)) ; utworzy nam listę asocjacyjną (10 0 20 0)
(subst X Y Lista) ; Podmienia w Liście jedną wartość na inną, tutaj wystąpienie Y zostanie zastąpnione przez Y
czyli zwróci nam ((-1 . <Entity name: 8838d90>) (0 . "LINE") (5 . "144") (67 . 0) (8 . "0") (410 . "Model") (62 . 256) (6 . "ByLayer") (370 . -1) (48 . 1.00000) (60 . 0) (39 . 0.000000) (10 0 20 0) (11 10.0000 10.0000 10.0000) (210 0.000000 0.000000 1.00000))
Pozostaje nam jedynie aktualizować zmieniony obiekt, co robimy przy użyciu funkcji entmod a jej parametrem będzie zaktualizowana lista definicji obiektu.
Warto jeszcze dodać na koniec, że aktualizowanie obiektu nie musi być wykonane po każdej zmianie właściwości, czyli możemy pobrać definicję, zmienić w niej wiele właściwości, a na koniec raz aktualizować obiekt przez entmod.
Ostatnią kwestią w zakresie tworzenia i modyfikowania obiektów jest wskazywanie elementów do zmiany. W poprzednim przykładzie posługiwaliśmy się ostatnio utworzonym obiektem. Modyfikacje można też wykonywać na dowolnym obiekcie, który wskaże użytkownik. Pomocna jest nam w tym funkcja (entsel)
No i dotarliśmy do tego, co można nazwać programowaniem, a w zasadzie programowaniem obiektowym.
Moim zdaniem jest to łatwiejsze niż używanie entmake. Nie wymaga uczenia się żadnych dziwnych numerów kodów, wystarczy wiedzieć czego się chce.
w ZWCAD VisualLISP jest dostępne od dawna, jednak w ograniczonym zakresie. W wersji 2010 dokonano znacznych zmian z tym zakresie i można już powiedzieć, że działa to w sposób zadowalający.
Zaczniemy może od najprostszej funkcji rysującej prostą kreskę:
(vl-load-com) - wczytuje do przestrzeni pamięci ZWCADa, funkcje pozwalające na programowanie obiektowe
(setq *ZCApp* (vlax-get-zwcad-object )) - pobiera obiekt ZWCADa jest to konieczne, jest to główny obiekt aplikacji i na nim wykonujemy wszystkie kolejne operacje. Przypisujemy ten obiekt do zmiennej globalnej *ZCApp*
(setq *ActiveDocment* (vla-get-activedocument *ZCApp*)) pobiera aktywny dokument z aplikacji i przypisuje do zmiennej *ActiveDocment*
(setq *MSpace* (vla-get-modelspace *ActiveDocment*)) pobiera przestrzeń modelu z aktywnego dokumentu-rysunku.
Już na tak prostych operacjach możemy zobaczyć pewną prawidłowość: żeby odczytać jakąś własność, lub obiekt z innego obiektu, możemy to zrobić, używając funkcji:
vla-get-... gdzie vla lub vlax to przedrostek wszystkich funkcji VisualLISP. get używamy, gdy chcemy odczytać informacje z obiektu. Gdy chcemy coś zapisać, używamy vla-put . Jeśli chcemy uruchomić funkcje będącą metodą obiektu używamy vlax-invoke-method
W całym programowaniu obiektowym czyli VisualLISP, potrzebna jest znajomość jedynie około 10 funkcji i angielskie nazwy właściwości i metod obiektów. W tym zakresie dokumentacja ZWCADa jest moim zdaniem wystarczająco obszerna. Funkcje, które musimy poznać to:
Praktycznie to wygląda tak:
vlax-invoke-method Object 'Metoda często można zamienić przez vla-Metoda Object jak w naszym przykładzie (vlax-invoke-method *MSpace* 'addLine...) i vla-addLine. Ma to na celu ułatwienie pracy programistom i nie ma wpływu na działanie. Moim zdaniem to jest przede wszystkim kwestia przyzwyczajenia.
Pojawiła się tu jedna nowa funkcja: vlax-3d-point jej zadaniem jest zamiana listy współrzędnych na variant. Jest to wymuszone przez funkcje addLine, która wymaga, żeby współrzędne podawane były jako variant.
Copyright © 2000—2010 by
Usługi Informatyczne SZANSA - Gabriela Ciszyńska-Matuszek.
Autoryzowany Dystrybutor programu ZWCAD w Polsce od 2005 roku.
Wszelkie prawa zastrzeżone.