Counting blocks in a specific location (autolisp) - autocad

So I'm making a simple function in autolisp to count the number of a specific block in a drawing, and it looks like this:
(defun c:contarblocos()
(setq ss (ssget "x" ' ((0. "INSERT") (2. "Nome do bloco"))))
(setq count (sslength ss))
(alert(strcat "Total de blocos no desenho: " (itoa count)))
)
Now, what I really want is to count the number of blocks in a specific area, defined by the user. In other words, the user will call the function, and then the function will ask for a specific area, where it will look for the specific block and count them, not counting any blocks from outside the selected area.

Rather than using the x mode string of the ssget function (which searches the entire drawing database for all entities which fulfil the criteria of the filter list argument), simply omit this argument to permit the user to make a selection using any valid selection method, e.g.:
(defun c:contarblocos ( / sel )
(if (setq sel (ssget '((0 . "INSERT") (2 . "Nome do bloco"))))
(alert (strcat "Total de blocos no desenho: " (itoa (sslength sel))))
)
(princ)
)
There are a few other issues with your current code:
Always declare the variables whose scope is local to your function: in my above example, you will note that the sel symbol is declared in the variable list within the defun expression. For more information on why this is important, you may wish to refer to my tutorial here.
You should test whether ssget returns a valid selection set before calling the sslength function to obtain the number of items in the set, since (sslength nil) will error. You will see that I use an if statement in my code to accomplish this.
The ssget filter list argument should be an association list of dotted pairs, and as such, there should be a space between the key and the value in each list item, hence this:
(0. "INSERT")
Should become:
(0 . "INSERT")
You should include a final (princ) or (prin1) expression within the defun expression so that the function returns a null symbol to the command line, rather than returning the value returned by the last evaluated expression (i.e. the alert expression, which will return nil). Including a (princ) expression per my example will ensure that the function exits 'cleanly'.

Related

Filtering an expression output with regexp

The bad code of main is (string-match "module" (help uri-path)) that returns an error
scheme#(guile-user) [5]> (string-match "module" (help uri-path))
`uri-path' is an object in the (web uri) module.
- Special Form: uri-path
While compiling expression:
Syntax error:
unknown file:9:23: sequence of zero expressions in form (begin)
scheme#(guile-user) [5]>
What I am trying to reach, is displaying only one line of help function output. How to fix it?
Use procedure-documentation to get the documentation of a procedure as a string.
scheme#(guile-user)> (help cons)
`cons' is a procedure in the (ice-9 safe-r5rs) module.
- Scheme Procedure: cons x y
Return a newly allocated pair whose car is X and whose cdr is Y.
The pair is guaranteed to be different (in the sense of `eq?') from
every previously existing object.
scheme#(guile-user)> (procedure-documentation cons)
$6 = "- Scheme Procedure: cons x y\n Return a newly allocated pair whose car is X and whose cdr is Y.\n The pair is guaranteed to be different (in the sense of `eq?') from\n every previously existing object."

call function with two string parameters in Common-LISP Programming

I created a function which gets two string parameters. The function simply adds each string length. below is a code.
(defun add_twostring_length (mystr1 mystr2)
(+ (length mystr1) (length mystr2))
)
When I call add_twostring_length function like this,
(add_twostring_length "cpp" "lisp")
output is correct. 7
But, when I call the same function in the manner of using comma,
(add_twostring_length "cpp", "lisp")
I got an error message.
Error: Comma not inside a backquote.
[condition type: READER-ERROR]
I want to call function in the manner of (add_twostring_length "cpp", "lisp").
What is the wrong with the code?
picture showing error message
You might as well ask "why can't I call the function without parentheses?" In lisp, you call functions as an sexpr with the function in the car and the arguments in the cdr. There are no commas involved -- that's the syntax of lisp.
What you want is possible, but I will strongly advice against using it:
(set-macro-character #\,
#'(lambda (stream char)
(read stream t nil t)))
The above code creates the so called "read macro". At read-time common lisp will find all occurrences of , and ignore them. This makes possible calling functions like so:
(+ 1, 2, 3) ; => 6
However this will break escaping in templates:
`(1 2 ,(+ 3 4)) ; => (1 2 (+ 3 4))
Perhaps it is possible to make the read macro more intelligent, but I don't want to delve deeper into this, because I don't like the idea. Sorry.

Clojure : Documentation syntax, regarding when-let and if-let

I've been looking at the if-let and when-let macros, Im having trouble determining what exactly it is that they "do". In particular, the documentation sais :
clojure.core/when-let
([bindings & body])
Macro
bindings => binding-form test
When test is true, evaluates body with binding-form bound to the value of test
I thus am somewhat confused about the way macros are documented.
1) What does the "=>" symbol mean ?
2) What does "test" refer to ?
Direct answer to your questions:
=> means "expands to", as in BNF notation. In this case it means that you need two forms: binding-form and the test.
"test" means anything that can be evaluated as bool.
By the way, I think that the docs are unclear or even maybe erroneous here. It is hard (or impossible) to deduce that the two forms constituting the bindings need to be enclosed in a vector. IMHO it should be either when-let ([[bindings] & body]) (the vector shown in the args) or bindings => [binding-form test] (the vector shown in the BNF-like expansion.)
It's often helpful when dealing with a macro to call macroexpand and see what the generated code is.
(macroexpand
'(if-let [x (myfunc)]
(foo x)
(bar))
; expands to
(let* [temp__3695__auto__ (myfunc)]
(if temp__3695__auto__ (clojure.core/let [x temp__3695__auto__]
(foo x))
(bar)))
; the generated symbols are necessary to avoid symbol
; capture but can confuse. The above is equivalent to:
(let* [ t (myfunc)]
(if t
(let [x t]
(foo x))
(bar))
So you can see that if-let is a shorthand for "bind local variable to the result of a function call and if that variable is truthy call the first form, else call the other form. The value returned by your function is only available in the 'truthy' branch."
wrt documentation convention
bindings => binding-form test
=> reads something like 'is equivalent to'
test is some form that returns a value
For most of these functions, clojuredocs is your friend, example usage often clarify things. If the clojuredocs example doesn't cut it for you, you can add your own
Consider the following code:
(if-let [x (a-function)]
(do-something-with x) ;; (a-function) returned a truthy result
(do-something-else) ;; (a-function) returned nil or false
This is like let, in that x will be bound to the return value of (a-function). This function could return nil or false. In that case, the implicit test fails and (do-something-else) will be evaluated. If x is not nil and not false, (do-something-with x) will be evaluated.
A scenario where this could be useful:
(if-let [user (find-logged-in-user)]
(do something with logged in user) ;; a user was found
(redirect to login page) ;; no user was found
I sometimes use something like the following, to conditionally add keys to a map of options:
(apply merge {:username "joe"
:email "joe#example.com"}
(when-let [name (find-full-name)] {:name name})
(when-let [dob (find-date-of-birth)] {:dob dob}))
This results in a map with :username and :email keys, and a :name key if the users' full name was found, plus a :dob key if a date of birth was found.
I hope that makes the use of if-let and when-let clearer.

Autocad user variables

Is it possible to use local variables in dwg file and display them in text objects?
For example, I need to numerate objects starting with some value:
value0 = 5
value1 = value0 + 1
value2 = value0 + 2
etc...
Can I put value1 and value2 into some text object on my drawing?
User variables will certainly work. Be aware that they are limited in number and other programs may also set them without your knowing.
If you want simple values to be be displayed as text AutoCAD can do that. The scope of variables is up to you and the api you choose. (VB, VBA, AutoLisp, .NET etc.)
There are other data storage options available in the dwg file.
To display an integer in a TEXT or MTEXT (or attribute) object you insert a field, select DieselExpression as the field type and then type your expression. You can do this for other data types as well.
There are various user variables available for the task. To achieve the above, type the following into the AutoCAD command prompt:
setvar useri1 5 (sets the value of user integer1 to 5)
Then you can use the following DieselExpressions in fields inside different text objects:
$(getvar, useri1) (gets the value of useri1)
$(+,$(getvar,useri1),1) (add 1 to the value of useri1)
$(+,$(getvar,useri1),2) (add 2 to the value of useri1)
etc...
It would help to know what language you prefer to use. This is very easy to do using AutoLISP. Suppose you'd like a program to ask the user for a number, then proceed forward to increment that number and put the increments successively into drawing text (say lot numbers).
Here is a working and complete little sample of how you'd do something like this:
(defun c:consecunum ( / entget_in entsel_in value_in value_out)
(setq
value_in (getint "\nFirst number: ")
value_out value_in
)
(while (setq entsel_in (entsel (strcat "\nText to replace with \"" (itoa value_out) "\": ")))
(setq entget_in (entget (car entsel_in)))
(entmod
(subst
(cons 1 (itoa value_out))
(assoc 1 entget_in)
entget_in
)
)
(setq value_out (1+ value_out))
)
)
If you have any questions about how this works, don't hesitate to ask.

Should the behaviour of a function depend on the name of its variable?

Here is a short elisp code which shows that the behaviour of a function depends on the name of its variable. Is this a bug?
A function is declared using a variable x. When that function is called with a variable named anything other than x, it works as expected. But if it is called with a variable named x, it fails!
My system is GNU Emacs 22.2.1 (powerpc-apple-darwin8.11.0, Carbon Version 1.6.0) of 2008-04-05 on g5.tokyo.stp.isas.jaxa.jp
Paste this on an emacs buffer, put the cursor after the last parehthesis and press \C-x\C-e to see that the function make-zero does now work correctly when called the second time.
(progn
(defun make-zero (x)
"Simple function to make a variable zero."
(set x 0))
(setq x 10)
(insert "\n Variable x is now equal to " (number-to-string x))
(setq y 20)
(insert "\n Variable y is now equal to " (number-to-string y))
(insert "\n\n Let us apply make-zero to y")
(make-zero 'y)
(insert "\n Variable y is now equal to " (number-to-string y))
(insert "\n\n Let us apply make-zero to x")
(make-zero 'x)
(insert "\n Variable x is now equal to " (number-to-string x))
(insert "\n\n Why make-zero had no effect on x? Is it because the name of the
variable in the definition of make-zero, namely 'x', is the same as the name of
the variable when make-zero was called? If you change the name of the variable
in the definition of make-zero from x to z, this strange behaviour will
disappear. This seems to be a bug in elisp."))
It's not a bug so much as the nature of Elisp's (and Lisp in general) dynamic binding. ' doesn't pass a reference (that is, it's not like & in C/C++), it passes an unevaluated symbol; what it then evaluates to depends on the scope in which it's evaluated, which means it gets the x that's in scope inside the function.
In Lisp-think, the normal way around this would be to use a macro.
(defmacro make-zero (x) (list 'set x 0))
or
(require 'cl)
(defmacro make-zero (x) `(set ,x 0))
It's not a bug. It'd be worth your while reading the manual entry for Scoping Rules For Variable Bindings.
The function you wrote calls set, which takes a symbol (the value of the first argument) and changes its value to the value of the 2nd argument. The make-zero you wrote binds x locally to its input argument, so when you pass in the symbol x, set changes the first binding for x it finds, which happens to be the local binding.
Here's a different example, let's say you just had the following:
(defun print-something (something)
(set 'something "NEW VALUE")
(insert something))
(print-something "OLD") ; inserts "NEW VALUE"
Looking at that snippet of code, does it make sense that the set line changes the local value of something?
It doesn't matter whether or not there's a global setting for the symbol something.
Another example is the following:
(defvar x "some global value") ;# could have used setq here
(let ((x "local binding"))
(set 'x "new value"))
Which binding would you expect the set line to change? The one created by the let or the global one created by defvar?
The function you wrote is (pretty much) doing exactly the same thing as the let, you're creating a local binding for a variable which is seen before the global one.
If you want to pass around a reference to a variable then the only safe way to do that is via macros, which I recommend, but not until you've grasped the basics of lisp (b/c macros are definitely more complicated). That said, don't let me stop you from diving into macros if that's your passion.
A good introduction to programming Emacs lisp can be found here.
geekosaur's answer does a nice job of showing how you'd achieve what you want.

Resources