Is there a way to save variables of the “first corner point” and “other corner point” when a user picks first point, then types in the length and width (with dynamic input on) when using the “Rectangle” command?
Example:
Command: RECTANGLE
Specify first corner point or [Chamfer/Elevation/Fillet/Thickness/Width]:
Specify other corner point or [Area/Dimensions/Rotation]: @Anonymous',15'
I want to replace what I have below with the “Rectangle” command so user can type in the length and width they need. The user will want the length and width to be whole numbers (Ex: 13, 15, 20, 23...etc) which can be done if using the rectangle command. Right now they have to draw a rectangle they want in whole numbers first. Then use the routine and snap to the corners. Hoping to combine all in one routine.
What I have now:
(setq firstpick (getpoint "\nEnter first corner: "))
(setq secondpick (getcorner firstpick "\nEnter cross corner: "))
; Get all four corners of user drawn rectangle
(setq pt1 firstpick)
(setq pt3 secondpick)
(setq pt2 (list (car pt1) (cadr pt3)))
(setq pt4 (list (car pt3) (cadr pt1)))
; Get the Area drawn and save in variable “myrecarea”
(setq mylength (distance pt1 pt2)); length
(setq mywidth (distance pt1 pt4)); width
(setq myrecarea (* mylength mywidth)); Get area of rectangle (length x width)
...more code
I want to replace above with using the “Rectangle” command (if possible) so user can type in length and width. Not sure how to extract those points (firstpick, secondpick) and save as variables...
(setq firstpick (command "rectangle"))(?)
(setq secondpick (?)
; Get all four corners of user drawn rectangle
(setq pt1 firstpick)
(setq pt3 secondpick)
(setq pt2 (list (car pt1) (cadr pt3)))
(setq pt4 (list (car pt3) (cadr pt1)))
; Get the Area drawn and save in variable “myrecarea”
(setq mylength (distance pt1 pt2)); length
(setq mywidth (distance pt1 pt4)); width
(setq myrecarea (* mylength mywidth)); Get area of rectangle (length x width)
...more code
If I can keep the variables pt1, pt2, pt3, pt4 as the four corners of my rectangle, I think the rest of my routine should keep working since those variables are needed later on as locations for drawing lines.
*The Area size determines what is drawn later in the routine…
One last question,
Is it possible to save everything drawn in a routine in a block? Not sure how the block naming would work if routine run several times in a single drawing without overwriting the original block.
Solved! Go to Solution.
Solved by Kent1Cooper. Go to Solution.
A problem you have is that the RECTANGLE command allows you to size the rectangle but then point to which way you want it to be drawn, and that point is most likely not to be a corner.
Now if you want your rectangles always orthogonal to the current UCS, then we can emulate the command by having the user pick the first point, which we save, and then running the command from that point, and picking up the opposite corner after the command has completed. Hmm, maybe it doesn't have to be orthogonal.
Here, try this out...
(defun c:RCT ( / ent)
(and
(setq p1 (getpoint "\nFirst corner: "))
(vl-cmdf "_.rectangle" p1)
(while (> (getvar "cmdactive") 0) (vl-cmdf pause))
(setq ent (entget (entlast))
plist (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 10)) ent))
p2 (nth 2 plist)
)
(entmake (list '(0 . "LINE")(cons 10 p1)(cons 11 p2)))
(entmake (list '(0 . "LINE")(cons 10 (nth 1 plist))(cons 11 (last plist))))
)
)
It draws the diagonals, but it leaves p1 and p2 as globals and needs error and undo control (easy to add).
If you need only the diagonals and not any points, then we can localize p1 and p2.
What else did you need if the area is big enough?
As to making a block, we can make an anonymous block that doesn't need a name and doesn't have to be purged if you erase all of them. But you can copy it around all you want.
John F. Uhden
test it
(defun rectang-pts ()
(VL-LOAD-COM)
(VL-CMDF "rectangle" pause pause "")
(setq rectangle-obj (VLAX-ENAME->VLA-OBJECT (entlast)))
(VLA-GETBOUNDINGBOX rectangle-obj 'dl 'ur)
(setq pt1 (VLAX-SAFEARRAY->LIST dl))
(setq pt3 (VLAX-SAFEARRAY->LIST ur))
) ;_ defun
Thanks Devitg.
I think this is what I'm looking for! I tried to implement my old code to get pt2 and pt4 (the other corners of rectangle) so I could have all four points, but getting an error.
I updated to:
(VL-LOAD-COM)
(VL-CMDF "rectangle" pause pause "")
(setq rectangle-obj (VLAX-ENAME->VLA-OBJECT (entlast)))
(VLA-GETBOUNDINGBOX rectangle-obj 'dl 'ur)
(setq pt1 (VLAX-SAFEARRAY->LIST dl))
(setq pt3 (VLAX-SAFEARRAY->LIST ur))
(setq pt2 (list (car pt1) (cadr pt3)))
(setq pt4 (list (car pt3) (cadr pt1)))
Got a 'bad argument type: numberp: nil' error (I'm guessing my list is empty or nil then?)
I then tried this:
(VL-LOAD-COM)
(VL-CMDF "rectangle" pause pause "")
(setq rectangle-obj (VLAX-ENAME->VLA-OBJECT (entlast)))
(VLA-GETBOUNDINGBOX rectangle-obj 'dl 'ur)
(setq pt1 (VLAX-SAFEARRAY->LIST dl))
(setq pt3 (VLAX-SAFEARRAY->LIST ur))
(setq pt2 (list (car dl) (cadr ur)))
(setq pt4 (list (car ur) (cadr dl)))
But got a 'bad argument type: consp #<safearray...>' error
I then tried:
(VL-LOAD-COM)
(VL-CMDF "rectangle" pause pause "")
(setq rectangle-obj (VLAX-ENAME->VLA-OBJECT (entlast)))
(VLA-GETBOUNDINGBOX rectangle-obj 'dl 'ur)
(setq pt1 (VLAX-SAFEARRAY->LIST dl))
(setq pt3 (VLAX-SAFEARRAY->LIST ur))
(setq pt2 (VLAX-SAFEARRAY->LIST pt1))
(setq pt4 (VLAX-SAFEARRAY->LIST pt3))
Got a 'error: bad argument type: safearrayp nil'
I use the variable pt1, pt2, pt3, pt4 from the rectangle corners through out my code as points to draw lines from. Everything kinda builds off of these 4 points. I think if I can get pt2 and pt4 values that will complete all four corners, the rest of the code should run (hopefully).
Any ideas? I don't have too much experience using visual LISP yet...
Thanks again for the code. This is a big help!
@rebPTFNF wrote:
Thanks Devitg.
I think this is what I'm looking for!...
You don't. Better take a lesson and learn from john's code. You might not need it now, but definitely in the future.
Here's my suggestion. As simple as I think it only could be...
(defun c:Brec ( / e p a i n) (command "_.rectang") ; rectang command (while (> (getvar 'cmdactive) 0) (command pause)) ; supply a user input while the command is active (setq e (entlast)) ; save ename of last entity (rectangle) (setq p (trans (cdr (assoc 10 (entget e))) 0 1)) ; get its first vertex (for insertion point) (setq a (getpropertyvalue e "Area")) ; get its area (setq i 100) ; start name from 100+1 (while (tblsearch "block" (setq n (strcat "myrectang-" (itoa (setq i (1+ i))))))) ; test name with increment until is not already used (command "_.block" n "_non" p e "" ; create a block "_.insert" n "_s" 1 "_r" 0 "_non" p) ; re-insert a block (princ (strcat "\nNew block created: '" n "' of area " (rtos a) " something squared.")) ; get a user know (princ) ; don't bother a user with nil )
@rebPTFNF wrote:
Is there a way to save variables of the “first corner point” and “other corner point” when a user picks first point, then types in the length and width (with dynamic input on) when using the “Rectangle” command?
....
(defun C:RSCP () ; = Rectangle, Save Corner Points
(command-s "_.rectang"); [must be without Fillet or Chamfer options]
(setq
pt1 (vlax-curve-getPointAtParam (entlast) 0)
pt2 (vlax-curve-getPointAtParam (entlast) 1)
pt3 (vlax-curve-getPointAtParam (entlast) 2)
pt4 (vlax-curve-getPointAtParam (entlast) 3)
); setq
(princ)
); defun
That allows any and all possible options in the making of the rectangle, including Rotation [which at a non-orthogonal angle would throw off any saving of points based on combining X and Y coordinates from opposite corners, or based on the bounding box]. But it won't return what you want if you include the Fillet or Chamfer options at non-zero values. If you really want only the specified "first" and "other" corners [even if that may not be the way the rectangle was specified], use just the pt1 and pt3 variables.
@ВeekeeCZ wrote:....
.... (command "_.block" n "_non" p e "" ; create a block ....
That makes a Block of only the just-drawn rectangle. @rebPTFNF , when you said "Is it possible to save everything drawn in a routine in a block?" were you talking about more than just one thing? That's possible, but it would require some more code.
Sorry for the late reply. Thank you to all for the great suggestions and code! I will try them out and see how it goes.
For the block request:
I have a lengthy routine (1100 lines) that creates an outdoor structure based on size and position of a rectangle first drawn by the user. Then the rest of the structure is created based off of that. The size (Area) can change what is drawn and the position (pt1, pt2, pt3, pt4) determines where its built. The structure(s) are usually placed on top of existing CAD linework of an outdoor area (which can sometimes get busy). If the structure(s) needs to be moved around once created, would be allot easier if they are already blocks. Not critical but would help save some time if that happens...
Thanks everyone and I will work on these solutions...
Can't find what you're looking for? Ask the community or share your knowledge.