@john.uhden wrote:
Beginner's Programming Challenge
--->%
This challenge is to write a function that takes two (2) entity names of two
(2) separate circles to see if they are concentric. The function should return
either T or 1 for true and nil for not concentric.
--->%
NOTE: Ignoring instructions to keep code to a minimum number of lines because line count is not related to the solution.
Steps to solve:
1. Allow user to select circles.
2. Pass two ent names to a function that checks to see if two coordinates match.
Potential Problems:
1. What if user hits ESC during selection(s).
2. What if user does not select a circle (and selects a line, for example).
SOLUTION:
1. allow user to pick an ent.
(defun pick-something ()
;; pick something
;;
;; RETURNS: entname or nil
(car (entsel)) )
2. define a function that accepts two ent names and checks to see if two coordinates match.
(defun check-concentric (ent1 ent2)
;; check-concentric
;; Accepts two entity names and checks to see if center points are the same.
;;
;; RETURNS: T or NIL
;;
(apply 'and
;; we will apply the AND function to see if we get all T's.
(mapcar '=
;; We will iterate the list and compare each items in
;; both lists to see if they are the same (this
;; should return either "nil" or "T" for each item checked.
(assoc 10 (entget ent1))
;; this call shoulc return a list of numbers like:
;; (10 20.0044 22.5881 0.0)
(assoc 10 (entget ent2)))) )
TRIAL:
(check-concentric (pick-something) (pick-something))
EVALUATION: UGH! Horrible!
1. We do not check to see if user selects a circle.
2. we do not account for mis-picks
3. Our `check-concentric` function is doing too much; functions should do "one thing" or as little as possible.
Problems 1 and 2 are bigger topics but 3 is easy to fix so let's address that right away.
We can divide the tasks of checking equality and getting entities into smaller function(s).
Here is a function that checks two lists for equality.
(defun check-eq (lst1 lst2)
;; check-eq
;; Accepts two lists to check to see if equal
;;
;; RETURNS: T of NIL
;;
;; TEST: (check-eq '(1 2 3 4) '(1 2 3 4))
;; > T
;; (check-eq '(1 2 3 4) '(a b c d))
;; > nil
(apply 'and (mapcar '= lst1 lst2)) )
Now we can redo our `check-concentric` function
(defun check-concentric (ent1 ent2)
;; check-concentric
;; Accepts two entity names and checks to see if center points are the same.
;;
;; RETURNS: T or NIL
(check-eq
(assoc 10 (entget ent1))
(assoc 10 (entget ent2))) )
EVALUATION: We managed to fix problem #3. Let's move on.
Problem 2 (mis-picks).
We can account for mis-picks by looping until we actually get a good pick from the user.
(defun pick-something ()
;; pick-something
;; This offers a slightly better `entsel` routine
;; which will keep looping until the user picks
;; an item.
;;
;; RETURNS: entname or nil
(cond
((car (entsel)))
((princ "\nYou missed, try again.")
(pick-something))) )
; EXAMPLE USE:
; (check-concentric (pick-something) (pick-something))
Problem 1 (check ent type).
We can check to see if the item picked is actually a circle like this:
(defun check-circle (ent)
;; check-circle
;; Accepts an ent-name and checks to see if
;; it is a circle type
;;
;; RETURNS: T or NIL
(eq "CIRCLE" (cdr (assoc 0 (entget ent)))) )
We can use our `check-circle` function like this:
(defun check-two-circles ( / ent1 ent2)
(setq ent1 (pick-something)
ent2 (pick-something))
(if (and
(check-circle ent1)
(check-circle ent2))
(check-concentric ent1 ent2))
)
So, our final code should be:
FINAL CODE:
NOTE: This should be "better" but it still isn't "great/good" nor is it the only way to solve this problem(s). To develop "good" code takes time, tests, and forethought. This was just a good introduction for new programmers into proper "thought process".
(defun check-eq (lst1 lst2)
;; check-eq
;; Accepts two lists to check to see if equal
;;
;; RETURNS: T of NIL
;;
;; TEST: (check-eq '(1 2 3 4) '(1 2 3 4))
;; > T
;; (check-eq '(1 2 3 4) '(a b c d))
;; > nil
(apply 'and (mapcar '= lst1 lst2)) )
(defun check-concentric (ent1 ent2)
;; check-concentric
;; Accepts two entity names and checks to see if center points are the same.
;;
;; RETURNS: T or NIL
;;
(check-eq
(assoc 10 (entget ent1))
(assoc 10 (entget ent2))) )
(defun pick-something ()
;; pick-something
;; This offers a slightly better `entsel` routine
;; which will keep looping until the user picks
;; an item.
;;
;; RETURNS: entname or nil
(cond
((car (entsel)))
((princ "\nYou missed, try again.")
(pick-something))) )
(defun check-circle (ent)
;; check-circle
;; Accepts an ent-name and checks to see if
;; it is a circle type
;;
;; RETURNS: T or NIL
(eq "CIRCLE" (cdr (assoc 0 (entget ent)))) )
(defun check-two-circles ( / ent1 ent2)
;; Checks if two circles are concentric
;;
;; RETURNS: T or NIL
(setq ent1 (pick-something)
ent2 (pick-something))
(if (and
(check-circle ent1)
(check-circle ent2))
(check-concentric ent1 ent2))
)