Renaming Dynamic Block Visibility States using VBA - vba

How can I change or rename visibility states for a dynamic block in AutoCAD using VBA, similar to clicking RENAME in the Visibility State dialog box which appears when issuing the BVSTATE command in the Block Editor?
Thanks so much for your help.

In short, it is not possible to rename Dynamic Block Visibility States directly using the LISP or VBA API, without resorting to invoking standard AutoCAD commands, for example, using the AutoLISP command function, or sendcommand method.
Dynamic Block Parameters contained within a block definition are not exposed to the ActiveX object model and therefore cannot be modified using Visual LISP or VBA.
Such parameters are exposed to Vanilla AutoLISP by examining the DXF data stored within the Extension Dictionary of the BLOCK_RECORD entity, but such data cannot be modified using entmod, nor does it yield any relevant properties following conversion to an equivalent VLA-Object representation.
For what it's worth, you can access the Dynamic Block Parameter DXF data using the following route through the AutoLISP API:
First, obtain the BLOCK entity:
(setq bl (tblobjname "block" "YourBlockName"))
Then obtain the parent BLOCK_RECORD entity:
(setq br (cdr (assoc 330 (entget bl))))
Now obtain the Extension Dictionary from DXF group 360 (additional checks for the presence of "{ACAD_XDICTIONARY" against DXF group 102 should be used in production code):
(setq d1 (cdr (assoc 360 (entget br))))
Now search this dictionary for the ACAD_ENHANCEDBLOCK entry:
(setq d2 (dictsearch d1 "acad_enhancedblock"))
This will yield the DXF data for the ACAD_EVALUATION_GRAPH entity.
You can then iterate over the DXF group 360 within the DXF data to obtain the DXF data for each Dynamic Block Parameter found within the block definition, e.g.:
_$ (foreach dxf d2 (if (= 360 (car dxf)) (print (cdr (assoc 0 (entget (cdr dxf)))))))
"BLOCKPOLARPARAMETER"
"BLOCKPOLARGRIP"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKPOLARSTRETCHACTION"
"BLOCKFLIPPARAMETER"
"BLOCKFLIPGRIP"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKFLIPACTION"
"BLOCKVISIBILITYPARAMETER"
"BLOCKVISIBILITYGRIP"
"BLOCKGRIPLOCATIONCOMPONENT"
"BLOCKGRIPLOCATIONCOMPONENT"

Related

What exactly does it mean for a handler to "decline" to handle a signal?

In the HyperSpec entry for HANDLER-BIND, it says that a handler can decline to handle a signal.
However, the linked glossary entry for decline to handle a signal is not very enlightening:
decline v. (of a handler) to return normally without having handled the condition being signaled, permitting the signaling process to continue as if the handler had not been present.
This definition begs and does not answer the question of what constitutes not returning normally?
Is there a full list of actions that constitute "handling" a signal?
I know from hands-on experience that INVOKE-RESTART appears to fit this criterion. But is that the only way for a handler to "handle" a signal, or are there others?
I think to understand the true meaning of “handle”, you should consider how the condition system works under the hood. Kent Pitman's sample implementation, written during the standardization process, is a good place to start (even though it has kludgy stuff like essentially implementing an entire object system, since CLOS was not yet part of the language).
Roughly speaking, the action of handler-bind is to set up a special variable, which we will call *handler-clusters*, so that it holds lists of lists of (type . function) pairs, corresponding to the list of bindings. A possible definition is
(defmacro handler-bind (bindings &body forms)
`(let ((*handler-clusters* (cons (list (mapcar #'(lambda (x) `(cons ',(car x) ,(cadr x)))
bindings))
*handler-clusters*)))
,#forms))
The signal function, then, goes through the clusters; if it finds one for the correct condition type, it calls the associated function. Definition:
(defun signal (datum &rest arguments)
(let ((condition (coerce-to-condition datum arguments :default 'simple-condition))
(*handler-clusters* *handler-clusters*)) ; save current value
(when (typep condition *break-on-signals*)
(with-simple-restart (continue "Continue the signaling process")
(break "Break caused by *BREAK-ON-SIGNALS*")))
(loop for cluster := (pop *handler-clusters*) do
(loop for binding in cluster do
(when (typep condition (car binding))
(funcall (cdr binding) condition)))))
nil)
where coerce-to-condition is a function that deals with “condition designators”. A subtle point is that we can't simply (loop for cluster in *handler-clusters* do …), because if, during the call of a handler, a condition of the same type as that which is being handled is signaled, the handler would be called recursively, which is probably not desirable. Thus the previous value is saved and we destructively pop the cluster off.
Now, remember that Common Lisp allows closures over block names and tagbody tags. That is, after the definitions
(defvar *transfer-control*)
(defun weird (function)
(tagbody
(go :start)
:tag
(print 'transferred)
(return-from weird)
:start
(setf *transfer-control* (lambda () ; captures the tag :tag
(go :tag)))
(funcall function)))
a form like
(weird (lambda () (funcall *transfer-control*)))
is allowed, and will print 'transferred. The control transfer happens, in a sense, outside of the lexical scope of the tagbody; the ability to (go :tag) has “escaped” its enclosing scope. (It would be an error to funcall *transfer-control* after weird has returned, because the dynamic extent of the tagbody has been exited.)
All this is to say that calling an ordinary Common Lisp function can cause a transfer of control, instead of returning a value. Calling *transfer-control* does nothing but unwind the dynamic environment up to the point of the tagbody, and then jumps to :tag. The function doesn't “return” in the usual sense of the term, because the evaluation of the expression in which it is embedded will be abruptly stopped, never to resume. (With weird and *transfer-control*, we've defined a primitive substitute for catch and throw that simply transfers control but doesn't convey a value at the same time. To see definitions of tagbody, block, and catch in terms of each other, see Henry Baker's “Metacircular Semantics for Common Lisp Special Forms”.)
Therefore, when signal calls the handler for a condition, two things can happen:
The handler transfers control, aborting the evaluation of signal and unwinding the stack to the place to which control was transferred.
The handler does not transfer control, but returns a value. In this case, as the definition above shows, signal will continue looking for a handler until reaching the end of *handler-clusters* or until another handler transfers control. This is called “declining”.
(In a way, it can also do neither or both, by, for instance, calling signal on another condition. The specification calls this deferring.)
For example, the hyperspec gives a sample expansion for handler-case. The form
(handler-case form
(type1 (var1) . body1)
(type2 (var2) . body2) ...)
becomes (ignoring problems of variable capture)
(block return-point
(let ((condition nil))
(tagbody
(handler-bind ((type1 #'(lambda (temp)
(setq condition temp)
(go :handler-tag-1)))
(type2 #'(lambda (temp)
(setq condition temp)
(go :handler-tag-2)))
...)
(return-from return-point form))
:handler-tag-1
(return-from return-point (let ((var1 condition)) . body1))
:handler-tag-2
(return-from return-point (let ((var2 condition)) . body2))
...)))
(I've rewritten the hyperspec's code to be more readable, although unhygienic, and I also fixed an error in the original.)
As you can see, the handlers established by handler-case unconditionally transfer control if called. Thus handler-case handlers definitely “handle” conditions.
Restarts are implemented in a very similar way, by restart-bind setting up the dynamic environment and invoke-restart using it to call a function. Because restarts are just functions, they need not transfer control, and so calling invoke-restart is not always an act of “handling”, although it is if the restart was established by restart-case or with-simple-restart—or, of course, if the restart transfers control.
The glossary describes things exactly but tersely: if a handler returns normally, it has declined to handle the condition. In order to handle the condition, it must instead transfer control so that it never returns. In CL this means it must transfer control 'upwards'.
An example might be
(block done
(handler-bind ((error (lambda (c)
(return-from done c))))
(error "exploded")))
Here the handler for conditions of type error is handling the condition, since it never returns normally but rather returns from the done block.
A full description of this is here.
Apologies for any indentation / paren errors: my lisp machine has emitted smoke so I am typing this on a more primitive system.

Common Lisp: How do I set a variable in my parent's lexical scope?

I want to define a function (not a macro) that can set a variable in the scope its called.
I have tried:
(defun var-set (var-str val)
(let ((var-interned
(intern (string-upcase var-str))))
(set var-interned val)
))
(let ((year "1400"))
(var-set "year" 1388)
(labeled identity year))
Which doesn't work because of the scoping rules. Any "hacks" to accomplish this?
In python, I can use
previous_frame = sys._getframe(1)
previous_frame_locals = previous_frame.f_locals
previous_frame_locals['my-var'] = some_value
Any equivalent API for lisp?
You cannot do that because after compilation the variable might not even exist in any meaningful sense.
E.g., try to figure out by looking at the output of (disassemble (lambda (x) (+ x 4))) where you
would write the new values of x.
You have to tell both the caller and the callee (at compile time!) that the variable is special:
(defun set-x (v)
(declare (special x))
(setq x v))
(defun test-set (a)
(let ((x a))
(declare (special x))
(set-x 10)
x))
(test-set 3)
==> 10
See Dynamic and Lexical variables in Common Lisp for further details on lexical vs dynamic bindings.
You can't. This is why it is called lexical scope: you have access to variable bindings if and only if you can see them. The only way to get at such a binding is to create some object for which it is visible and use that. For instance:
(defun foo (x)
(bar (lambda (&optional (v nil vp)
(if vp (setf x vp) x))))
(defun bar (a)
...
(funcall a ...))
Some languages, such as Python have both rather rudimentary implementations of variable bindings and a single implementation (or a mandated implementation) which allow you to essentially poke around inside the system to subvert lexical scoping. Some CL implementations may have rudimentary implementation of variable bindings (probably none do) but Common Lisp the language does not mandate such implementations and nor should it.
As an example of the terrible consequences of mandating that some kind of access to lexical variables must be allowed consider this:
(defun outer (n f)
(if (> n 0)
(outer (g n) f)
(funcall f)))
If f could somehow poke at the lexical bindings of outer this would mean that all those bindings would need to exist at the point f was called: tail-call elimination would thus be impossible. If the language mandated that such bindings should be accessible then the language is mandating that tail-call elimination is not possible. That would be bad.
(It is quite possible that implementations, possibly with some debugging declarations, allow such access in some circumstances. That's very different than the language mandating such a thing.)
What are you trying to achieve?
What about a closure? Write the defun inside the let, and create an accessor and a setter function if needed.
(let ((year "1400"))
(defun current-year ()
year)
(defun set-year (val)
(setf year val)))
and
CL-USER> (current-year)
"1400"
CL-USER> (set-year 1200)
1200
CL-USER> (current-year)
1200
That Python mechanism violates the encapsulation which motivates the existence of lexical scope.
Because a lexical scope is inaccessible by any external means other than invocations of function bodies which are in that scope, a compiler is free to translate a lexical scope into any representation which performs the same semantics. Variables named in the source code of the lexical scope can disappear entirely. For instance, in your example, all references to year can be replaced by copies of the pointer to the "1400" string literal object.
Separately from the encapsulation issue there is also the consideration that a function does not have any access at all to a parent lexical scope, regardless of that scope's representation. It does not exist. Functions do not implicitly pass their lexical scope to children. Your caller may not have a lexical environment at all, and there is no way to know. The essence of the lexical environment is that no aspect of it is passed down to children, other than via the explicit passage of lexical closures.
Python's feature is poorly considered because it makes programs dependent on the representation of scopes. If a compiler like PyPy is to make that code work, it has to constrain its treatment of lexical scopes to mimic the byte code interpreted version of Python.
Firstly, each function has to know who called it, so it has to receive some parameter(s) about that, including a link to the caller's environment. That's going to be a source of inefficiency even in code that doesn't take advantage of it.
The concept of a well-defined "previous frame" means that the compiler cannot merge together frames. Code which expects some variable to be in the third frame up from here will break if those frames are all inlined together due to a nested lexical scope being flattened, or due to function inlining.
As soon as you provide an interface to the parent lexical environment, and applications start using it, you no longer have lexical scoping. You have a form of dynamic scoping with lexical-like visibility rules.
The application logic can implement de facto dynamic scope on top of this API, because you can write a loop which searches for a variable across the chain of lexical scopes. Does my parent have an x variable? If not, does the grandparent, if there is one? You can search the dynamic chain of invocations for the most recent one which binds x, and that is dynamic scope.
There is nothing wrong with dynamic scope, if it is a separate discipline that is not entangled in the implementation of lexical scope.
That said, an API for tracing frames and getting at local variables is is the sort of introspection that is very useful in developing a debugger. Another angle on this is that if you work that API into an application, you're using debugging features in production.
(defvar *lexical-variables* '())
(defun get-var (name)
(let ((var (cdr (assoc name *lexical-variables*))))
(unless var (error "No lexical variable named ~S" name))
var))
(defun deref (var)
(funcall (if (symbolp var)
(or (cdr (assoc var *lexical-variables*))
(error "No lexical variable named ~S" var))
var)))
(defun (setf deref) (new-value var)
(funcall (if (symbolp var)
(or (cdr (assoc var *lexical-variables*))
(error "No lexical variable named ~S" var))
var)
new-value))
(defmacro with-named-lexical-variable ((&rest vars) &body body)
(let ((vvar (gensym))
(vnew-value (gensym))
(vsetp (gensym)))
`(let ((*lexical-variables* (list* ,#(mapcar (lambda (var)
`(cons ',var
(lambda (&optional (,vnew-value nil ,vsetp))
(if ,vsetp
(setf ,var ,vnew-value)
,var))))
vars)
*lexical-variables*)))
,#body)))
(defun var-set (var-str val)
(let ((var-interned (intern (string-upcase var-str))))
(setf (deref var-interned) val)))
(let ((x 1)
(y 2))
(with-named-lexical-variable (x y)
(var-set "x" 3)
(setf (deref 'y) 4)
(mapcar (function deref) '(x y))))
;; -> (3 4)
(let ((year "1400"))
(with-named-lexical-variable (year)
(var-set "year" 1388))
year)
;; --> 1388

Is it possible to push a lookup parameter into multiple block definitions using Autolisp

I'll give a hypothetical example to demonstrate my problem. Imagine that I have a lookup parameter "Color" on a dynamic block definition for a chair and I've given it the possible values of "Red", "Blue", and "Green". Now I need to push this lookup parameter to tons and tons of other dynamic block definitions for other types of chairs. I don't want to have to go into the UI and the block editor for each definition and add this lookup parameter. Instead I would like to automate this by writing an Autolisp routine and passing in the different blocks.
Is this possible using Autolisp? Is it possible using any of the other AutoCAD APIs?
Note below:
I want to edit different block definitions, not references.
I don't want to use a block properties table because I'm already using that for other purposes.
In short: No, this functionality was never exposed to the LISP API.
Whilst you can retrieve and change the values of existing dynamic block parameters (using the getdynamicblockproperties method of a block reference object), you cannot create or modify dynamic block parameters within a block definition, nor will such objects be visible through the Visual LISP API.
Curiously, the parameters are visible when interrogating the DXF data of a block definition through Vanilla AutoLISP, by inspecting the ACAD_ENHANCEDBLOCK dictionary found within the Extension Dictionary of the BLOCK_RECORD entity:
(dictsearch
(cdr
(assoc 360
(entget
(cdr
(assoc 330
(entget
(tblobjname "block" "YourDynamicBlockName")
)
)
)
)
)
)
"acad_enhancedblock"
)
However, this area of DXF data is entirely undocumented and could likely produce unexpected and unstable results if modified directly, given that it isn't officially supported by the API.

Unbound symbols in reactor data after loading the drawing

I have added a modification reactor to my table. The reactor has a callout function in it's data. callout is a function am:trench-updated
(vlr-pers
(vlr-object-reactor
(list table)
(list (cons :am:dictionary dictionary)
(cons :am:modified callout))
(list (cons :vlr-modified 'am:table-modified))))
In the reactor I extract these callouts from the list:
(defun am:object-get (object field)
(cdr (assoc field object)))
(defun am:table-modified (reactor-object)
(setq reactor-data (vlr-data reactor-object)
callout (am:object-get reactor-data :am:modified))
(apply callout (list ...)))
It works fine until I save-load the drawing. After the load, callout contains the correct name, but nil value.
An AutoLISP function will only be defined within the scope of the document namespace and will therefore need to be redefined when the document (drawing file) is reopened. I'm unsure why such function would be undefined following a save operation however.
I would personally suggest that you avoid the use of persistent reactors in favour of rebuilding transient reactors on drawing startup. In my experience, persistent reactors are never truly persistent.

The use of ":" and "->" in AutoLISP

;;----------------=={ Add Objects to Block }==----------------;;
;; ;;
;; Adds all objects in the provided SelectionSet to the ;;
;; definition of the specified block. ;;
;;------------------------------------------------------------;;
;; Author: Lee Mac, Copyright © 2011 - www.lee-mac.com ;;
;;------------------------------------------------------------;;
(defun LM:AddObjectstoBlock ( doc block ss / lst mat )
(setq lst (LM:ss->vla ss)
mat (LM:Ref->Def block)
mat (vlax-tmatrix (append (mapcar 'append (car mat) (mapcar 'list (cadr mat))) '((0. 0. 0. 1.))))
)
(foreach obj lst (vla-transformby obj mat))
(vla-CopyObjects doc (LM:SafearrayVariant vlax-vbobject lst)
(vla-item (vla-get-Blocks doc) (cdr (assoc 2 (entget block))))
)
(foreach obj lst (vla-delete obj))
(vla-regen doc acAllViewports)
This is the first time I have seen this type of syntax being used in AutoLISP.
I am trying to get some explanation of what "LM:" actually means.
The use of "Ref->" is also a question for me. "Ref" does not seem to be defined so it seems it must be part of the system somehow although I could not pull out any documentation describing such use of "Ref->".
Why is the local variable ss being accessed with "LM:ss->"?
Thank you.
This type of syntax is not construction of AutoLISP/Visual LISP. it's Lee Mac's standard. I understand it in this way:
"LM:" actually means shortcut of "Lee Mac" ;)
(LM:ss->vla ss) shound switch datatype from selection set to list of vla-objects where selection set is something simmilar to list of selected elements, but defined as type entity, not vla-object. Maybe get by (ssget) or (ssgetfirst)
(LM:Ref->Def block) get block definition based on it's reference. where "LM:Ref->Def" is only full name of function. "Ref" is not any kind of variable, it's part of function name.
"LM:ss->" not means that we use ss defined as parameter of function, but "LM:ss->vla" is name of function.
When defining a function in AutoLISP, the only naming convention which imparts an alternative behaviour on the resulting function is the prefix c:
For example:
(defun c:test ( )
(princ "\nHello World!")
(princ)
)
The use of the c: prefix in the function name means that the function may be evaluated as a command directly at the AutoCAD command-line.
Here, typing test at the AutoCAD command-line would cause Hello World! to be printed on a new line in the command-line window.
If the function was instead defined as:
(defun test ( )
(princ "\nHello World!")
(princ)
)
Typing test at the AutoCAD command-line would result in the error message:
Command: test Unknown command "TEST". Press F1 for help.
For the function to be evaluated, the user would instead need to type: (test).
With this in mind, the use of LM: has no other meaning than identification as a function from my library, and to decrease the probability that a function of the same name will be defined within the same namespace.
For example, if I were to define a function such as:
(defun AddLine ( pt1 pt2 )
(entmakex
(list
'(0 . "LINE")
(cons 10 pt1)
(cons 11 pt2)
)
)
)
Given the generic naming of this function and ubiquitous operation that it performs (at least where AutoCAD is concerned), there may well be another such function with the same name defined within the Document Namespace.
Consequently, the existing function would be redefined when the above defun expression is evaluated, or the existing function would redefine the above function if its own defun expression were to be evaluated later.
By prefixing the function name with my own author prefix LM::
(defun LM:AddLine ( pt1 pt2 )
(entmakex
(list
'(0 . "LINE")
(cons 10 pt1)
(cons 11 pt2)
)
)
)
I am helping to ensure that when I evaluate LM:AddLine within the Document Namespace, my own definition of this function will always be used, and there is less chance that I could 'contaminate' the definition of a function used by another loaded program.
Similarly, the use of -> within the function name is purely a naming convention and imparts no other meaning to the function.
For example, I have named my function LM:ss->vla because it is a standard function from my library which converts a Selection Set (which I've abbreviated ss) to a list of VLA-Objects.