A little bit of background: I am creating a template for my team of drafters to use. We have a set of commonly used objects (les't call them "markers"), like section markers, leaders, dimensions, title blocks, etc. all set up in a table (not a real "Table", just arranged neatly in a rectangle). All of the markers are annotative, so that we do not need a separate set of markers for each os the scales that we work on.
Now we come to the problem: Although the markers, being annotative, scale properly when the annotation scale is changed, they all scale around their own basepoints (as they should). The problem is, that if these markers get too big due to the scale changes, they start to overlap so heavily, that they become totally unusable. I would like for them to move away from one another, so that they maintain their relative distances unchanged. In other words, I kinda want the whole table to behave like it is annotative. I know that it would be easy to solve by just making the whole table into an annotative block, but the markers need to be easily accessible for the drafters to use. I don't want them to have to explode the table-block each time they need to take a marker, or to have to go inside of this block, copy the markers they want, come out of the block and only then use them.
I tried to come up with a set of steps that would result in this behavior I want and this is what I think the LISP should do everytime the annotative scale is changed in the model space:
- Get the centerpoint of the table border (which would itself be an annotative block, so that it properly encloses the "scaled-up" table in every scale).
- Determine which objects are inside of the border (determine all the markers that are to be moved).
- Measure the distance between this centerpoint of the border and the basepoints of all of the objects that are inside the border (the markers).
- Scale this distance and move each marker in the same direction it is already "facing" with regard to the centerpoint, so that the new distance (in the new scale) is equal to this scaled distance. The scale factor of the distance would be based on the current and the new chosen scale (so if I was in 1:10 scale initially and change the scale to 1:1000, the distance grows by a factor of 100).
- I don't want the LISP to prompt user for anything, it should run whenever the scale is changed, realise from which scale to which the change ocurred; and apply the position changes on the markers automatically.
Here's the link to an image showcasing the simplified version of the problem:
https://i.stack.imgur.com/RU70f.png
You can see the various markers inside of the orange table border. The border in the picture is selected, so that its basepoint is visible (I think it might be easiest to use this basepoint as the centerpoint around which the whole table "scales")
If anything is unclear or anyone needs additional info, please ask. And please help me
EDIT: I should probably add that I know pretty much nothing about writing LISPS (or programming in general for that matter), so if You could be as explicit as You can in Your answers, I would really appriciate that.
EDIT 2: I started to learn about AutoLISP and reactors in particular. I've written the following code as a start:
(vlr-sysvar-reactor
"CANNOSCALEVALUE"
'((:vlr-sysvarchanged . MoveMarkersOnScaleChange))
)
(defun MoveMarkersOnScaleChange (calling-reactor :vlr-sysVarChanged)
(princ "Hello")
)
From what I understand, this should simply print "Hello" in the command line each time the scale is changed (the CANNOSCALEVALUE variable changes). It kinda works like that, but I noticed that once the .lsp is loaded into my file, it starts to print "Hello" after pretty much everything I do (like draw a polyline, move something and so on), not only after the scale change (though that works as well). Sometimes it even prints in a rapid succession (HelloHelloHello, etc.). Could someone enlighten me as to what is going on here...?
I suspect it has something to do with the part(calling-reactor :vlr-sysVarChanged)
, cause this is the only part of the code I do not really get. And yes, I know that:
"Callback functions for all reactors, other than Object reactors, must be defined to accept two arguments:
The first argument identifies the Reactor object that called the function.
The second argument is a list of parameters set by AutoCAD."
but I do not really know what it means, so it's not much help.
You can capture event of change annotation scale by reactor
( vlr-sysvar-reactor data functionToRun )
let it watch variableCANNOSCALE
like this:The center point of table You can get like this.
I don't know how You identify table - to simplify let's assume we have a handle to it so:
If the rectangle frame is on specified layer, and You are sure nothing else is on this layer You can use
(ssget "X" (list(cons 8 "TABLE BORDER") ))
to select it.To select everything inside the frame You can use such code: