Najmniejszy opisany prostokąt - LISP


Iskra

Rekomendowane odpowiedzi

Witam wszystkich,

 

Na początku krótko o mnie. Z LISP-em mam doczynienia dopiero od 2 msc.

Nigdy wczesniej też nie pisałem postów na formu więc jeśli robię coś źle dajcie znać.

Przy pracy na pełny etat i dwójce małych dzieci nie ma za wiele czasu, ale staram się jak mogę

i oto poniżej jest mój pierwszy "użytkowy program". :)

 

 

Mam mały, mianowicie nie zawsze działa poprawnie.

Program powinien rysować na wskazanej polilinii opisany prostokąt o najmniejszej powierzchni.

Służy mi to w pracy do wyliczania powierzchni fasady wentylowanej. Do oferty trzeba ująć właśnie najmniejszy

opisany prostokąt, jeżeli płyta ma nieforemny kształt.

 

Jak na załączonym zdjęciu, czasami omija jeden punkt. Niebieskie to analizowana Polilinia natomiast żółte to efekt działania programu.

 

Program znajduje się natomiast tutaj:

 (setq PL (entsel "\nWSKAŻ POLILINIĘ : "))
     (if (= PL nil)
        (progn
         (alert "Musisz wskazac POLILINIĘ")
         (vl-exit-with-value 0)
        );progn
      );if



(setq PL (car PL)); wyciąga nazwe ze wskazanej polilinii 

(setq vla_PL (vlax-ename->vla-object PL); zamienia nazwe obiektu z typowej numeracji ACAD na nazwy obiektowe
         ILOSC_WIERZCHOLKOW (vlax-curve-getEndParam vla_PL)); zlicza ilosc wierzchołków wskazanej polilinij


        (setq i 0)
        (setq Petla (fix ILOSC_WIERZCHOLKOW)) ;fix: Real -> Integer

        (setq Dane_i (list)) 

;****************************************************************
;UTORZENIE MACIERZY PUNKTOW Z KTORYCH ZBUDOWANA JEST POLILINIA (PKT1 X Y Z ...)
(repeat (+ Petla 1)
       ; wyciagamy punkt z PL (Polilinii)
    (setq Punkt_1 (vlax-curve-getpointAtParam vla_PL i))
    (setq P1_x (car Punkt_1)
          P1_y (cadr Punkt_1)
          P1_z (caddr Punkt_1)
	  Dane_i (cons i Dane_i)
          Dane_i (cons P1_x Dane_i)
          Dane_i (cons P1_y Dane_i)
          Dane_i (cons P1_z Dane_i)
	  );setq            
       (setq i (1+ i))
   );repeat

 (setq Dane_i (reverse Dane_i)) ; Dane_i - ciągła lista wszystkich wierzchołków (nr i X, Y, Z wierzcholka)

;***************************************************************
;WPROWADZENIE POCZATKOWEGO POLA POWIERZCHNI PROSTOKATA OPISANEGO
(setq k 2
      Xmin (nth 1 Dane_i)
      Xmax (nth 1 Dane_i)
      Ymin (nth 2 Dane_i)
      Ymax (nth 2 Dane_i)
);setq

(while (<= k Petla)
    (progn
      (setq
        X (nth (- (* k 4) 3) Dane_i)
        Y (nth (- (* k 4) 2) Dane_i)
	);setq
      (if (< X Xmin)
	
	 (setq Xmin X)
	);if

      (if (> X Xmax)
	(setq Xmax X)
	);if
      (if (< Y Ymin)
	(setq Ymin Y)
	);if

      (if (> Y Ymax)
	(setq Ymax Y)
	);if
      
      (setq k (1+ k));setq
      
     );progn
);while


;***********************************************************
;Wyznaczenie prostokata na podstawie min i max punktow X i Y
		    (setq
                      Pkt1 (list Xmin Ymin)
		      Pkt2 (list Xmax Ymin)
		      Pkt3 (list Xmax Ymax)
		      Pkt4 (list Xmin Ymax)
		      L (distance Pkt1 Pkt2)
		      H (distance Pkt2 Pkt3)
		      
		      Pole (* L H); Pole koncowe
		      Pmin Pkt1; Punkt 1 koncowy
		      Pmax Pkt3; punkt 2 koncowy
		      kat 0; kat koncowy
		      );setq


		 ;(princ "\nPoczatkowa powierzchnia prostokata wynosi: ")
                 ;(princ Pole)
	         ;(princ " o wymiarach LxH = ")
		 ;(princ L) (princ " x ") (princ H)
		 ;(princ "\noraz punktach wstawienia P1: ") (princ Pmin) (princ " oraz P2: ") (princ Pmax)
;***************************************************************
(setq i 1
      j (+ i 1)
      );setq
(while (< i Petla)
  (progn
    (while (<= j Petla)
      (progn
	(setq P1 (list (nth (- (* i 4) 3) Dane_i) (nth (- (* i 4) 2) Dane_i) (nth (- (* i 4) 1) Dane_i))
	      P2 (list (nth (- (* j 4) 3) Dane_i) (nth (- (* j 4) 2) Dane_i) (nth (- (* j 4) 1) Dane_i))
	      kat_rad (angle P1 P2)
	      kat_grad (angtos kat_rad 0 10)
	      );setq
;****************************************************************

	(command "_ucs" "_z" P1 P2)
;WYSZUKANIE SKRAJNYCH PUNKTOW W AKTUALNYM UKLADZIE WSPOLRZEDNYCH

	(setq k 2
      X_ (nth 1 Dane_i)
      Y_ (nth 2 Dane_i)
      Z_ (nth 3 Dane_i)
      Punkt (list X_ Y_ Z_)
      Punkt (trans Punkt 0 1 nil)
      Xmin (nth 0 Punkt)
      Xmax (nth 0 Punkt)
      Ymin (nth 1 Punkt)
      Ymax (nth 1 Punkt)
      );setq

(while (<= k Petla)
    (progn
      (setq
        X (nth (- (* k 4) 3) Dane_i)
        Y (nth (- (* k 4) 2) Dane_i)
	Z (nth (- (* k 4) 1) Dane_i)
        Punkt (list X Y Z)
        Punkt (trans Punkt 0 1 nil)
	
	X (nth 0 Punkt)
        Y (nth 1 Punkt)
	
	);setq
      (if (< X Xmin)
	
	 (setq Xmin X)
	);if

      (if (> X Xmax)
	(setq Xmax X)
	);if
      (if (< Y Ymin)
	(setq Ymin Y)
	);if

      (if (> Y Ymax)
	(setq Ymax Y)
	);if
      
      (setq k (1+ k));setq
      
     );progn
);while
;Wyznaczenie opisanego prostokata na skrajnych punktach
	(setq
                      Pkt1 (list Xmin Ymin)
		      Pkt2 (list Xmax Ymin)
		      Pkt3 (list Xmax Ymax)
		      Pkt4 (list Xmin Ymax)
		      L (distance Pkt1 Pkt2)
		      H (distance Pkt2 Pkt3)
		      
		      P_ucs (* L H); Pole w aktualnym ukladzie
);setq
	  		(if (< P_ucs Pole)
			  (setq Pole P_ucs
			        Pmin Pkt1; Punkt 1 koncowy
		                Pmax Pkt3; punkt 2 koncowy
				Pmin (trans Pmin 1 0 nil)
				Pmax (trans Pmax 1 0 nil)
				kat kat_grad
				);setq
			  );if

	;(command "_rectangle" Pkt1 "_r" kat Pkt3) 

	   (command "_ucs" "_w")
	
;***************************************************************
	     (princ "\nWspółrzedne odcinka ")
	     (princ i)
             (princ " - ")
	     (princ j)
	     (princ " wynoszą: ")
	     (princ P1)
	     (princ " oraz ")
	     (princ P2)

	     (setq j (1+ j));setq
	);progn
      );while j
    (setq i (1+ i)
	  j (+ i 1));setq    
    );progn
  );while i
(princ)

(command "_rectangle" Pmin "_r" kat Pmax) 





Ogólne założenie programu jest takie, że zczytuje on punkty polilinii a następnie łączy je w pary

np. dla czworokąta są następujące 1-2, 1-3, 1-4, 2-3, 2-4, 3-4. Dla każedej pary zmianie układ współrzędnych

tak aby oś X leżała na wskazanym odcinku. Po zmianie układu odczytuje wartości X i Y wszystkich punktów i wyszukuję

najmniejsze i największe wartości. Nie umiałem tutaj zastosować funkcji "min" i "max" dlatego zrobiłem to za pomocą funkcji "if"

i w przydaku prawdy zmiania główną wartość Xmin, Xmax, Ymin albo Ymax.

Po wyszukaniu punktów odczytuje wartość długość i wysokość i wylicza powierzchnie.

Wybór najmniejszego prostokąta również za pomocą funkcji "if" jeżeli prawda to zastępuję główną wartość i zapamiętuje prarametry

prostokąta tzn. dł, wys, kąt obrotu oraz pow.

 

Będę wdzięczny za wskazówki.

 

Problem drugi którym się jeszcze nie zajmowałem to podobny program ale dla polilinii posiadających łuk. Moj program widzi naturalnie tylko konce łuk. Czy jest możliwe wyszukanie punktu min lub max dla wskazanej polilinii? Np. na zasadzie przesuwania linii o wskazany

wektor i jeżeli są 2 punkty przecięcia to zwiększa wektor jeżeli 0 to różnicę między wektorami dzieli na pół i tak do skutku aż znajdzie tylko 1 wspólny punkt. To taki mój pomysł ale jeszcze nie prubowałem go zrealizować. Narazie chciałbym usprawnić program dla wielokątów.

 

Będę wdzięczny za wszelkie wskazówki co może być nie tak.

 

Pozdrawiam

 

post-1479-0-77603000-1444557224_thumb.jpg

Odnośnik do komentarza
Udostępnij na innych stronach

Co do znalezienia najmniejszego prostokąta (opisującego płaską figurę) zobacz tutaj:


Jest tam program do ściągnięcia:


Potestuj i zobacz czy spełnia twoje oczekiwania.

 

Co do lisp-ów zaś, zobacz tutaj: http://forum.cad.pl/cadpl-pack-v1-lsp-t78161.html

To o takim zjawisku o nazwie CADPL-Pack. Jest to zestaw funkcji bibliotecznych, których użycie (także w twoim omawianym tutaj problemie), znacznie może ułatwić pracę. Również sama dyskusja przy poczęciu i rozwoju Pack-a, (w mojej opinii) może być źródłem porządnej lisp-owej wiedzy. W tej chwili widzę już na początku wiele błędów w twoim kodzie. Chętnie (w miarę możliwości czasowych) służę pomocą, w ich ewentualnej poprawie i wyjaśnieniu na czym polegają.
Odnośnik do komentarza
Udostępnij na innych stronach

Witam

Korzystając z samych odcinków prostych pomysł z łączeniem punktów w pary jest bardzo trafny, natomiast nie sprawdzi się w przypadku segmentów łukowych.
Obiekty graficzne w CAD mają metodę: GetBoundingBox

np:

(vl-load-com)
(setq util (vla-get-utility (vla-get-activedocument (vlax-get-acad-object))))
(vla-getentity util 'obj 'ip "\nSelect Object: ")


(vla-GetBoundingBox obj 'minpoint 'maxpoint)


(princ (vlax-safearray->list minpoint ) )
(terpri)
(princ vlax-safearray->list maxpoint)

Metoda GetBoundingBox przekazuje to zmiennych minpoint  i maxpoint odpowiedni lewy dolny i prawy górny narożnik prostokąta obejmującego element

Jest tylko jeden problem:  GetBoundingBox wylicza prostokąt obejmujący w układzie globalnym więc zwykle uzyskany prostokąt nie będzie najmniejszym.
Myślę, że jeśli mamy obracać układem współrzędnych równie dobrze możemy pokręcić samym mierzonym elementem, albo jego kopią. Może i uzyskany prostokąt nie będzie najmniejszy z możliwych, ale przyjmując jakąś rozsądną relację wydajności do dokładności możemy obracać np 90 razy co 1 stopień, lub 180 razy co 0.5 stopnia aż do uzyskania wystarczająco dokładnego efektu w akceptowalnie długim czasie wykonania.

Pozdrawiam

Odnośnik do komentarza
Udostępnij na innych stronach

Witam

Korzystając z samych odcinków prostych pomysł z łączeniem punktów w pary jest bardzo trafny, natomiast nie sprawdzi się w przypadku segmentów łukowych.

Obiekty graficzne w CAD mają metodę: GetBoundingBox

np:

(vl-load-com)
(setq util (vla-get-utility (vla-get-activedocument (vlax-get-acad-object))))
(vla-getentity util 'obj 'ip "\nSelect Object: ")


(vla-GetBoundingBox obj 'minpoint 'maxpoint)


(princ (vlax-safearray->list minpoint ) )
(terpri)
(princ vlax-safearray->list maxpoint)

Metoda GetBoundingBox przekazuje to zmiennych minpoint  i maxpoint odpowiedni lewy dolny i prawy górny narożnik prostokąta obejmującego element

Jest tylko jeden problem:  GetBoundingBox wylicza prostokąt obejmujący w układzie globalnym więc zwykle uzyskany prostokąt nie będzie najmniejszym.

Myślę, że jeśli mamy obracać układem współrzędnych równie dobrze możemy pokręcić samym mierzonym elementem, albo jego kopią. Może i uzyskany prostokąt nie będzie najmniejszy z możliwych, ale przyjmując jakąś rozsądną relację wydajności do dokładności możemy obracać np 90 razy co 1 stopień, lub 180 razy co 0.5 stopnia aż do uzyskania wystarczająco dokładnego efektu w akceptowalnie długim czasie wykonania.

Pozdrawiam

Nie wydaje mi się aby zabawy z obracaniem obiektów, będą efektywniejsze niźli LISP który wskazałem we wcześniejszym poście. Wykorzystuje on algorytm Grahama (wyznaczenie otoczenia punktów), sprowadzając wynik ostatecznie w uproszczeniu do najmniejszego prostokąta (o co w rzeczywistości chodzi). Wydaje mi się że działa dobrze w większości zastosowań.

Odnośnik do komentarza
Udostępnij na innych stronach

Wowww :shok: ... jak zaczynalem zabawe LISP-em to widzialem tylko pare stron funkcji i stwierdzilem ze idzie to ogranac.

Bazowalem glownie na zestawieniu funkcji z e-cad.pl i ksiazki AutoLISP - Praktyczny Kurs.

A tu im dalej w las tym wiecej drzew...ilosc mozliwosci mocno mnie zaskoczyla.

 

Wielke dziekie Kojacek, program ze SWAP-a sprawdza sie w 100%, dokladnosc jest jak najbardziej wystarczajaca.

CADPL-Pack tez robi wrazenie, ale narazie jeszcze sie w niego nie wgryzalem. Mam zajecie na kilka tygodni ale chetnie bym tez uslyszal Twoje uwagi odnosnie mojego kodu. Oczywiscie jak bedziesz mial chwile.

Sam bym teraz sporo rzeczy zmienil. Przede wszystkim zaczal uzywac podprogramow. Teraz robilem wszystko w jednym ciagu i jak mi przyszlo cos zmienic to szukanie zabieralo zbyt duzo czasu.

 

Co do funkcji GetBoundingBox moze zastapic moje wyliczenia min i max oraz okresla prawidlowo te punkty rowniez dla lukow.

Jednak nie sprawdza sie juz w przypadku splajnu. Wyrzuca punkty polozone troche dalej niz wskazany splajn.

Te cos nowego na co nie zwrocilem wczesniej  uwagi, do momentu uzycia programu ze SWAP-a.

 

Pozostaje zakasac rekawy i do roboty. Wielkie dzieki za pomoc :good:

A tak na marginesie istnieje cos takiego jak spis wszystkich podstawowych funkcji VLispa? Cos takiego jak jest na stronie e-cad.pl dla Autolispa.

 

ps. Przepraszam za brak polskich znakow ale w pracy nie posiadam "polskiej klawiatury"

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli można tutaj (chyba że admin przeniesie do innego wątku), od samego początku.
Czyli wybór obiektu. Niech będzie prosta funkcja o nazwie Sel do wyboru jednego obiektu. Do testowania zwracać będzie wynik Ok lub Źle. W kolejnych krokach trochę urośnie, ale pozwoli to prześledzić działanie.
Podobnie jak w twoim kodzie, chcemy wybrać obiekt (polilinię). Spójrz:
 

(defun Sel (/ e)
  (if
    (setq e (entsel "\nWskaż polilinię: "))
    (princ "\nOk")
    (princ "\nŹle. ")
   )
)





Powiedzmy szczerze że żadnych rewelacji, nie trafisz - masz źle, wybierzesz jest Ok. Powiela twój błąd - możesz wybrać cokolwiek, a chcesz przecież polilinię.
Zatem druga przymiarka:
 

(defun Sel (/ e d)  
  (if    
    (and      
      (setq e (entsel "\nWskaż polilinię: "))
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
    )
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)

W and od razu pobieramy dane obiektu (zmienna d), jednocześnie sprawdzamy czy to Polilinia. Lepiej?
Lepiej ale... w twoim przypadku trzeba wybrać polilinię zamkniętą raczej. Zatem popatrzmy:
 

(defun Sel (/ e d)  
  (if    
    (and
      (setq e (entsel "\nWskaż polilinię: "))      
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
      (= 1 (logand 1 (cdr (assoc 70 d))))
    )    
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)

and ma teraz trzy warunki ( 1.wybraliśmy obiekt, 2.polilinię i 3.zamkniętą). Zamknięta polilinia w DXF to kod 70. Musi mieć wartość 1 (oraz ewentualnie 129). Jest dużo lepiej. Ale to nie koniec. Właściwie, to powinieneś wybrać zamkniętą polilinię ale o co najmniej 3 segmentach... Więc zmieniamy sel:
 

(defun Sel (/ e d)
  (if    
    (and      
      (setq e (entsel "\nWskaż polilinię: "))
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
      (= 1 (logand 1 (cdr (assoc 70 d))))
      (>= 4 (cdr (assoc 90 d)))
    )
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)

I teraz mamy już bardziej (niż mniej) poprawny kawałek kodu do wybrania polilini...

Edytowane przez kojacek
Odnośnik do komentarza
Udostępnij na innych stronach

ok, 99% kodu jest dla mnie jak najbardziej zrozumiala.

Tylko czemu w 3-ciej wersji dodajesz iloczyn logiczny (logand) przy sprawdzeniu zamkniecia polilinii?

Ma to jakies uzasadnienie?

W 4-rtej wersji przy sprawdzeniu ilosci wierzcholkow, porownujesz bezposrednio liczby po wyciagnieciu 2-go elementu.

Odnośnik do komentarza
Udostępnij na innych stronach

ok, 99% kodu jest dla mnie jak najbardziej zrozumiala.

Tylko czemu w 3-ciej wersji dodajesz iloczyn logiczny (logand) przy sprawdzeniu zamkniecia polilinii?

Ma to jakies uzasadnienie?

W 4-rtej wersji przy sprawdzeniu ilosci wierzcholkow, porownujesz bezposrednio liczby po wyciagnieciu 2-go elementu.

 

Od końca. Ilość wierzchołków to jedyna wartość dla kodu 90. Stąd od razu porównanie. Dla zamknięcia sprawa jest bardziej złożona. Kod 70 zawiera jednocześnie informację czy Polilinia jest zamknięta, oraz czy generowanie rodzaju linii jest włączone czy nie. I tak: 0 - poly otwarta a 1 zamknięta. PLINEGEN zaś to wartość 128. Stąd test zamknięcia polilinii sprowadza się do sprawdzenia logand = 1 (1 i 129 to zamknięta).

Odnośnik do komentarza
Udostępnij na innych stronach

Od końca. Ilość wierzchołków to jedyna wartość dla kodu 90. Stąd od razu porównanie. Dla zamknięcia sprawa jest bardziej złożona. Kod 70 zawiera jednocześnie informację czy polilinia jest zamknięta, oraz czy generowanie rodzaju linii jest włączone czy nie. I tak: 0 - poly otwarta a 1 zamknięta. PLINEGEN zaś to wartość 128. Stąd test zamknięcia polilinii sprowadza się do sprawdzenia logand = 1 (1 i 129 to zamknięta).

potrzebna byla krotka powtorka z liczb binarnych ale teraz jest juz wszystko jasne. Dzieki

Odnośnik do komentarza
Udostępnij na innych stronach

A teraz powinienem przybrać groźną minę i rzec, że oto podpuściłem was, a wy błędów nie widzicie... W rzeczywistości to sam go popełniłem.

Chodzi o formę:



(>= 4 (cdr (assoc 90 d)))


bowiem powinno być:



(>= (cdr (assoc 90 d)) 4)


ponieważ porównanie "większe / równe niż" odnosi się do "prawej" strony, czyli do drugiego argumentu. W naszym przypadku ilość wierzchołków ma być równa lub większa niż 4, a nie odwrotnie. Prawda?

Odnośnik do komentarza
Udostępnij na innych stronach

Aby do końca doprowadzić sprawę poprawnego (do naszych celów) wyboru polilini, zauważmy jeszcze jeden przypadek. Oto bowiem wyobraźmy sobie polilinię zamkniętą składajacą się z dwóch segmentów łukowych. Niech to będzie księżyc (czy półksiężyc) na przykład. Do tej pory ograniczenia jakie nałożyliśmy to: Polilinia zamknięta z trzema lub więcej segmentami. Musimy pochylić się nad ilością segmentów. Wychodzi na to że minimum trzy segmenty jest warunkiem koniecznym dla polilini składającej się segmentów prostoliniowych. Dla segmentów łukowych (choćby jeden łuk) bowiem, warunek spełniają już dwa segmenty. Jak tego dokonać w naszym Sel?
 
Z pomocą przychodzi nam wiedza o budowie LWPOLYLINE, a w szczególności opis DXF wypukłości (bulge) czyli kody 42. Kody dotyczą opisu każdego wierzchołka, czyli w danych obietu występują wielokrotnie. Nie czas teraz opisywać szczegółowo co to jest bulge, teraz wystarczy nam wiedza że dla segmentów prostoliniowych kod 42 wynosi 0.0, dla łukowych zaś jest różny od 0.0.
W istocie sprawdzenie czy dana polilinia składa się tylko z segmentów prostoliniowych, sprowadza się do sprawdzenia czy suma wszystkich kodów 42 jest równa zeru. Pamiętać należy także żeby bulge sprowadzić do liczb dodatnich (mogą być ujemne), tak aby nie zakłamać wyniku. Dla naszych celów przyda się także funkcja biblioteczna z CADPL-Pack'a, o nazwie cd:DXF_massoc, (całą bibliotekę można pobrać TU )
Funkcja zwraca listę wszystkich wartości zadanego kodu z listy DXF. I tak: jeśli d jest listą danych DXF obiektu, wywołanie:
(cd:DXF_massoc 42 d) może zwrócić listę (np): (-0.517875 0.919164 0.0), teraz: (mapcar 'abs (cd:DXF_massoc 42 d)) zwraca: (0.517875 0.919164 0.0)
a z: (apply '+ (mapcar 'abs (cd:DXF_massoc 42 d))) wynik będzie wynosił: 1.43704
Oczywiście dla polilini o zerowych bulge (segmenty prostoliniowe) - suma wszystkich zer, zwróci zero.
I teraz mamy już naszą zmodyfikowaną funkcję Sel:
(defun Sel (/ e d)
  (if    
    (and      
      (setq e (entsel "\nWskaż polilinię: "))
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
      (= 1 (logand 1 (cdr (assoc 70 d))))
      (if
        (zerop (apply '+ (mapcar 'abs (cd:DXF_massoc 42 d))))
        (>= (cdr (assoc 90 d)) 4)
        (>= (cdr (assoc 90 d)) 3)
      )
    )
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)

Zadanie domowe: Napisać funkcję do wyboru polilinii będącej prostokątem... :)

Odnośnik do komentarza
Udostępnij na innych stronach


(defun Sel (/ e d)
  (if    
    (and      
      (setq e (entsel "\nWskaż polilinię: "))
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
      (= 1 (logand 1 (cdr (assoc 70 d))))
      (>= 4 (cdr (assoc 90 d)))
    )
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)

Witam

Wczoraj testowałem ten kod w ZWCAD i rzeczywiście zwracana była wartość "Źle" dla polilinii zamkniętej o liczbie segmentów >= 5. Dla prostokąta było OK.

Natomiast jest druga rzecz... Dlaczego w linijce jest wartość 4 skoro dla 3 segmentów polilinii zamkniętej (trójkąta), są tylko 3 wierzchołki? Według mnie powinno być tak (>= (cdr (assoc 90 d)) 3) i to działa w ZWCAD.

 

Nawiązując jeszcze do ostatniego posta, to może być jeszcze tak, że Polilinia składa się nie tylko z samych łuków i linii. Może być np. łuk i linia, która ją zamyka (np. półkole) -ma tylko 2 segmenty oraz 2 wierzchołki. Nie jestem programistą, ale obawiam się, że kod w powyższym poście tego nie uwzględnia.

 

Jeśli chodzi o zadanie domowe, to uprościłem go trochę do 4 segmentów polilinii, wystarczy w linijce usunąć znak większości: (= (cdr (assoc 90 d)) 4) ;)

Pozdrawiam

 

Odnośnik do komentarza
Udostępnij na innych stronach

Zauważmy jednak że taki sam trójkąt możemy polilinią narysować na 2 sposoby:
1) Wskazując 3 punkty i zakończyć opcją zamknięcia. Wtedy ma 3 vertex-y i 3 segmenty
2) Wskazując 4 punkty (pierwszy i ostatni w tym samym punkcie) i dopiero zamknąć. Graficznie powstanie taki sam trójkąt, ale będzie miał 4 vertex-y, i 4 (ostatni zerowy) segmenty.

 

Oba obiekty wyglądają tak samo, są jednak różne.

 

Co do zadania domowego. Nie każdy czworobok jest prostokątem.

Edytowane przez kojacek
Odnośnik do komentarza
Udostępnij na innych stronach

Zauważmy jednak że taki sam trójkąt możemy polilinią narysować na 2 sposoby:

1) Wskazując 3 punkty i zakończyć opcją zamknięcia. Wtedy ma 3 vertex-y i 3 segmenty

2) Wskazując 4 punkty (pierwszy i ostatni w tym samym punkcie) i dopiero zamknąć. Graficznie powstanie taki sam trójkąt, ale będzie miał 4 vertex-y, i 4 (ostatni zerowy) segmenty.

 

Słuszna uwaga, ale to nie zmienia faktu, że minimalna liczba wierzchołków dla ww. przypadku jest nadal 3. Innym szczególnym przypadkiem byłaby Polilinia narysowana z dwóch linii nakładających się na siebie, a dopiero później zamknięta... ale od razu zamknięta miałaby tylko 2 wierzchołki... Według mnie taki przypadek można zweryfikować czy obszar jest większy od 0. Wolę się w to nie zagłębiać ;) A co do zadania, to uprzedziłem, że go uprościłem.

Pozdrawiam

Odnośnik do komentarza
Udostępnij na innych stronach

Słuszna uwaga, ale to nie zmienia faktu, że minimalna liczba wierzchołków dla ww. przypadku jest nadal 3. Innym szczególnym przypadkiem byłaby polilinia narysowana z dwóch linii nakładających się na siebie, a dopiero później zamknięta... ale od razu zamknięta miałaby tylko 2 wierzchołki... Według mnie taki przypadek można zweryfikować czy obszar jest większy od 0. Wolę się w to nie zagłębiać ;) A co do zadania, to uprzedziłem, że go uprościłem.

Pozdrawiam

 

Miałem kiedyś problem z mapą wygenerowaną jako DXF z jakiegoś programu. Część obiektów (co dziwne nie wszystkie), było stworzone właśnie w ten sposób: pierwszy i ostatni punkt się pokrywały. Obiekty zamknięte. Stąd chcąc sprostać w maksymalny sposób porządkowi, trzeba rozważyć i taką możliwość. Sytuację gdzie jeden lub więcej segmentów się pokrywa, od początku należy potraktować jako błędną i obiektu takiego w ogóle nie rozważać.

Tutaj ilustruję dane DXF dwóch przykładowych trójkątów (graficznie identycznych), o których mówię:

post-451-0-99910400-1444817601_thumb.png

Wynika z tego że trzeba sprawdzić czy ostatni i pierwszy wierzchołek nie pokrywają się. W zależności od wyniku obrać drogę: Albo poprawiamy, albo zostawiamy i uważamy że jest ok, albo ignorujemy.

 

Co do zadania domowego: uproszczone czy nie, nie spełnia wymagań poprawnego rozwiązania...

Edytowane przez kojacek
Odnośnik do komentarza
Udostępnij na innych stronach

Z mojej strony dodam ze program powinien rozpoznawac prawidlowa polilinie od 3 wezlow (tzn od trojkatow), jezeli nie ma zadnych lukow.

Przy poliliniach z lukami od 2 wezlow przy sprawdzeniu warunkow sumy "bulge " rozna od 0.

 

Pytanie tylko czy nasz program chcemy ograniczyc do polilinii zamknietych

czy moze powinien analizowac wszystkie mozliwosci. Jezeli celem jest stworzenie funkcji opisujacej prostokat na wskazanej polilinii

to powinna ona tez uwzgledniac te niedomkniete. Nie mam na tyle doswiadczenia aby przewidziec jak bedzie to wygladalo na pozniejszym etapie

tzn. czy mozna napisac program uniwersalny dla wszystkich przypadkow czy dla kazdego sortu bedzie potrzebny inny program.

 

Co do pracy domowej to nie mam kiedy przysiasc i napisac kod ale pomysl jest taki zeby sprawdzic nastepujace warunki:

1) ilosc wierzcholkow =4  (90 . 4)

2) Polilinia zamnkieta (70 . 1)

3) przekatne sa sobie rowne (= d1 d2), wciagnac wspolrzedne punktow  i policzyc (setq d1 (distance pt1 pt3))

(setq d2 (distance pt2 pt4)).

 

Dla prostokatow z 5 segmentow (ostatni segment zerowy) konieczna byloby sprawdzenie czy pierwszy punkt jest rowny ostatniemu.

Odnośnik do komentarza
Udostępnij na innych stronach

Zadanie domowe rozwiązane bardzo dobrze (choć bez funkcji), ale ok. Funkcja może wygladać tak:

(defun SelRect (/ e d dia)  (defun dia (p)    
(if      (not (zerop (distance (car p)(cadddr 
p))))      
(equal        (distance (car p)(caddr 
p))        (distance (cadr p)(cadddr 
p))        
0.001      )    )  
)  (if       
(and           (setq e 
(entsel "\nWskaż prostokąt: "))      (= (cdr (assoc 
0 (setq d (entget (car e))))) "LWPOLYLINE")      (= 
1 (logand 1 (cdr (assoc 70 d))))      (zerop (apply 
'+ (mapcar 'abs (cd:DXF_massoc 42 d))))      (= 
(cdr (assoc 90 d)) 4)      (dia (cd:DXF_massoc 10 
d))    )    (princ 
"\nOk")    (princ "\nŹle. ")  ))

SelRect, ma w sobie zdefiniowaną funkcję dia, która zwraca T jeżeli z listy punktów wynika że odległości 1-3 i 2-4 (przekątne) są równe (z tolerancją .001). Trzeba zwrócić uwagę na sprawdzenie czy pierwszy i ostatni punkt się nie pokrywają - eliminuje to przypadek listy 4 współrzędnych definuijących w rzeczywistości trójkąt, a nie czworokąt. Funkcja jest argumentacyjna, i wstawiona jest jako kolejny element w and. Czyli wyszło teraz tak:
- coś wybrane
- to jest LWPoly
- jest zamknięta
- nie ma łuków
- ma 4 wierzchołki
- przekątne są równe...

Wracając do naszej funkcji wyboru, można niektóre warunki zargumentyzować np. otwarta/zamknięta itp. W następnym odcinku możemy to spróbować.


Witam

Wydaje mi się, że obliczenie przekątnych nie wystarczy, bo obiekt może być skręcony o 180 st. względem osi X, a "przekątne" wyjdą takie same ;)

attachicon.gifrect.png

Pozdrawiam

 

Masz rację! Trzeba dodać jeszcze jeden inny warunek. Jaki będzie najprościej?

Odnośnik do komentarza
Udostępnij na innych stronach

Właśnie tak jak pisałem wcześniej.

attachicon.gifrect_bad.png

 

Ja bym jeszcze sprawdził kąt czy jest równy 90 stopni pomiędzy trzema kolejnymi wierzchołkami.

Pozdrawiam

No to zadanie domowe nam urosło... ;)

Proponuję dodatkowo sprawdzenie (porównanie) pól polilini: Otrzymanych z pomnożenia długości 1 i drugiego boku, oraz właściwości Area obiektu. Zdaje się że każde "skrzywienie" geometrii (pomimo równych przekątnych) powinno dać różne wyniki. Zmodyfikowana SelRect wygląda tak:

(defun SelRect (/ e d dia)
  (defun dia (l p)
    (if
      (not (zerop (distance (car p)(cadddr p))))
      (and
        (equal
          (distance (car p)(caddr p))
          (distance (cadr p)(cadddr p))
          0.001
        )
        (equal
          (* (distance (car p)(cadr p))(distance (cadr p)(caddr p)))
          (vla-get-Area (vlax-ename->vla-object l))
          0.001
        )
      )
    )
  )
  (if    
    (and      
      (setq e (entsel "\nWskaż prostokąt: "))
      (= (cdr (assoc 0 (setq d (entget (car e))))) "LWPOLYLINE")
      (= 1 (logand 1 (cdr (assoc 70 d))))
      (zerop (apply '+ (mapcar 'abs (cd:DXF_massoc 42 d))))
      (= (cdr (assoc 90 d)) 4)
      (dia (car e)(cd:DXF_massoc 10 d))
    )
    (princ "\nOk")
    (princ "\nŹle. ")
  )
)
Odnośnik do komentarza
Udostępnij na innych stronach

No to żeby nie było że tak proste zadanie można rozwiązać tak szybko dodam jeszcze swoje uwagi:

1. Co się stanie jeśli Użytkownik zamiast posłusznie wskazać prostokąt naciśnie na klawiaturze [ESC]? Zawsze, ale to absolutnie zawsze jeśli pozwalamy Użytkownikowi zrobi cokolwiek należy użyć obsługi wyjątków vl-catch-all-apply

2. Będąc pod wpływem idei Roberta C. Martina dotyczącej czystości kodu chciałbym jeszcze zwrócić uwagę na czytelność kodu.
 - Dziś wiemy że DXF 70 pozwala sprawdzić czy Polilinia jest zamknięta.  ale czy będzie to dla nas jasne za kilka czy kilkanaście miesięcy, jeśli cały ten czas będziemy pracować w LISP to pewnie tak, ale być może kiedyś wrócimy do dawno zapomnianego kodu, który działał ale musimy w nim coś zmienić będziemy się zastanawiac "o co chodziło z tym 129". A może po kilku miesiącach musimy dodać obsługę okręgów. Nie wiem czy okrąg ma DXF 70 i jakie jest jego znaczenie , ale skoro jest okręgiem to na pewno jest zamknięty i nie ma potrzeby sprawdzanie tego warunku. Warto w takiej sytuacji mieć dokładnie jedno miejsce gdzie tego szukać. Dlatego sugeruję opakować każdy warunek funkcją.

 - być może w przyszłości to nie twórca programu a jego współpracownik, następca, pomocnik, uczeń czy ktokolwiek będzie czytał ten sam kod i będzie zastanawiał się czy funkcja "dia" ma porównywać długości przekątnych, czy jaka jest jej rola. Przeczyta i zrozumie, ale na ten czas odwróci swoją uwagę od czegoś co było ważniejsze bo miał zadanie sprawdzić/dodać cośtam co nie ma się nijak do przekątnych  Dlatego lepiej jest nazywać funkcje i zmienne w taki sposób, żeby czytając jasne było co ma się dziać w kodzie. zainteresowany szczegółami implementacji może sobie znaleźć definicję funkcji i ją przeanalizować.

3. Rozumiem że dla uproszczenia przykładu można użyć (princ "\nŹle. "), ale przestrzegam przed używaniem takiego rozwiązania w kodzie produkcyjnym . Lepiej jest stałe tekstowe przechowywać gdzieś indziej, i tylko odwoływać się do nich w kodzie po symbolu.
Wszytko jest OK, puki pracujemy na swoim komputerze, na znanej stabilnej wersji programu. Aż tu nagle niespodzianie pewnego dnia ktoś nam proponuje żeby uruchomić ten kod na innej maszynie, cieszy oczywiście że nasza praca jest przez kogoś doceniona, ale tylko do czasu kiedy zamiast "Wskaż prostokąt: " zobaczymy "WskaĹĽ prostokÄ…t: " poprostu niektóre systemy działają na Unicode, ale inne NIE. Oczywiście zawsze możemy zmienić każdy krzaczek na poprawną literkę, ale wtedy mamy już 2 wersje kodu do utrzymania i musimy o tym pamiętać przy każdej zmianie wprowadzonej do kodu.
Być może pewnego dnia zechcemy nasz program udostępnić (być może za niewielką opłatą ;) ) komuś kto nie zna naszego języka, wówczas tłumaczymy 1 plik z tekstami a nie musimy wyszukiwać w kodzie wszystkich tekstów.
Podobnie można przejechać się na formatowaniu daty, ale to już temat na inną pogadankę.

Moja propozycja kodu źródłowego jest taka:

(defun SelRect (/ select SelectedEntity IsRectangle e d dia OutVal)
  (defun IsRectangle (Entity / EntityList IsPolyline IsClosed DiagonalsAreEqual AreaIsCorrect NumberOfVertex )
	(setq EntityList (entget Entity) )
	(progn 	 ; Locals
	(defun IsPolyline (Entity / ) 
		(= (cdr (assoc 0 Entity)) "LWPOLYLINE")  
	)
	(defun IsClosed (EntityList / ) 
		(= 1 (logand 1 (cdr (assoc 70 EntityList))))
	 )
	(defun NumberOfVertex (EntityList / ) 
		(cdr (assoc 90 EntityList))
	)
	(defun HasArcSegment (EntityList / ) 
		(zerop (apply '+ (mapcar 'abs (cd:DXF_massoc 42 EntityList))))
	)
	
	(defun DiagonalsAreEqual (Entity  / p ) 
		(setq p (cd:DXF_massoc 10 Entity ) )
	  (if (and
	  (not (zerop (distance (car p)(cadddr p))))
      (equal
         (distance (car p)(caddr p))
         (distance (cadr p)(cadddr p))
         0.001
       )  
      )
	  )
	)
	
	(defun AreaIsCorrect (Entity / p ) 
		(setq p (cd:DXF_massoc 10 Entity ) )
		(equal
          (* (distance (car p)(cadr p))(distance (cadr p)(caddr p)))
          (vla-get-Area (vlax-ename->vla-object Entity))
          0.001
        )
	)
	
	
    )
	(if (and
	  (IsPolyline EntityList)
	  (IsClosed EntityList)
	  (= (NumberOfVertex EntityList ) 4)
	  (not (HasArcSegment EntityList))
      (DiagonalsAreEqual Entity)
	  (AreaIsCorrect Entity)	  
	    )
    )
  )
    
  (setq select (vl-catch-all-apply 'entsel (list "\nWskaż prostokąt: ")))	; przechwytuję błąd jeśli Użytkownik wciśnie [ESC] 
  (if (not (vl-catch-all-error-p select))	; sprawdzam czy wybór jest poprawny 
	(progn
	 (setq SelectedEntity (car select ))
	 (if (IsRectangle SelectedEntity)
		(setq OutVal 'IsRectangle )
		(setq OutVal 'NOTRectangle )
	 )
	)
	(setq OutVal 'NothingSelected )
  ) 
  OutVal
)

Przepraszam jeśli nie działa, zmiany wprowadzałem w samym tekście bo przyznam że nie mam zainstalowanego CADPacka . Obiecuje że zainstaluje i sprawdzę kiedy będę miał trochę więcej czasu.

Odnośnik do komentarza
Udostępnij na innych stronach

No to żeby nie było że tak proste zadanie można rozwiązać tak szybko dodam jeszcze swoje uwagi:

1. Co się stanie jeśli Użytkownik zamiast posłusznie wskazać prostokąt naciśnie na klawiaturze [ESC]? Zawsze, ale to absolutnie zawsze jeśli pozwalamy Użytkownikowi zrobi cokolwiek należy użyć obsługi wyjątków vl-catch-all-apply

2. Będąc pod wpływem idei Roberta C. Martina dotyczącej czystości kodu chciałbym jeszcze zwrócić uwagę na czytelność kodu.

 - Dziś wiemy że DXF 70 pozwala sprawdzić czy polilinia jest zamknięta.  ale czy będzie to dla nas jasne za kilka czy kilkanaście miesięcy, jeśli cały ten czas będziemy pracować w LISP to pewnie tak, ale być może kiedyś wrócimy do dawno zapomnianego kodu, który działał ale musimy w nim coś zmienić będziemy się zastanawiac "o co chodziło z tym 129". A może po kilku miesiącach musimy dodać obsługę okręgów. Nie wiem czy okrąg ma DXF 70 i jakie jest jego znaczenie , ale skoro jest okręgiem to na pewno jest zamknięty i nie ma potrzeby sprawdzanie tego warunku. Warto w takiej sytuacji mieć dokładnie jedno miejsce gdzie tego szukać. Dlatego sugeruję opakować każdy warunek funkcją.

 - być może w przyszłości to nie twórca programu a jego współpracownik, następca, pomocnik, uczeń czy ktokolwiek będzie czytał ten sam kod i będzie zastanawiał się czy funkcja "dia" ma porównywać długości przekątnych, czy jaka jest jej rola. Przeczyta i zrozumie, ale na ten czas odwróci swoją uwagę od czegoś co było ważniejsze bo miał zadanie sprawdzić/dodać cośtam co nie ma się nijak do przekątnych  Dlatego lepiej jest nazywać funkcje i zmienne w taki sposób, żeby czytając jasne było co ma się dziać w kodzie. zainteresowany szczegółami implementacji może sobie znaleźć definicję funkcji i ją przeanalizować.

3. Rozumiem że dla uproszczenia przykładu można użyć (princ "\nŹle. "), ale przestrzegam przed używaniem takiego rozwiązania w kodzie produkcyjnym . Lepiej jest stałe tekstowe przechowywać gdzieś indziej, i tylko odwoływać się do nich w kodzie po symbolu.

Wszytko jest OK, puki pracujemy na swoim komputerze, na znanej stabilnej wersji programu. Aż tu nagle niespodzianie pewnego dnia ktoś nam proponuje żeby uruchomić ten kod na innej maszynie, cieszy oczywiście że nasza praca jest przez kogoś doceniona, ale tylko do czasu kiedy zamiast "Wskaż prostokąt: " zobaczymy "WskaĹĽ prostokÄ…t: " poprostu niektóre systemy działają na Unicode, ale inne NIE. Oczywiście zawsze możemy zmienić każdy krzaczek na poprawną literkę, ale wtedy mamy już 2 wersje kodu do utrzymania i musimy o tym pamiętać przy każdej zmianie wprowadzonej do kodu.

Być może pewnego dnia zechcemy nasz program udostępnić (być może za niewielką opłatą ;) ) komuś kto nie zna naszego języka, wówczas tłumaczymy 1 plik z tekstami a nie musimy wyszukiwać w kodzie wszystkich tekstów.

Podobnie można przejechać się na formatowaniu daty, ale to już temat na inną pogadankę.

Moja propozycja kodu źródłowego jest taka:

(defun SelRect (/ select SelectedEntity IsRectangle e d dia OutVal)
  (defun IsRectangle (Entity / EntityList IsPolyline IsClosed DiagonalsAreEqual AreaIsCorrect NumberOfVertex )
	(setq EntityList (entget Entity) )
	(progn 	 ; Locals
	(defun IsPolyline (Entity / ) 
		(= (cdr (assoc 0 Entity)) "LWPOLYLINE")  
	)
	(defun IsClosed (EntityList / ) 
		(= 1 (logand 1 (cdr (assoc 70 EntityList))))
	 )
	(defun NumberOfVertex (EntityList / ) 
		(cdr (assoc 90 EntityList))
	)
	(defun HasArcSegment (EntityList / ) 
		(zerop (apply '+ (mapcar 'abs (cd:DXF_massoc 42 EntityList))))
	)
	
	(defun DiagonalsAreEqual (Entity  / p ) 
		(setq p (cd:DXF_massoc 10 Entity ) )
	  (if (and
	  (not (zerop (distance (car p)(cadddr p))))
      (equal
         (distance (car p)(caddr p))
         (distance (cadr p)(cadddr p))
         0.001
       )  
      )
	  )
	)
	
	(defun AreaIsCorrect (Entity / p ) 
		(setq p (cd:DXF_massoc 10 Entity ) )
		(equal
          (* (distance (car p)(cadr p))(distance (cadr p)(caddr p)))
          (vla-get-Area (vlax-ename->vla-object Entity))
          0.001
        )
	)
	
	
    )
	(if (and
	  (IsPolyline EntityList)
	  (IsClosed EntityList)
	  (= (NumberOfVertex EntityList ) 4)
	  (not (HasArcSegment EntityList))
      (DiagonalsAreEqual Entity)
	  (AreaIsCorrect Entity)	  
	    )
    )
  )
    
  (setq select (vl-catch-all-apply 'entsel (list "\nWskaż prostokąt: ")))	; przechwytuję błąd jeśli Użytkownik wciśnie [ESC] 
  (if (not (vl-catch-all-error-p select))	; sprawdzam czy wybór jest poprawny 
	(progn
	 (setq SelectedEntity (car select ))
	 (if (IsRectangle SelectedEntity)
		(setq OutVal 'IsRectangle )
		(setq OutVal 'NOTRectangle )
	 )
	)
	(setq OutVal 'NothingSelected )
  ) 
  OutVal
)

Przepraszam jeśli nie działa, zmiany wprowadzałem w samym tekście bo przyznam że nie mam zainstalowanego CADPacka . Obiecuje że zainstaluje i sprawdzę kiedy będę miał trochę więcej czasu.

Pozwolę sobie wyrazić swoją opinię, w sprawie trzech powyższych punktów.

Ad 1. Zgoda, ale chyba za wcześnie na to wszystko. Do tej pory odnosiłem wrażenie że wątek mając nieco charakter edukacyjny, powoli rośnie zwiększając poziom zaawansowania. Zwłaszcza że kolega Iskra (zakładając wątek) sam nadmienił że się dopiero uczy. Napisał kawałek dość dobrego kodu (w ogólności co do zasady), nie wystrzegł się paru błędów, ale nie zniechęcajmy go jednak na samym początku. Na vl-catch-all-apply przyjdzie jeszcze czas. Na razie bez radykalnego zawsze i absolutnie. Póki co proste rzeczy, pytania i odpowiedzi. Chce wiedzieć, pyta, ma potencjał, na wszystko przyjdzie czas. Popatrz (że znów wrócę do CAD-Pack'a), nie mówię że wszystko jest do d*py, weź no funkcję cd:USR_EntSelObj, daj se spokój bo ona jest git... Na marginesie, warto na nią też popatrzeć.

Ad 2. Różnić się będę także co do rzekomej czytelności kodu. Wydaje mi się że przedstawiona propozycja zaciemnia a nie rozjaśnia. Ogólnie jestem zwolennikiem stosowania funkcji w funkcji (mającej charakter lokalny) w dwóch przypadkach. Po pierwsze: podfunkcja (tak ją nazwijmy umownie), wywoływana jest wielokrotnie, lub (po drugie), jest na tyle obszerna że zaciemnia właśnie kod główny. Ten drugi przypadek widać w zastosowaniu funkcji dia wewnątrz SelRect. Wszystkie inne wywołania w and, (typ obiektu, zamknięcie, bulge itp.) wydają się na tyle proste że nie widzę potrzeby definiowania ich jako osobne funkcje. Zwłaszcza jako funkcje lokalne (mające zasięg tylko wewnątrz innej jednej funkcji). Spójrzmy, przykład pierwszy z brzegu. Kod:

 

(defun IsPolyline (Entity / )  
  (= (cdr (assoc 0 Entity)) "LWPOLYLINE") 
)

właściwie niczego nie wnosi (oprócz zwiększenia objętości), bowiem samo:

 

(= (cdr (assoc 0 Entity)) "LWPOLYLINE")

wydaje się być i tak czytelne. Ewentualnie można je opatrzyć komentarzem.

Powtórzę raz jeszcze - zwłaszcza jako funkcja lokalna. Co innego gdyby to była funkcja biblioteczna (mogąca mieć wielokrotne zastosowanie w wielu miejscach). Jestem zagorzałym zwolennikiem tworzenia funkcji bibliotecznych. Jednak uważam, należy zachować tutaj pewien umiar i szukać możliwie uniwersalnego zastosowania. Bowiem (jeszcze na tym przykładzie), gdyby nawet twoja IsPolyline, była nawet funkcją biblioteczną, jej sens i tak jest mocno wątpliwy. Bowiem tym tropem trzeba by stworzyć tyle funkcji ile jest typów obiektów (Isline, IsArc, IsCircle... etc.) Nie trzeba wiele analizować że nie ma to sensu. W tym przypadku funkcja biblioteczna mogłaby być jedna i sprawdzać czy podany obiekt jest akceptowany wg jakiegoś kryterium (tutaj rodzaj obiektu). Na przykład definicja:

 

(defun GetTypeObj (Ent TypeLst)  
  (car (member (cdr (assoc 0 (entget Ent))) TypeLst))
)

i potem przykładowe wywołania:

 

(GetTypeObj (car (entsel)) '("LWPOLYLINE" "LINE" "ARC"))

pozwala określić ze wskazania czy to jest polilnia albo linia albo łuk

czy:

 

(GetTypeObj (car (entsel)) '("LWPOLYLINE"))

zawęzić typ tylko do polilinii.

Podsumowując - w mojej opinii - poprzez przerost definicji funkcji zaciemniłeś, a nie rozjaśniłeś kod.

 

Ad 3. Powtórzę to co w Ad 1. Ogólnie zgoda, niemniej tutaj testujemy budowanie prostej funkcji ilustrując jej działanie, tak aby była zrozumiała, na tym poziomie ogólności. W tej chwili potrzebujemy informacji czy wybór jest ok czy be. Gdy to przejdziemy nastąpić może ciąg dalszy (coś się dzieje gdy jest ok, coś innego gdy jest be).

Edytowane przez kojacek
Odnośnik do komentarza
Udostępnij na innych stronach

Dlaczego jeszcze za wcześnie na obsługę sytuacji wyjątkowych? Zaprezentowałem przykład, jeśli Iskra czy ktokolwiek zechce z niego skorzystać to zapraszam, jeśli nie zrozumie na bazie przykładu , chętnie wyjaśnię wszelkie wątpliwości. Chyba że to jakiś kurs z narzuconym harmonogramem, to w takim razie nie wcinam się więcej ;)

Akurat w temacie obsługi spontaniczności Użytkowników pozostanę przy swoim radykalnym zawsze i absolutnie zachęcając do przyswojenia sobie tego nawyku jak najwcześniej przez opakowanie go w funkcję biblioteczną , oczywiście polecam CAD-Pack nie nawołuję do odkrywania koła na nowo, natomiast pozostawienie funkcji przekazujących działanie Użytkownikowi bez przechwycenia sytuacji niepożądanych kojarzy mi się ze strzelaniem z dowolnej broni z zamkniętymi oczami.

Nie jest moim celem propagowanie funkcji lokalnych używam ich rzadko stawiając na biblioteki. Sama funkcja IsPolyline jest nieszczęśliwa wcale jej nie bronię. GetTypeObj jest znacznie lepsza. Ale już ocenę czytelności np

HasArcSegment

vs.

(zerop (apply '+ (mapcar 'abs (cd:DXF_massoc 42 EntityList))))

i kolejnych pozostawmy tym, którzy to będą czytali. Jak każdy twórcy mam zbyt osobisty stosunek do swoich tworów by ocenić to obiektywnie.

Budujemy prostą funkcję, OK. Jest już zrozumiała, również OK. Potrzebowaliśmy prostej informacji i ja otrzymaliśmy. Może właśnie teraz  przejdźmy dalej wskazując jaki kierunek może mieć rozwój tej funkcji. Czy to już zbyt szybko czy nie również pozostawiam ocenie tych, którym okaże się to przydatne, lub nie.

Odnośnik do komentarza
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Usuń formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie