To understand why your code is producing undesired results, walk through the code expression by expression and analyse the result of each evaluation:
On first pass:
objtype = nilTherefore:
(NOT (= objtype "VIEWPORT")) = Tvalidating the test expression for the
while loop.
1. User has selected an object, but NOT a Viewport:vport = (<Entity name: abc123> (123.0 456.0 0.0))
obj = <Entity name: abc123>
objdata = ((0 . "CIRCLE") (5 . "ABC") ... )
objtype = "CIRCLE"Now the
alert expression is evaluated, regardless of the object type:
(ALERT "This was indeed a viewport, thankyou")All expressions within the
while loop have now been evaluated, so the test expression is again evaluated:
(NOT (= objtype "VIEWPORT")) = (NOT (= "CIRCLE" "VIEWPORT")) = TSo the loop continues:
2. User does not select anything:vport = nil
obj = nil
objdata = ; error: bad argument type: lentityp nil
objtype = "CIRCLE" (<-- still holds previous value)The
entget expression will return an error as the entity name argument is
nil (since
obj is
nil).
3. User selects a Viewport:vport = (<Entity name: abc123> (123.0 456.0 0.0))
obj = <Entity name: abc123>
objdata = ((0 . "VIEWPORT") (5 . "ABC") ... )
objtype = "VIEWPORT"The
alert expression is again evaluated (though again regardless of the object type):
(ALERT "This was indeed a viewport, thankyou")The test expression is then evaluated:
(NOT (= objtype "VIEWPORT")) = (NOT (= "VIEWPORT" "VIEWPORT")) = (NOT T) = nilThe test expression returns
nil, hence the
while loop is terminated.
Whenever you are uncertain as to why a specific block of code is behaving in an undesired way, I would always recommend stepping through the code, expression by expression, as I have above, feeding the expressions each possible case (i.e. user selects invalid object / user fails to select anything / user selects viewport) and noting the returns of each evaluation; the reason for the unexpected behaviour should soon become apparent.
In fact, I would recommend this methodology when attempting to understand
any portion of code: step through each expression as if you were playing the role of the AutoLISP interpreter: pass each expression the arguments stated in the code and analyse the return of each evaluation.
For the task at hand, I would personally recommend the following code:
)
)
)
(princ "\nMissed, try again.") )
(princ "\nThank you for selecting a Viewport.") (princ "\nNothing selected, goodbye.") )
)
I would opt for
ssget over
entsel where viewport selection is concerned, since the
ssget filter list will permit the user to select polygonal viewports in addition to rectangular viewports - to achieve the same behaviour using
entsel you would need to test the selected entity for the existence of a pointer to the associated
VIEWPORT entity, (i.e. test for the
(102 . "{ACAD_REACTORS") (102 . "}") pair surrounding the
VIEWPORT entity).
When using
ssget, you could also enable the
NOMUTT system variable to facilitate the use of a custom selection prompt.