Mtext. Autolisp returns "Invalid point" but typing the point in the command windows works - autocad

I'm new to autolisp and setting my first macro. I want to create a rectangle, label it with some text centered on it and then convert both entities into a block (this is for optimizing the loading of packaged items into a trailer).
I've succeed building the rectangle but I'm stuck on the mtext part. This is what I have done so far:
(defun c:caja ()
;Switch OFF System Variables
(setvar "osmode" 0)
;Switch OFF snap
;(setvar "blipmode" 0)
;Switch OFF Blipmode
*******************************************************
;User Inputs
(setq pt1 (getpoint "\nSelect start point: "));lower left corner
(setq Long (getdist "\nLength m : "))
(setq Ancho (getdist "\nWidth : "))
;(setq Alto (getdist "\nHeight : "))
;(setq Peso (getdist "\nWeight : "))
*******************************************************
(setq pt2 (polar pt1 0 Long )) ;lower right corner
(setq pt3 (polar pt2 (* pi 0.5) Ancho));upper right corner
*******************************************************
(command"rectang" pt1 pt3"")
(command "mtext" "!pt1" "!pt3" "potato")
When executing the last line of the code I get:
Invalid point. ; error: Function cancelled.
However autocad lets me keep working on the mtext command and asks me to "specify first corner". If I type !pt1 there it Works.
My understanding is that in autolisp I must write between quotes "" every answer that I would normally type in the command prompt so I don't know what I'm doing wrong.

Using the exclaimation mark prefix allows you to evaluate global AutoLISP variables directly at the AutoCAD command-line, outside of any AutoLISP program.
However, when used within a program, such variables will be evaluated as part of the evaluation of the AutoLISP program, and therefore the exclaimation mark prefix is not required.
You have already implemented this successfully when calling the RECTANG command:
(command "rectang" pt1 pt3 "")
Therefore, you can use the same logic for the MTEXT command:
(command "mtext" pt1 pt3 "potato" "")
I would also make the following recommendations:
Store the current values of system variables before changing them, so that you may reset them back to their original values (otherwise the user will lose all of their Object Snap settings, for example).
Implement a local error handler to automatically reset system variables in the event of an error or the user pressing Esc. Refer to my tutorial here for more information on how to accomplish this.
Use an underscore (_) & period (.) to prefix command names, e.g.:
(command "_.rectang" ... )
The underscore ensures that the command is interpreted in English in non-English versions of AutoCAD. The period ensures that the standard definition of the command is used, not a redefinition.
Test for valid user input using an if statement before proceeding.
Declare your local variables to ensure that you variables are not inadvertently overwritten by other programs defining symbols in the document namespace. See my tutorial here for more information on this.

Related

How can make any entity as last entity in Autocad Autolisp

I am working with AutoCAD electrical 2016. there is "c:aeballoon" command which can be applied to last entity via lisp. if I want to apply this command to any other entity (say Nth entity) in the drawing. so there is one solution if any how make Nth entity as last entity. so this c:aeballoon command can successfully applied to that Nth Entity.
Thank in advance
You can create the following AutoCADLisp Program.
copy the following to notepad
(defun c:makelast() (command ".copy" "si" (setq kk (car (entsel))) "0,0" "" ".erase" kk "")(princ))
save the file as makelast.lsp
Use Appload command to load the program.
RUn the new command Makelast to select the object you want to make it last.

Enable "dynamic input" when measuring distance

I have a LISP routine which measures between two points using getpoint, it then creates a table and (well, it will once I've finished anyway) populate the table with figures, based on the measured value.
The problem is when I select the first point, there is no visual feedback of where I selected, such as there is when using the built in distance tool. For example, in both of the below screenshots, I have chosen my first point to measure from, but not the second where I want to measure to;
Using the distance tool;
Using my tool;
How, in LISP, can I add this "dynamic input" (I think thats the correct term?) to give my user some kind of visual feedback that the tool is working as they expect?
The function (getpoint [pt] [msg]) actually has two optional parameters. It looks like you're already using the msg parameter to display your custom message ("Choose second point"), but you can pass the previous point as the first parameter to get a nice reference line between that point and the crosshairs. For example:
(setq P1 (getpoint "Choose first point: "))
(setq P2 (getpoint P1 "Choose second point: "))
Additionally, there's a (getdist [pt] [msg]) function, which behaves similarly but previews and returns a distance.
(setq P1 (getpoint "Choose first point: "))
(setq P2 (getdist P1 "Choose second point: "))

How to list the names of all the blocks of a .dwg file in AutoCAD CORE console?

i will get custom block in a .dwg file from a list of blocks which I will parse programmatically in Java.
You can use the command INSERT with the option ?
cd C:\Program Files\Autodesk\AutoCAD 2016
accoreconsole.exe /i "Sample\Database Connectivity\Floor Plan Sample.dwg"
Command: _INSERT
Enter block name or [?]: ?
Enter block(s) to list <*>:
Defined blocks.
"CHAIR7"
"COMPUTER"
"DESK2"
"DESK3"
"DOOR"
"DR-36"
"DR-69P"
"DR-72P"
"FC15X27A"
"FC42X18D"
"FNPHONE"
"IBMAT"
"KEYBOARD"
"NCL-HL"
"RECTANG"
"RMNUM"
"SOFA2"
User Unnamed
Blocks Blocks
17 0
I am not familiar with Core Console but for listing all block in a DWG file, you need to use LISPs. Something like axBlock from jtbworld . You may also mock around with LISP code and call it via a SCRIPT.
Edit:
Copy and paste following code in Notepad and save it as axBlock.lsp in the root fo your C drive (for instance):
(defun c:axblocks (/ b bn tl)
(vlax-for b (vla-get-blocks
(vla-get-ActiveDocument (vlax-get-acad-object))
)
(if (= (vla-get-islayout b) :vlax-false)
(setq tl (cons (vla-get-name b) tl))
)
)
(reverse tl)
)
I just tweaked jtbworld's code a little bit to make it easier for you.
Now you have your LISP code ready and you only need to load it into AutoCAD. You have couple of options for that:
Use APPLOAD command in AutoCAD and browse for axBlock.lsp which
you just created
Drag axBlock.lsp over your AutoCAD window.
Call axBlock.lsp via a script file. And scripts are nothing
really
but a simple textual file with *.scr extension. For that you just
need this line of code to be in your script file:
(load "C:\\axBlock.lsp")
After doing any of above three methods, as long as you type axBlock in AutoCAD and hit Enter, you will see the list of existing blocks.
Moreover, if you followed approach no.3 from above list, you can make a shortcut and call axBlock within the script file as well i.e. you load and call the function in one hit. If you want to do so, just add axBlock in the second line of your script code. Note there an extra SPACE after axBlock

Is there a way with org-capture-templates to not insert a line if initial content is blank

I would like to have org-capture-template that does not insert certain text if a %-escape is blank. I am actually using the template with org-protocol and :immediate-finish, so I don't have the ability to manually edit and delete the blank line in a buffer. And sometimes I may select text on the web page and sometimes I may not. I am also just generally interested being able to make more dynamic templates.
Take this capture template as an example
(setq org-capture-templates
(quote (("w" "capture" entry (file "~/org/refile.org")
"* [[%:link][%:description]] :NOTE:\n%i\n%U\n" :immediate-finish t))))
With org-protocol://capture://w/http%3A%2F%2Fstackoverflow.com%2F/Stack%20Overflow/Hot%20Network%20Questions.
I get this which is fine.
* [[http://stackoverflow.com/][Stack Overflow]] :NOTE:
Hot Network Questions
[2014-01-12 Sun 13:01]
But if I don't have text selected like this example org-protocol://capture://w/http%3A%2F%2Fstackoverflow.com%2F/Stack%20Overflow/.
I get this:
* [[http://stackoverflow.com/][Stack Overflow]] :NOTE:
[2014-01-12 Sun 12:58]
I would like to know how to get rid of the blank line in this last example without having to use two templates.
My thought is to somehow use quote to build the string dynamically at template creation time, but I don't know how to get the value of %i to eval.
Use this auxiliary function:
(defun v-i-or-nothing ()
(let ((v-i (plist-get org-store-link-plist :initial)))
(if (equal v-i "")
""
(concat v-i "\n"))))
And this as capture template:
("w" "capture" entry (file "~/refile.org")
"* [[%:link][%:description]] :NOTE:\n%(v-i-or-nothing)%U\n"
:immediate-finish t)

elisp create unnamed buffer from contents of file

I was trying some code from Elisp Cookbook, and I initially tought that this code:
(defun process-file (file)
"Read the contents of a file into a temp buffer and then do
something there."
(when (file-readable-p file)
(with-temp-buffer
(insert-file-contents file)
(goto-char (point-min))
(while (not (eobp))
;; do something here with buffer content
(forward-line)))))
Will create a new ( unnamed/unsaved ) buffer on my emacs window, having the contents of that file ( and maybe open it in the foreground ). However, this doesn't happen. Can you guide me towards this?
EDIT: I experimented a little, and got to this:
(defun myTest (file)
(interactive "f")
; check if file is readable
(when (file-readable-p file)
; create a new "untitled" buffer
(let ((myBuf (get-buffer-create "untitled")))
; make it the current displayed buffer
(switch-to-buffer myBuf)
(insert "Hello"))))
Is this the way to do it?
Since this is a buffer named "untitled", I can only have one of these in a session. Is there something I could use to have more than one, without resorting to random numbers?
The elisp way to generate a unique buffer name is to use generate-new-buffer-name. The documentation is:
(generate-new-buffer-name NAME &optional IGNORE)
Return a string that is the name of no existing buffer based on NAME.
If there is no live buffer named NAME, then return NAME. Otherwise
modify name by appending `', incrementing NUMBER (starting at
2) until an unused name is found, and then return that name. Optional
second argument IGNORE specifies a name that is okay to use (if it is
in the sequence to be tried) even if a buffer with that name exists.

Resources