Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Looking for a way to mimic Revit's align tool to align a line to another line

24 REPLIES 24
Reply
Message 1 of 25
Haider_of_Sweden
2474 Views, 24 Replies

Looking for a way to mimic Revit's align tool to align a line to another line

I work with AutoCAD and Revit on a daily basis.

Often, I miss the the ability to align lines to each other in AutoCAD as you do in Revit.

 

If we take this situation for example:

Haider_of_Sweden_1-1615453370931.png

 

In revit you'd go AL (the tool command= then pick what to align to, and then what to align. It would move to the place and have the same orientation too.

 

 

Is there any LISP solution for that?

24 REPLIES 24
Message 2 of 25

You can use MOVE or STRETCH and go from an ENDpoint or INTersection involving the one you want to change, and PERpendicular to the one you want to align it with.

Kent Cooper, AIA
Message 3 of 25

Thanks @Kent1Cooper 
This in fact how I do it today. But once you've tasted the "revit way", its hard not to want it.

You call the command, then you press source and target and done. 

 

 

Message 4 of 25
dbroad
in reply to: Haider_of_Sweden

You're trying to compare apples and oranges.  You should compare the AutoCAD Architecture toolset to Revit, not plain AutoCAD.  ACA has align, repositionfrom, walloffsetmove, and walloffsetset and automatically anchors walls to one another and doors and windows to walls. Download and experiment with a free trial version.

 

Architect, Registered NC, VA, SC, & GA.
Message 5 of 25
Haider_of_Sweden
in reply to: dbroad

Hi @dbroad 

 

I am not comparing apples and oranges 🙂

This is simple me looking for a solution that does something specific. Thank you for pointing out ALIGN for me, it is useful for other stuff (I used to move the whole object, and rotate etc, hence align is a great tool)

 

The rest of the tools seem also not to be the ones I am looking for.

If you take a look at this GIF I made, you will see what I am after. I only want to alter a sub-element, ie one segment of a polyline.

 

Align.gif

Message 6 of 25
Shneuph
in reply to: Haider_of_Sweden

If they are polylines you can use the center grip and perpendicular snap.  It's pretty close, but still not quite as fast.  This is probably the easiest solution.

 

https://knowledge.autodesk.com/community/screencast/b43e6a44-a3ba-4726-8741-3bcf5a6c9937 

---sig---------------------------------------
'(83 104 110 101 117 112 104 64 71 109 97 105 108 46 99 111 109)
Message 7 of 25

Not much slower HERE 

Message 8 of 25
dbroad
in reply to: Haider_of_Sweden

Revit is a distinctly different program than AutoCAD. AutoCAD Architecture is comparable.

That said, AutoCAD does have parametric features. They just don't work with AEC walls.

2021-03-11_13-19-40.gif

 The command illustrated above is gccollinear.

Architect, Registered NC, VA, SC, & GA.
Message 9 of 25

If we were to look at pick pline segment so get p1 p2 could do a update pline pts by new Y or X value, there is lisp for get pline segment which returns the vertice numbers, then update.

Message 10 of 25


@ВeekeeCZ wrote:

Not much slower HERE 


Very good solution!

Were you using Temporary Override Keys? Or shift RMB and then P?

 


@Sea-Haven wrote:

If we were to look at pick pline segment so get p1 p2 could do a update pline pts by new Y or X value, there is lisp for get pline segment which returns the vertice numbers, then update.


I was hoping for this type of answer, ie a LISP that asks for a pline segment and then does the segment alignment.

Any clue if there is a finished LISP script that does what I was looking for?

 

Message 11 of 25

Try this hopefully self explaining.

 

; move a pline segment based on a x or y point
; By AlanH march 2021

(defun c:plseg( / plent pick plobj pick2 param segment co-ord pt1 pt2 pt3 xy1 xy2 x y new_coord1 oldsnap)

(setq plent (entsel "\nSelect Pline segment "))

(setq
      pick (cadr plent)
      plObj (vlax-ename->vla-object (car plent))
      pick2 (vlax-curve-getclosestpointto plobj pick)
      param (vlax-curve-getparamatpoint plObj pick2)
      segment (fix param)
      co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (car plent))))
)
(setq pt1 (nth segment co-ord))
(setq pt2 (nth (+ segment 1) co-ord))
(setq oldsnap (getvar 'osmode))
(setvar 'osmode 1)
(setq pt3 (getpoint "\nPick point for reference "))
(setvar 'osmode 0)
(setq x (car pt3) y (cadr pt3))
(setq  xy (getstring "\nDo you want X or Y "))

(if (= (strcase xy) "X")
    (setq xy1 (list x (cadr pt1)) xy2 (list x (cadr pt2)))
)
(if (= (strcase xy) "Y")
    (setq xy1 (list (car pt1) y) xy2 (list (car pt2) y))
)

(setq pt1 (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble '(0 . 1)) xy1)))
(vla-put-coordinate plobj segment pt1)
(setq pt2 (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble '(0 . 1)) xy2)))
(vla-put-coordinate plobj (+ segment 1) pt2)

(setvar 'osmode oldsnap)
(princ)
)
Message 12 of 25


@Haider_of_Sweden wrote:

@ВeekeeCZ wrote:

Not much slower HERE 


Very good solution!

Were you using Temporary Override Keys? Or shift RMB and then P?

 

Yes, Shift+RMT P to launch a perpendicular osnap mode as a temporary override.

Love this feature. I even customized the key letters to be easier to remember to me.

Contrarily the built-in Temp Override Shortcuts or keys I consider unreliable.

Message 13 of 25

Mr. Haider,

Why not just use the OFFSET command?

John F. Uhden

Message 14 of 25


@john.uhden wrote:

Mr. Haider,

Why not just use the OFFSET command?


I use FIELD to generate area tags and offset would create a totally new polyline which I need to reconnect to each FIELD text..

 

@ВeekeeCZ wrote:

Yes, Shift+RMT P to launch a perpendicular osnap mode as a temporary override.

Love this feature. I even customized the key letters to be easier to remember to me.

Contrarily the built-in Temp Override Shortcuts or keys I consider unreliable.


Indeed a good feature. Would you please share how you customized the key letters? 

And regarding the Temp Override Shortcuts, what do you dislike there? I can see there are shortcuts defined, but I could never figure out how to use them

Haider_of_Sweden_1-1616501414898.png

 

@Sea-Haven wrote:

Try this hopefully self explaining.

 

 

; move a pline segment based on a x or y point
; By AlanH march 2021

(defun c:plseg( / plent pick plobj pick2 param segment co-ord pt1 pt2 pt3 xy1 xy2 x y new_coord1 oldsnap)

(setq plent (entsel "\nSelect Pline segment "))

(setq
      pick (cadr plent)
      plObj (vlax-ename->vla-object (car plent))
      pick2 (vlax-curve-getclosestpointto plobj pick)
      param (vlax-curve-getparamatpoint plObj pick2)
      segment (fix param)
      co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (car plent))))
)
(setq pt1 (nth segment co-ord))
(setq pt2 (nth (+ segment 1) co-ord))
(setq oldsnap (getvar 'osmode))
(setvar 'osmode 1)
(setq pt3 (getpoint "\nPick point for reference "))
(setvar 'osmode 0)
(setq x (car pt3) y (cadr pt3))
(setq  xy (getstring "\nDo you want X or Y "))

(if (= (strcase xy) "X")
    (setq xy1 (list x (cadr pt1)) xy2 (list x (cadr pt2)))
)
(if (= (strcase xy) "Y")
    (setq xy1 (list (car pt1) y) xy2 (list (car pt2) y))
)

(setq pt1 (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble '(0 . 1)) xy1)))
(vla-put-coordinate plobj segment pt1)
(setq pt2 (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble '(0 . 1)) xy2)))
(vla-put-coordinate plobj (+ segment 1) pt2)

(setvar 'osmode oldsnap)
(princ)
)

 


Great solution @Sea-Haven 

 

Two questions: 

1) On some polylines, this lisp halts. I get this 

 

 

Do you want X or Y y
Cannot invoke (command) from *error* without prior call to (*push-error-using-command*).
Converting (command) calls to (command-s) is recommended.

 

 

What do you think the causes could be?

 

 

2) You think you can make the LISP understand the X or Y based on the picked reference line?

 

Right now, your script works on perpendicular angles in either X or Y. This means if the reference line's two verts are located in 0,0 and 10,0 then we could calculate that the alignment should be X.

While if the verts would be 0,0 and 0,10 then we have Y alignment.

From the examples above, if both X values are the same then we have Y alignment and if both Y values are similar we have X alignment, right?

 

You could even put in a threshold value, so that if you have 0,0 and 0.1,10 it would still be considered as X. Or maybe not, then the user would know that the reference line isn't 100% perpendicular and need to act on it.

 

Message 15 of 25

I don't know what all this X and Y stuff is about, but parallel to me means
at the same angle, so the polar function could be used to compute the new
endpoints. But what point on the line is being held, 1st, 2nd, midpoint?
Do you want to maintain its length? If it's 3D, do you want to maintain
its Z values, or if the length is to change, do you want to maintain its
slope?

John F. Uhden

Message 16 of 25

I have it renamed so just to see the tree place. The key letter is defined by & (ampersand).

Z9E3zK5E_0-1616504372184.png

 

Message 17 of 25

@Haider_of_Sweden 

Try this.  It doesn't work (yet) with polylines, and it may not retain the line's original length, but it's a start.

But, you will find that lines can be at any angle.

(defun c:Realign ( / *error* cmd e1 e2 ent1 ent2 p1 p2 p3 p4 ang)
   (gc)
   (vl-load-com)
   (prompt "\nREALIGN (c)2021, John F. Uhden for @Haider_of_Sweden")

   (defun *error* (err)
      (if (= (type cmd) 'INT)(setvar "cmdecho" cmd))
      (vla-endundomark *doc*)
      (cond
        ((not err))
        ((wcmatch (strcase err) "*CANCEL*,*QUIT*")
          (vl-exit-with-error "\r                                              ")
        )
        (1 (vl-exit-with-error (strcat "\r*ERROR*: " err)))
      )
      (princ)
   )
   ;;-----------------------------------------------
   ;; Initialize some drawing and program variables:
   ;;
   (setq *doc* (vlax-get (vlax-get-acad-object) 'Activedocument)
         cmd (getvar "cmdecho")
   )
   (vla-endundomark *doc*)
   (vla-startundomark *doc*)
   (setvar "cmdecho" 0)
   (command "_.expert" (getvar "expert")) ;; dummy command
   (and
    (setq e1 (car (entsel "\nSelect primary line: ")))
	(setq ent1 (entget e1))
	(or
	  (= (cdr (assoc 0 ent1)) "LINE")
	  (prompt "\nRntity selected is not a line.")
	)
	(setq p1 (cdr (assoc 10 ent1))
	      p2 (cdr (assoc 11 ent1))
    )
	(setq e2 (car (entsel "\nSelect line to realign to primary: ")))
	(or (not (equal e1 e2))
	  (prompt "  Same entity selected.")
	)
	(setq ent2 (entget e2))
	(or
	  (= (cdr (assoc 0 ent2)) "LINE")
	  (prompt "\nRntity selected is not a line.")
	)
    (setq p3 (cdr (assoc 10 ent2))
	      p4 (cdr (assoc 11 ent2))
    )
	(setq ang (+ (angle p1 p2)(* pi 0.5)))
	(setq p3 (inters p3 (polar p3 ang 10) p1 p2 nil)
	      p4 (inters p4 (polar p4 ang 10) p1 p2 nil)
    )
	(setq ent2 (subst (cons 10 p3)(assoc 10 ent2) ent2))
	(setq ent2 (subst (cons 11 p4)(assoc 11 ent2) ent2))
	(entmod ent2)
  )
  (*error* nil)
)
	

 

John F. Uhden

Message 18 of 25

You are right you could look at segment selected and compare the 2 points making the segment x1,y1 and x2,y2 if y1 = y2 then yes its horizontal. 

 

You have pt1 pt2 so as you say no need for question x or y just need to work it out. Your more than welcome to change the code. 

Message 19 of 25
john.uhden
in reply to: Sea-Haven

@Haider_of_Sweden 

I couldn't resist.

This version realigns lines with polyline segments as well (if not bulged).

Of course with a little more work it could realign with tangents to bulges or with text/mtext, etc.

(defun c:Realign ( / *error* cmd e1 e2 ent1 ent2 etype p obj param p1 p2 p3 p4 ang)
   (gc)
   (vl-load-com)
   (prompt "\nREALIGN v1.1 (c)2021, John F. Uhden for @Haider_of_Sweden")

   (defun *error* (err)
      (if (= (type cmd) 'INT)(setvar "cmdecho" cmd))
      (vla-endundomark *doc*)
      (cond
        ((not err))
        ((wcmatch (strcase err) "*CANCEL*,*QUIT*")
          (vl-exit-with-error "\r                                              ")
        )
        (1 (vl-exit-with-error (strcat "\r*ERROR*: " err)))
      )
      (princ)
   )
   ;;-----------------------------------------------
   ;; Initialize some drawing and program variables:
   ;;
   (setq *doc* (vlax-get (vlax-get-acad-object) 'Activedocument)
         cmd (getvar "cmdecho")
   )
   (vla-endundomark *doc*)
   (vla-startundomark *doc*)
   (setvar "cmdecho" 0)
   (command "_.expert" (getvar "expert")) ;; dummy command
   (and
    (setq p (entsel "\nSelect source line segment: "))
    (setq e1 (car p))
	(setq ent1 (entget e1))
	(setq etype (cdr (assoc 0 ent1)))
	(cond
	  ((= etype "LINE")
    	(setq p1 (cdr (assoc 10 ent1))
	          p2 (cdr (assoc 11 ent1))
        )
	  )
	  ((= etype "LWPOLYLINE")
	    (setq p (cadr p)
		      obj (vlax-ename->vla-object e1)
        	  p (vlax-curve-getclosestpointto obj p)
			  param (vlax-curve-getparamatpoint obj p)
	    )
		(if (not (zerop (vla-getbulge obj param)))
		  (prompt "\n  Segment selected is bulged.")
		  (setq p1 (vlax-curve-getpointatparam obj (fix param))
			    p2 (vlax-curve-getpointatparam obj (1+ (fix param)))
          )
		)
	  )
	  (1 (prompt (strcat "\n  Entity selected is a(n) " etype)))
	)
	(setq e2 (car (entsel "\nSelect line to realign to primary: ")))
	(or (not (equal e1 e2))
	  (prompt "\n  Same entity selected.")
	)
	(setq ent2 (entget e2))
	(or
	  (= (cdr (assoc 0 ent2)) "LINE")
	  (prompt "\n  Rntity selected is not a line.")
	)
    (setq p3 (cdr (assoc 10 ent2))
	      p4 (cdr (assoc 11 ent2))
    )
	(setq ang (+ (angle p1 p2)(* pi 0.5)))
	(setq p3 (inters p3 (polar p3 ang 10) p1 p2 nil)
	      p4 (inters p4 (polar p4 ang 10) p1 p2 nil)
    )
	(setq ent2 (subst (cons 10 p3)(assoc 10 ent2) ent2))
	(setq ent2 (subst (cons 11 p4)(assoc 11 ent2) ent2))
	(entmod ent2)
  )
  (*error* nil)
)
	

 

John F. Uhden

Message 20 of 25
Sea-Haven
in reply to: john.uhden

Hi John just not sure am I doing something wrong running your code ? My code uses a pline segment and a point. I had to explode the original pline etc to get anything to work.

 

Went back and reread some posts by Haider

 

"If you take a look at this GIF I made, you will see what I am after. I only want to alter a sub-element, ie one segment of a polyline."

 

Select line to realign to primary:
Rntity selected is not a line.

 

screenshot363.png

 

You are correct for angled plines which is correct pt, X Y or  is it actually the extension of the destination pline direction. I think we need Haider to confirm.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report