Enable "dynamic input" when measuring distance - autocad

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: "))

Related

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

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.

How can I add 2 articulations to a note as part of a post-event?

I copied this example from here, and it works fine, working as if I had simply entered ->.
dashPlus = #(let ((m (make-music 'ArticulationEvent
'articulation-type "accent")))
(set! (ly:music-property m 'tweaks)
(acons 'font-size -3
(ly:music-property m 'tweaks)))
m)
However, I'm trying to figure out how to define a combination tenuto/marcato articulation, which somehow got changed somewhere during the Finale file -> MusicXML -> .ly process from what I entered into Finale (the combination articulation) to an individual marcato articulation and an individual tenuto articulation attached to the same note (-- ->).
How can I change this to add not only one accent, but a combination of both, and also somehow manipulate the articulations' script-priority values so that the tenuto is always stacked closest to the staff? (I'm afraid my grasp of Scheme isn't too strong. I understand a few things but this is all way over my head.)

How to program faster, (generate code from a pattern?)

I frequently run into problems that could be solved with automating code writing, but aren't long enough to justify it as tediously entering each piece is faster.
Here is an example:
Putting lists into dictionaries and things like this. Converting A into B.
A
hotdog HD
hamburger HB
hat H
B
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Sure I could come up with something to do this automatically, but it would only make sense if the list was 100+ items long. For a list of 10-20 items, is there a better solution than tediously typing? This is a Ruby example, but I typically run into cases like this all the time. Instead of a case statement, maybe it's a dictionary, maybe it's a list, etc.
My current solution is a python template with the streaming input and output already in place, and I just have to write the parsing and output code. This is pretty good, but is there better? I feel like this would be something VIM macro would excel at, but I'm that experienced with VIM. Can VIM do this easily?
For vim, it'd be a macro running over a list of space separated pairs of words, inserting the first 'when "' bit, the long form word 'hotdog', the ending quote, a newline and 'return "', and then the abbreviation and then final quote, then going back to the list and repeating.
Starting with a register w of:
when "
register r of:
return "
an initial list of:
hotdog HD
hamburger HB
hat H
and a starting file of:
def symbolizeType
case self.type
"newline here"
you can use the following macro at the start of the initial list:
^"ayeeeb"byeo"wp"apa"^Mrb"j
where ^M is a newline.
I do this frequently, and I use a single register and a macro, so I'll share.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
This is a long explanation, but the process is extremely simple and intuitive.
Here are the steps that I would take:
A. The starting text
hotdog HD
hamburger HB
hat H
B. Insert the initial, non-repetitive lines preceding the text to transform
def symbolizeType
case self.type
hotdog HD
hamburger HB
hat H
C. Transform the first line, while recording your keystrokes in a macro
This step I'll write out in detailed sub-steps.
Place the cursor on the first line to transform ("hotdog") and type qa to begin recording your keystrokes as a macro into register a.
Type ^ to move the cursor to the start of the line
Type like you normally would to transform the line to what you want, which for me comes out looking like the following macro
^i^Iwhen "^[ea"^[ldwi^M^Ireturn "^[ea"^[j
Where ^I is Tab, ^[ is Esc, and ^M is Enter.
After the line is transformed to your liking, move your cursor to the next line that you want to transform. You can see this in the macro above with the final j at the end.
This will allow you to automatically repeat the macro while it cycles through each repetitive line.
Stop recording the macro by typing q again.
You can then replay the macro from register a as many times as you like using a standard vim count prefix, in this case two consecutive times starting from the next line to transform.
2#a
This gives the following text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
D. Finally, insert the ending non-repetitive text
def symbolizeType
case self.type
when "hotdog"
return "HD"
when "hamburger"
return "HB"
when "hat"
return "H"
end
Final Comments
This works very quick for any random, repetitive text, and I find it very fluent.
Simply pick a register, record your keystrokes, and then replay your keystrokes from the register.
For things like this I have a few ways of making it easier. One is to use an editor like Sublime Text that allows you to multi-edit a number of things at once, so you can throw in markup with a few keystrokes and convert that into a Hash like:
NAME_TO_CODE = {
hotdog: 'HD',
hamburger: 'HB',
hat: 'H'
}
Not really a whole lot changed there. Your function looks like:
def symbolize_type(type)
NAME_TO_CODE[type.to_sym]
end
Defining this as a data structure has the bonus of being able to manipulate it:
CODE_TO_NAME = NAME_TO_CODE.invert
Now you can do this:
def unsymbolize_type(symbol)
CODE_TO_NAME[symbol.to_s]
end
You can also get super lazy and just parse it on the fly:
NAME_TO_CODE = Hash[%w[
hotdog HD
hamburger HB
hat H
].each_slice(2).to_a]
snippets are like the built-in :abbreviate on steroids, usually with parameter insertions, mirroring, and multiple stops inside them. One of the first, very famous (and still widely used) Vim plugins is snipMate (inspired by the TextMate editor); unfortunately, it's not maintained any more; though there is a fork. A modern alternative (that requires Python though) is UltiSnips. There are more, see this list on the Vim Tips Wiki.
There are three things to evaluate: First, the features of the snippet engine itself, second, the quality and breadth of snippets provided by the author or others; third, how easy it is to add new snippets.

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)

How to delete the input cell upon evaluation?

I would like to accomplish the following: upon evaluation of an input cell, it should self-destruct (i.e. delete itself). I tried to hack something together with SelectionMove and NotebookDelete, but didn't quite get what I wanted.
Here are potential use cases:
the command might be a shorthand for a series of other commands that will be generated dynamically and inserted into the notebook
the command might only be used for side effects (e.g. to set a notebook option or to open a new notebook); leaving the command in the notebook after evaluation serves no purpose and creates clutter
Edit: As per Mr. Wizard, the answer is SelectionMove[EvaluationNotebook[], Previous, Cell]; NotebookDelete[];. I don't know why it wasn't working for me before. Here is some code that uses this idiom.
writeAndEval[nb_, boxExpr_] := (NotebookWrite[nb,
CellGroupData[{Cell[BoxData[boxExpr], "Input"]}]];
SelectionMove[nb, Previous, Cell];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb]);
addTwoAndTwo[] := Module[{boxExpr},
boxExpr = RowBox[{"2", "+", "2"}];
SelectionMove[EvaluationNotebook[], Previous, Cell];
NotebookDelete[];
writeAndEval[EvaluationNotebook[], boxExpr];
]
Now, running addTwoAndTwo[] deletes the original input and makes it look as if you've evaluated "2+2". Of course, you can do all sorts of things instead and not necessarily print to the notebook.
Edit 2: Sasha's abstraction is quite elegant. If you are curious about "real-world" usage of this, check out the code I posted in the "what's in your toolbag" question: What is in your Mathematica tool bag?
To affect all Input cells, evaluate this is the notebook:
SetOptions[EvaluationNotebook[], CellEvaluationFunction ->
( (
SelectionMove[EvaluationNotebook[], All, EvaluationCell]; NotebookDelete[];
ToExpression##
)&)
]
If you only want to affect one cell, then select the cell and use the Options Inspector to set CellEvaluationFunction as above.
Or, building on Mr. Wizard's solution, you can create a function SelfDestruct, which will delete the input cell, if you intend to only do this occasionally:
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookDelete[]]; e)
Then evaluating 2+3//SelfDestruct outputs 5 and deletes the input cell. This usage scenario seems more appealing to me.

Resources