AutoCAD, AutoLISP

Obiekty nazwane

O nazwach, czyli co wolno a czego nie wolno używać w nazwach obiektów. Z pewnością nie raz, mogliście spotkać się z takim (nieco smutnym) komunikatem Menedżera warstw, zabijającym wasze mozolne (i niewątpliwie kreatywne) starania w celu utworzenia tej jedynej niepowtarzalnej nazwy warstwy… 😉

O nazwanych (autocad-owych)  obiektach pisałem już TUTAJ, a o pewnych możliwościach ich zmiany także – TUTAJ. Dziś chcę przybliżyć nieco problemy związane z podaniem poprawnej nazwy w LISP-ie. O ile bowiem, ręczne działania użytkownika skutkują wyświetlaniem odpowiednich (jak powyżej) komunikatów, to działania w (dowolnym) API, z niedopuszczalną nazwą, powodują zawsze błąd programu. Ponieważ (zaś) nadrzędnym zadaniem programującego jest zapewnienie poprawnego działania programu w możliwie najszerszym zakresie, ważnym jest przewidywanie potencjalnych błędów i zapobieganie im, już na najniższym poziomie.

Obecnie (od wersji AutoCAD 2000 (1999)) w nazwach symboli nazwanych niedopuszczalne są znaki:

Oczywiście AutoCAD zapewnia pełną zgodność z wcześniejszymi, wprowadzając odpowiednią zmienną systemową:

W AutoLISP istnieje funkcja o nazwie snvalid, która  pozwala sprawdzić czy nazwa określona jako jej argument, jest dopuszczalną nazwą symbolu. W niektórych jednak sytuacjach, okazuje się to niewystarczające. Stąd też zdefiniowałem swoją LISP-ową funkcję którą wywołuję w kodzie, gdy snvalid, zwraca wartość NIL. W tym przypadku, funkcja jk:STR_SNValid, dokonuje „naprawy” nazwy (argument Str) , zastępując wszystkie wystąpienia znaków niedopuszczalnych, znakiem określonym jako argument Nst. Funkcja wygląda tak:


;;; --------------------------------------------------------------- ;;;
;;; jk:STR_SNValid - kojacek 2018                                   ;;;
;;; --------------------------------------------------------------- ;;;
(defun jk:STR_SNValid (Str Nst / p)
  (setq p  (list 34 42 44 47 58 59 60 61 62 63 96 92 124))
  (while p
    (setq Str (vl-string-translate (chr (car p)) Nst Str)
          p (cdr p)
    )
  )
  Str
)
;;; --------------------------------------------------------------- ;;;

Przykładowe wywołanie (i wynik działania) ilustruje obraz:

Potrzeba napisania tej funkcji powstała w wyniku użycia pewnego (doskonałego zresztą) programu zmieniającego wstawienie bloku dynamicznego na odpowiadający mu graficznie blok statyczny. Program ów, jako część nowej nazwy bloku przyjmował opis jego stanu widoczności. W niektórych blokach opis ten zawierał znaki, które są niedopuszczalne, w nazwie bloku, w konsekwencji czego, program generował błąd. Użycie funkcji jk:STR_SNValid, skutecznie wyeliminowało przyczynę powstawania błędu, i odtąd program działa bez zakłóceń.

. . . )

Reklamy
AutoLISP

WeldLine

Pomysł na zastosowanie złożonego rodzaju linii jako linii symbolizującej oznaczenie spoiny, zrodził się (i był zrealizowany) już wiele lat temu. Teraz (od czasu do czasu) znów się przydaje, już w nieco unowocześnionej i odmłodzonej formie, w zupełnie innym miejscu…

Mechanizm dynamicznego tworzenia złożonego rodzaju linii, jeśli nie istnieje on w rysunku, opisywałem już przy okazji rysowania izolacji.  W identyczny sposób postępuję również w tym przypadku, różnicą jest jedynie definicja rodzaju linii. W przeciwieństwie do linii izolacji, gdzie wykorzystywany jest symbol, tutaj elementem linii jest tekst. To powoduje potrzebę również dynamicznego utworzenia stylu tekstu, przed wczytaniem definicji linii. Wszystkie te działania odbywają się „w locie”, co czyni to narzędzie prostym i wydajnym w użyciu,  ograniczając działanie rysującego do niezbędnego minimum. A o to przecież w cad-owskich zabawach właśnie chodzi 😉 …

Stosunkowo krótki (dzięki CADPL-Pack‚owej optymalizacji) przedstawiam poniżej:


;;; --------------------------------------------------------------- ;;;
;;; WeldLine.lsp                                                    ;;;
;;; by kojacek 2000, 2018                                           ;;;
;;; --------------------------------------------------------------- ;;;
(setq *jk-WELD* 3.0)
;;; --------------------------------------------------------------- ;;;
(defun C:WELDLINE ()(jk:StdSteel-WeldLine)(princ))
;;; --------------------------------------------------------------- ;;;
(defun jk:StdSteel-WeldLine (/ -%l s e l p c f o)
  (defun -%l (/ l f s c)
    (if
      (not (tblobjname "LTYPE" "WeldLine"))
      (progn
        (if
          (not (tblobjname "STYLE" "Std-Weld-Symbol"))
          (progn
            (setq s (cd:ACX_AddTextStyle "Std-Weld-Symbol"))
            (if
              (setq c (findfile "simplex.shx"))
              (progn
                (vla-put-Fontfile s c)
                (vla-put-Height s 0.0)
              )
            )
          )
        )
        (setq l
          (list
            "*WeldLine,Weld Line ((((((((((((((("
            (strcat
              "A,0,-0.2,[\"(\",Std-Weld-Symbol,S=0.65,"
              "R=0.0,X=0,Y=0.22],-0.4"
            )
          )
              f (vl-filename-mktemp nil nil ".lin")
        )
        (cd:SYS_WriteFile f l nil)
        (vla-load (cd:ACX_LineTypes) "WeldLine" f)
        (vl-file-delete f)
      )
    )
    (or (tblobjname "LTYPE" "WeldLine"))
  )
  (setq c
    (getreal
      (strcat
        "\nHeight of weld line <"
        (cd:CON_Real2Str *jk-WELD* 2 nil) ">:"
      )
    )
  )
  (if (not c)(setq c *jk-WELD*))
  (cd:SYS_UndoBegin)
  (if
    (setq l (-%l))
    (progn
      (setq *jk-WELD* c)
      (setq s (getpoint "\nStart point: "))
      (if
        (setq e (getpoint s "\nEnd point: "))
        (progn
          (setq o
            (cd:ACX_AddLWPolyline
              (cd:ACX_ASpace)(list s e) nil)
          )
          (vla-put-LineType o "WeldLine")
          (vla-put-LinetypeScale o c)
          (vla-put-Color o 8)
          (vla-put-LineWeight o 0.0)
        )
        (princ "\n*** Error - Invalid point.")
      )
    )
    (princ "\n*** Error - Linetype not loaded.")
  )
  (cd:SYS_UndoEnd)
  (princ)
)
;;; -------------------------------------------------------------- ;;;
(princ)

„Stara” (teraz już pełnoletnia) wersja rysowania spoiny była wspomniana na cad.pl tutaj

( . . . )

AutoLISP

Zmienna SNAPANG

Zmienna systemowa SNAPANG służy do ustala kąta obrotu pomocniczej siatki lokalizacyjnej dla bieżącej rzutni względem aktualnego układu współrzędnych. Wartość kąta można podać w linii poleceń, lub ustalić przez wskazanie dwóch punktów. W połączeniu z włączonym trybem ortogonalnym (zmienna ORTHOMODE), stanowi doskonałe narzędzie do precyzyjnego rysowania, bez konieczności manipulacji układem współrzędnych. Do szybkiego i bezbłędnego ustawienia zmiennej napisałem LISP-owe polecenie X, które dla określonych wskazanych entycji pobiera ich orientację na płaszczyźnie, i na tej podstawie ustala jej nową wartość. Obiektami rysunkowymi są: prosta, półprosta, linia, odniesienie do bloku (również XRef), wielokrotne wstawienie bloku, definicja atrybutu, tekst, tekst wielowierszowy, oraz lekka polilinia. W tym przypadku kąt określany jest na podstawie właściwości segmentu przez który została wybrana polilinia. Brak wyboru, czyli wskazanie punktu (nie obiektu) ustawia zmienną SNAPANG na wartość 0.0.

Działanie polecenia X widać poniżej, na przykładzie ustawienia SNAPANG do wskazanego bloku:

Poniżej zaś cały kod definicji polecenia:


; =============================================================== ;
; snapang.lsp                                                     ;
; Ustawia zmienna SNAPANG do wskazanego obiektu                   ;
; by kojacek 2010,2018                                            ;
; =============================================================== ;
(defun C:X (/ s e n d _rtd _gap)
  (defun _rtd (r)(* 180.0 (/ r pi)))
  (defun _gap (es / s p)
    (if
      (setq s (jk:ENT_GetLWPolySeg (car es)(cadr es)))
      (progn
        (setq p (jk:ENT_GetLWPolySegPoints (car es) s))
        (angle (car p)(cadr p))
      )
    )
  )
  (cd:SYS_UndoBegin)
  (if
    (setq s (entsel "\nSelect object: ") e (car s))
    (progn
      (setq d (entget e) n (cdr (assoc 0 d)))
      (setvar "SNAPANG"
        (cond
          ( (= "LINE" n)
            (angle (cdr (assoc 10 d))(cdr (assoc 11 d)))
          )
          ( (= "LWPOLYLINE" n)(_gap s))
          ( (member n
              '("TEXT" "MTEXT" "INSERT" "MINSERT"
                "ATTRIB" "ATTDEF"
              )
            )
            (cdr (assoc 50 d))
          )
          ( (member n '("RAY" "XLINE"))
            (angle '(0.0 0.0 0.0)(cdr (assoc 11 d)))
          )
          (t 0.0)
        )
      )
    )
    (setvar "SNAPANG" 0.0)
  )
  (cd:SYS_UndoEnd)
  (princ
    (strcat "\nSNAPANG = "
      (vl-princ-to-string (_rtd (getvar "SNAPANG")))
    )
  )
  (princ)
)
; =============================================================== ;
; zwraca numer segmentu obiektu LWPOLYLINE                        ;
;   en - ename lub vla-object LWPOLYLINE                          ;
;   pt - punkt wskazania                                          ;
; =============================================================== ;
(defun jk:ENT_GetLWPolySeg (en pt)
  (fix
    (vlax-curve-getParamAtPoint
      en
      (vlax-curve-getClosestPointTo en pt)
    )
  )
)
; =============================================================== ;
; Zwraca liste wspolrzednych segmentu SE dla LWPOLYLINE EN        ;
; =============================================================== ;
(defun jk:ENT_GetLWPolySegPoints (en se / v)
  (setq v (jk:ENT_LWPolySegs en nil))
  (if
    (< se v)
    (list
      (vlax-curve-getPointAtParam en se)
      (vlax-curve-getPointAtParam en (1+ se))
    )
  )
)
; =============================================================== ;
; zwraca ilosc segmentow LWPOLYLINE (gdy Mode=Nil) lub liste nume-;
; row segmentow: (0 1 2 ... N)                                    ;
; =============================================================== ;
(defun jk:ENT_LWPolySegs (en mode / v i l)
  (setq v (cdr (assoc 90 (entget en)))
        v (if
            (vlax-curve-isClosed en)
            v
            (1- v)
          )
  )
  (if Mode
    (progn
      (setq i 0)
      (while
        (< (length l)(1- v))
        (setq i (1+ i))
        (setq l (append (list i) l))
      )
      (cons 0 (reverse l))
    )
    v
  )
)
; =============================================================== ;
(princ)

Rzecz jasna konieczne jest wcześniejsze załadowanie biblioteki CADPL-Pack. O ile ustawienie zmiennej SNAPANG do obiektów typu LINE, XLINE, TEXT, MTEXT czy INSERT, jest stosunkowo proste, większym wyzwaniem było wyznaczenie kąta segmentu przez który została wskazana polilinia. Stąd obecność kilku bibliotecznych funkcji manipulowania na obiektach typu LWPOLYLINE.  Wykorzystuję tutaj pobranie numeru segmentu wskazanej polilinii (funkcja jk:ENT_GetLWPolySeg oraz pomocniczo jk:ENT_LWPolySegs) na podstawie punktu wskazania, następnie wybranie jego współrzędnych (funkcja jk:ENT_GetLWPolySegPoints) która w końcu służy do wyliczenie kąta segmentu. Polecenie X, można rzecz jasna rozbudować o  możliwość ustawienia SNAPANG, na podstawie kąta zdefiniowanego przez inne obiekty rysunkowe.

( . . . )

AutoLISP

Widoczność XREF-ów

Używacie odnośników zewnętrznych (XReference)? Na pewno tak. A gdy jest ich w rysunku za dużo, często utrudnione jest sterowanie ich widocznością. Zwykle używa się do tego dwóch polecenia ODNOŚNIK (_XREF), dostępnych również z palety Managera odniesień:

  • Usuń (Unload) – opcja usuwa wybrany odnośnik do pliku DWG. W miejscu odnośnika zewnętrznego zostaje znacznik, co umożliwia jego ponowne wczytanie.
  • Wczytaj ponownie (Reload) – opcja ponownie wczytuje i wyświetla ostatnio zapisaną wersję odniesień. Jeżeli program napotka błąd podczas wczytywania, zakończy wykonywanie polecenia.

Innym sposobem jest manipulowanie stanem widoczności warstw. Ma to jednak pewne wady. Odnośniki mogą być bowiem wczytywane na różne warstwy, czasem trudno jest szybko znaleźć odpowiednią. Ponadto działanie na warstwach może być zbyt wolne (regeneracja rysunku).

Poniżej przedstawiam krótkie makro LISP-owe sterujące globalnie widocznością wszystkich wczytanych do rysunku odniesień. Jest szybkie, a jedno zdefiniowane polecenie: XXR, działa jak przełącznik – sekwencyjnie włącza i wyłącza widoczność XRef-ów.

Kod makra, które ostatnio zaadoptowałem do biblioteki CADPL-Pack, wygląda tak:


; ---------------------------------------------------------------------- ;
; C:XXR - kojacek 2005,2018                                              ;
; ---------------------------------------------------------------------- ;
(defun C:XXR (/ l n s m i)
  (if
    (setq l (cd:SYS_CollList "BLOCK" 32))
    (progn
      (setq n (cd:STR_ReParse l ","))
      (if
        (setq s
          (ssget "x"
            (list (cons 0 "INSERT")(cons 2 n)
                  (cons 410 (getvar "CTAB"))))
        )
        (progn
          (if
            (not 
              (setq m (cdr (assoc 60 (entget (ssname s 0)))))
            )
            (setq m 0)
          )
          (cd:SYS_UndoBegin)
          (setq l (cd:SSX_Convert s 0) i (length l))
          (foreach % l (cd:ENT_SetDXF % 60 (abs (1- m))))
          (princ (strcat "\nZmieniono widoczność " (itoa i) " XREF-ów."))
          (cd:SYS_UndoEnd)
        )
      )
    )
    (princ "\nW rysunku nie ma XREF-ów.")
  )
  (princ)
)
; ---------------------------------------------------------------------- ;

Rzecz jasna – do poprawnego działania potrzeba wcześniej załadować rzeczonego CADPL-Pack’a. Działanie programu jest proste – zmieniana jest wartość kodu 60 DXF, odpowiedzialnego za widoczność obiektu. Właściwość ta w ActiveX nazywa się Visibility, i może ją mieć każdy obiekt rysunkowy.

. . .  )

AutoLISP

Bloki 1×1

Wykorzystanie bloków w AutoCAD-zie, jest najprostszą i najbardziej powszechną metodą automatyzacji tworzenia rysunku, dodatkowo (w przeciwieństwie do innych), niewymagającej znajomości programowania. Grupowanie wielu elementów, wielokrotne ich wstawianie, przemieszczanie, skalowanie, czyli w konsekwencji traktowania ich jak jeden obiekt, znacząco zwiększa wydajność i efektywność rysowania. Kilka słów o blokach 1×1, zwanych też czasami blokami jednostkowymi…

Definiowanie bloków o siatce jednostkowej 1×1 ma zastosowanie przy użyciu wszelkiego rodzaju symboli umownych, skalowanych albo jednorodnie albo z różnymi współczynnikami w osiach X i Y. Najważniejszą cechą takich obiektów jest taki sam proporcjonalny wygląd, niezależnie od jego wielkości. Z reguły więc będą to obiekty o kształcie kwadratu (prostokąta), okręgu, zestawu linii równoległych itp. W szeroko pojętym rysunku budowlano-architektonicznym i branżowym, mogą to być różnego rodzaju otwory, przebicia, słupy, belki, elementy konstrukcji, kanały, przewody kominowe, stopnie, kratki, moduły sufitów, podłóg, proste elementy wyposażenia itd. Poniżej na grafikach przykłady kilku zastosowań tego typu elementów.

Bloki dynamiczne (od wersji AutoCAD 2006 (rok 2005)) ustanowiły dodatkowo nową jakość. Wprowadzenie różnych parametrów zezwala teraz na większą swobodę w definiowaniu kształtu i wymiarów bloków jednostkowych. Dodatkowo możliwości wykorzystania wielu stanów widoczności pozwala tworzyć bloki, które funkcjonalnie tworzą pewną grupę (np. kanały w ścianach), a różnią się przeznaczeniem (tutaj: kanały dymowe / wentylacyjne / gazowe itp.). Takie rozwiązania mogą być też pomocne przy sprawdzaniu ilości, wielkości, obliczania powierzchni przekroju i innych możliwych parametrów, „zakodowanych” w parametrach i grafice symbolu.

Opiszę teraz sposób wykorzystania działań automatyzujących tworzenie dokumentacji, przy użyciu bloku jednostkowego i programowania LISP, radykalnie redukującego działanie użytkownika. Przykładem zastosowania połączenia trzech technik, a więc oprogramowanego wstawienia dynamicznego bloku jednostkowego, będzie wrysowanie oznaczenia projektowanego przebicia w ścianie. Symbolicznym oznaczeniem przebicia (wykonania otworu w ścianie) jest rysunek prostokąta z wypełnionymi obszarami ograniczonymi jego przekątnymi. Automatyzacja przedstawionego przykładu polega na dynamicznym wskazaniu dwóch punktów, tworzących prostokąt (projektowany otwór w ścianie), wstawienie tam odpowiednio przeskalowanego bloku, oraz (opcjonalnie) wyznaczenie kierunku czyli wypełnienia obszarów symbolu. Poniżej animacja tego działania – wrysowanie w ścianę miejsc projektowanych przebić dla montażu kanałów wentylacji:

Jak widać działanie projektanta, zostało tu ograniczone do niezbędnego minimum – całą „czarną robotę”, czyli wstawienie odpowiedniego symbolu oraz ustalenie jego wymiarów, przejmuje program LISP-owy. To ważne bowiem użytkownik może bardziej skupić na ważnych rzeczach, samo zaś szczegółowe rysowanie wykonuje stosunkowo prosty program. Krótkie makro definiujące polecenie PRZEBICIE wygląda tak:


; ======================================================================= ;
; Polecenie PRZEBICIE wstawia symbol projektowanego otworu w scianie.     ;
;           kojacek 2012/2015/2018                                        ;
; ======================================================================= ;
(defun C:PRZEBICIE (/ f p w h i m)
  (if
    (setq f (getpoint "\nOkreśl pierwszy narożnik:"))
    (if
      (setq p
        (cd:USR_GetCorner f "\nOkreśl kolejny narożnik:" T)
      )
      (progn
        (setq w (distance (car p)(cadr p))
              h (distance (car p)(cadddr p))
        )
        (cd:SYS_UndoBegin)
        (setq i
          (cd:BLK_InsertBlock
            (car p) "ArchStdPrzebicie" '(1 1 1) 0 T
          )
        )
        (cd:BLK_SetDynamicProps i "W" w)
        (cd:BLK_SetDynamicProps i "H" h)
        (if
          (setq m
            (cd:USR_GetKeyWord "\nZmienić wypełnienie?"
              '("Tak" "Nie") "Nie")
          )
          (cond
            ( (= m "Tak")
              (cd:BLK_SetDynamicProps i "Stan" "B")
            )
            (T nil)
          )
        )
        (cd:SYS_UndoEnd)
      )
    )
  )
  (princ)
)
; ======================================================================= ;
(princ)

Program wymaga wcześniejszego zdefiniowania jednostkowego (1×1) dynamicznego bloku o nazwie ArchStdPrzebicie, który posiada dwa stany widoczności o nazwach A i B, a gabaryty określane są parametrami rozciągania liniowego nazwanych W i H.  Oczywiście można zastosować inny blok z innymi parametrami – trzeba tylko odpowiednio zmodyfikować listing. Do prawidłowego działania programu, potrzebne jest też wcześniejsze załadowanie biblioteki CADPL-Pack. Warto zwrócić uwagę na mechanizm wstawiania bloku – możliwe jest wskazanie dowolnych dwóch punktów określających prostokąt. Nie ma tutaj znaczenia kierunek wskazania punktów („góra-dół” „od lewej-do prawej” itp.)  – blok jest zawsze „wpasowany” w wyznaczony prostokąt. Uzupełnieniem automatyzacji jest też wskazanie warstwy na którą „ląduje” wyznaczone przebicie. Tutaj ze względu na miejsce, pominąłem to działanie.

Przedstawiony uproszczony przykład ilustruje możliwości oprogramowania wstawiania bloków jednostkowych i dynamicznego ich skalowania. Taki sam mechanizm można wykorzystać do wstawiania innych symboli tego rodzaju, jak kanały wentylacyjne, dymowe, słupy, stopy fundamentowe itp.

. . . )

AutoLISP

Numerator

Dziś bardzo stary program, którego nie publikowałem już nawet w poprzedniej edycji strony (na republika.pl), z powodu jego pewnych ograniczeń. Ogólnie są dostępne narzędzia o podobnej funkcjonalności, ale o większych możliwościach. Co jakiś czas otrzymuję jednak sygnały, dotyczące jego udostępnienia. Zatem niniejszym dziś stary dobry numerator pojawia się ponownie…

Program pozwala na szybsze edytowanie atrybutów bloków, tekstów i tekstów wieloliniowych (MTEXT), których wartości mają charakter częściowo (lub całkowicie) liczbowy. Wszelkie powtarzalne elementy o unikalnym numerze, zwykle będące kolejnymi elementami ciągu liczb. Program ma swoje początki przed 1999 rokiem, do tej pory parokrotnie zmieniany (ostatnia kompilacja – 01-10-2009). Wartość tekstu w oknie dialogowym podzielona jest na trzy części. Przeznaczeniem środkowej (liczbowej) części jest określenie wartości od której kolejne wystąpienia będą zwiększane (lub zmniejszane). Wycinki przed (prefiks) i za liczbą (sufiks), pozwalają na wprowadzenie łańcuchów tekstowych nie podlegających zmianie. Wypełnianie ich nie jest wymagane, pozwala to na tworzenie opisów będących tylko liczbami. Po ustaleniu zasad numerowania , po wywołaniu polecenia AT każde wskazanie atrybutu bloku, tekst lub mtext-u wypełnia go odpowiednią wartością.

Tak wyglądały  „plastyczne” okna dialogowe poleceń AT oraz ATS w WindowsNT:

W oknie ustawień (polecenie ATS)  można dokonać następujących zmian parametrów:

  • wybranie elementów do zmiany (oprócz standardowego ATTRIB, również TEXT oraz MTEXT)
  • ustalenie znacznika UNDO, pozwala na późniejsze cofanie zmiany kolejnych wskazań, czy też zgrupowanie wszystkich zmian wykonanych w jednym poleceniu.
  • opcję kończenia polecenia – do wyboru jest „puste wskazanie” na ekranie kończące polecenie (dla lubiących szybkość), lub jego kontynuacja (ponowna próba wskazania). Wyjściem z polecenia AT jest wtedy opcja [Wyjdź].

Program działa na wszystkich dotychczas znanych wersjach AutoCAD-a począwszy od wersji 2000 włącznie.

Plik: pol_at.vlx (~9kB) kompilacja: 01-10-2009

( . . . )

AutoLISP

Opis bloku (2)

Wydawało się, że temat opisu bloków został już (tutaj) wyczerpany, lecz okazuje się, iż można go jeszcze rozwinąć, co dziś czynię, a zostało to zapoczątkowane tym komentarzem:

Krótko dziękując za dobre słowo, odniosę się teraz do dwóch spraw. Podoba mi się porównanie do… Kolumba 🙂 , sam wiele lat temu (gdy byłem wtedy mniej siwy i jeszcze mniej zgorzkniały 😉 ), przy pierwszych LISP-ach, czułem się podobnie. Odkrywanie nowych lądów na nie całkiem znanym oceanie programowania AutoCAD-a, to naprawdę interesująca, (nie raz) fascynująca i dająca (czasem) satysfakcję przygoda. Niestrudzenie (od lat (także) na tym blogu) do tego zachęcam.

Druga sprawa to rzecz już bardziej praktyczna, mianowicie – opisywanie bloku w wielolinii odniesienia, czyli przy użyciu MLEADER’a. Poprzednio przedstawiłem program który po wskazaniu bloku i pobraniu jego opisu (jeśli istniał), na jego podstawie tworzył opis w postaci obiektu typu TEXT. Teraz program gruntownie przebudowałem, dodając do niego nowe polecenie BLCOMM. Pozwala ona tworzyć opis za pomocą wielolinii odniesienia, tak jak to widać poniżej:

Oczywiście wcześniej zdefiniowane polecenie BLCOM działa bez zmian. BLCOMM tak samo rozpoznaje opis, w definicji bloku, który składa się z wielu linii, i pozwala na wybranie odpowiedniej wartości:

Kod „nowego” pliku blcom.lsp przedstawiam poniżej:


; ==================================================================== ;
; blcom.lsp - kojacek (2017,2018)                                      ;
;             Polecenie BLCOM tworzy tekst z opisem bloku              ;
;             Polecenie BLCOMM tworzy MLEADER z opisem bloku           ;
;             (wlasciwosc Comments obiektu jezeli ja posiada)          ;
; last-mod:                                                            ;
; 12-05-2018 [2] Nowe polecenie BLCOMM tworzy opis jako MLEADER        ;
;                Przebudowa poprzednich funkcji. Dzialanie BLCOM bez   ;
;                zmian.                                                ;
; 20-11-2017 [1] EffectiveName vs Name (thx: ziele_o2k)                ;
; ==================================================================== ;

; -------------------------------------------------------------------- ;
; zmienna globalna -> tekst wielkimi literami:
(setq *jk-BlockCommBig* T)
; -------------------------------------------------------------------- ;
(defun C:BLCOM  nil (jk:BlockComment 0)(princ))
(defun C:BLCOMM nil (jk:BlockComment 1)(princ)) ; <- [2]
; -------------------------------------------------------------------- ;
(defun jk:BlockComment (Mode / s d c n l a i r o v m makeML)
  (defun makeML (Start / e l c v m k)
    (if
      (setq e
        (getpoint
          Start "\nOkreśl położenie linii łączącej linii odniesienia:"
        )
      )
      (progn
        (setq v
          (vlax-make-variant
            (vlax-safearray-fill
              (safearray vlax-vbdouble '(0 . 5))
              (apply 'append (list Start e))
            )
          )
        )
        (setq m (vla-addMleader (cd:ACX_ASpace) v 0))
        (vla-put-TextString m " ")
        (setq k (vla-get-dogleglength m))
        (if
          (> (car Start)(car e))
          (progn
            (vla-put-dogleglength m 0)
            (vla-SetDogLegDirection m 0
              (vlax-3D-point
                (list (if (<= (car Start)(car e)) 1 -1) 0 0)
              )
            )
            (vla-put-dogleglength m k)
          )
        )
        (vla-SetLeaderLineVertices m 0 v)
      )
    ) m
  )
  (setq m (list "Punkt wstawienia opisu"
                "Określ położenie początku linii odniesienia"
          )
  )
  (if
    (and
      (setq s (entsel "\nWybierz blok: "))
      (= "INSERT" (cdr (assoc 0 (setq d (entget (car s))))))
    )
    (progn
      (setq v (vlax-ename->vla-object (car s))
            n (vlax-get-property v
                (if
                  (vlax-property-available-p v "EffectiveName")
                  "EffectiveName"
                  "Name"
                )
              )
      )
      (if
        (/= "" (setq c
                 (vla-get-Comments (vla-item (cd:ACX_Blocks) n))
               )
        )
        (progn
          (setq l (cd:STR_Parse
                    (vl-list->string
                      (vl-remove 13 (vl-string->list c))
                    )
                    "\n" nil
                  )
                a (cdr (assoc 8 d))
          )
          (cd:SYS_UndoBegin)
          (if
            (setq p (getpoint (strcat "\n" (nth Mode m) ":")))
            (if
              (setq o
                (if
                  (zerop Mode)
                  (cd:ACX_AddText
                    (cd:ACX_ASpace) " " p (getvar "TEXTSIZE") 0
                  )
                  (makeML p)
                )
              )
              (progn
                (setq i 0)
                (if
                  (= (length l) 1)
                  (setq r (nth i l))
                  (setq r (nth
                    (cd:DCL_StdListDialog l i
                      "Opis bloku" "Wybierz: " 50 12 1 11
                      (list "&OK" "") nil T T nil ) l
                    )
                  )
                )
                (if *jk-BlockCommBig* (setq r (strcase r)))
                (vla-put-TextString o r)  
                (cd:ACX_SetProp  o (list (cons "Layer" a)))
              )
              (princ "\nWystapił błąd - nie można utworzyć opisu.")
            )
            (princ "\nNie wskazano punktu. ")
          )
          (cd:SYS_UndoEnd)
        )
        (princ "\nBlok nie ma opisu. ")
      )
    )
    (princ "\nNie wskazano bloku. ")
  )
  (princ)
)
; ==================================================================== ;
(princ)

Oczywiście wymagane jest wcześniejsze załadowanie biblioteki CADPL-Pack’a.

( . . . )