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

Haider_of_Sweden
Collaborator
Collaborator

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

Haider_of_Sweden
Collaborator
Collaborator

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?

0 Likes
Reply
2,468 Views
24 Replies
Replies (24)

Kent1Cooper
Consultant
Consultant

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
0 Likes

Haider_of_Sweden
Collaborator
Collaborator

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. 

 

 

0 Likes

dbroad
Mentor
Mentor

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.
0 Likes

Haider_of_Sweden
Collaborator
Collaborator

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

0 Likes

Shneuph
Collaborator
Collaborator

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)
0 Likes

ВeekeeCZ
Consultant
Consultant

Not much slower HERE 

dbroad
Mentor
Mentor

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.

Sea-Haven
Mentor
Mentor

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.

0 Likes

Haider_of_Sweden
Collaborator
Collaborator

@В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?

 

0 Likes

Sea-Haven
Mentor
Mentor

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

ВeekeeCZ
Consultant
Consultant

@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.

0 Likes

john.uhden
Mentor
Mentor

Mr. Haider,

Why not just use the OFFSET command?

John F. Uhden

0 Likes

Haider_of_Sweden
Collaborator
Collaborator

@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.

 

0 Likes

john.uhden
Mentor
Mentor
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

0 Likes

ВeekeeCZ
Consultant
Consultant

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

Z9E3zK5E_0-1616504372184.png

 

john.uhden
Mentor
Mentor

@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

0 Likes

Sea-Haven
Mentor
Mentor

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. 

0 Likes

john.uhden
Mentor
Mentor

@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

0 Likes

Sea-Haven
Mentor
Mentor

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.

0 Likes