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

Angle from XY plane

21 REPLIES 21
Reply
Message 1 of 22
kpennell
3605 Views, 21 Replies

Angle from XY plane

So I've done a lot of searching this morning on "angles", and I couldn't find anything for getting the "out-of-plane" angle.

 

I'd like the user to pick two points, and return somehow the angle out of plane.

 

Thanks

KP

21 REPLIES 21
Message 2 of 22
_Tharwat
in reply to: kpennell

This ... ?

 

(if (and (setq p (getpoint "\n First point :"))
         (setq p1 (getpoint "\n Second point :" p))
)
(print (angle p p1))
)

 

Message 3 of 22
kpennell
in reply to: kpennell

This gives the angle "IN" the XY plane.  I need the angle "FROM" the XY plane.

Message 4 of 22
_Tharwat
in reply to: kpennell

Maybe this .... ?

 

(if (and (setq a (getpoint "\n First point :"))
         (setq b (getpoint "\n Second point :" a))
    )
  (progn
    (setq ang (- (angle a b) (angle a (polar a 0.0 (distance a b)))))
    (print (* 180.0 (/ ang pi))
    )
  )
)

 

Message 5 of 22
kpennell
in reply to: _Tharwat

This returns the same value, which is the value IN plane, not OUT OF plane or FROM plane

 

Appreciate the efforts though

Message 6 of 22
_Tharwat
in reply to: kpennell

Would you upload an image or a drawing showing your desire of the XY plane 's angle?

Message 7 of 22
kpennell
in reply to: _Tharwat

It's the same principle as useing the distance command.  When a user picks two points using the distance command there are some values retuned to the command prompt.  I've copied an example based on two random points:

 

Distance = 1'-3 7/16",  Angle in XY Plane = 314.97223515,  Angle from XY Plane = 1.20000000
Delta X = 0'-10 233/256",  Delta Y = -0'-10 235/256",   Delta Z = 0'-0 83/256"

 

I'd like to have the exact value that represents "Angle from XY Plane" returned to a variable somehow.

 

Does this clean up what I'm asking?

 

Thanks

KP

Message 8 of 22
Kent1Cooper
in reply to: kpennell


@kpennell wrote:

So I've done a lot of searching this morning on "angles", and I couldn't find anything for getting the "out-of-plane" angle.

 

I'd like the user to pick two points, and return somehow the angle out of plane.

....


Something like this, perhaps:

 

(setq
  p1 (getpoint "\nPick first point: ")
  p2 (getpoint "\nPick second point: ")
  distinXY (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0))
  deltaZ (- (caddr p2) (caddr p1))
  angfromXYplane (angtos (atan (/ deltaZ distinXY)))
)

 

or, with fewer variables:

 

(setq
  p1 (getpoint "\nPick first point: ")
  p2 (getpoint "\nPick second point: ")
); setq
(angtos
  (atan
    (/
      (- (caddr p2) (caddr p1)); = change in Z
      (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0)); = distance projected in XY plane
    ); /
  ); atan
); angtos

 

I do find that it always returns positive values -- e.g. from 0,0,0 to 1,0,-1 returns 315 degrees.  If you'd rather have that say -45 degrees, you'd need to do some conversion somewhere.

Kent Cooper, AIA
Message 9 of 22
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:
....

I do find that it always returns positive values -- e.g. from 0,0,0 to 1,0,-1 returns 315 degrees.  If you'd rather have that say -45 degrees, you'd need to do some conversion somewhere.


Like this, for instance:

 

(setq
  p1 (getpoint "\nPick first point: ")
  p2 (getpoint "\nPick second point: ")
); setq
(strcat
  (if (< (caddr p2) (caddr p1)) "-" "")
  (angtos
    (atan
      (/
        (abs (- (caddr p2) (caddr p1)))
        (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0))
      ); /
    ); atan
  ); angtos
); strcat

Kent Cooper, AIA
Message 10 of 22
phanaem
in reply to: kpennell

For some reasons, I wrote this code to replace native Distance command. It will give you the angle from XY plane among other infos.

(defun C:DI16 (/ *error* lst msg p1 p2 oldzin)

  (defun *error* (msg)
      (and msg
	   (not (eq msg "Function cancelled"))
	   (princ msg)
	   )
    (setvar 'dimzin oldzin)
    (princ)
  )

  (setq oldzin (getvar 'dimzin))
  (setvar 'dimzin 1)
  (and
    (setq p1 (getpoint "\nFirst Point: "))
    (setq p2 (getpoint p1 "\nSecond Point: "))
    (setq lst  (mapcar '- p2 p1)
	  lst1 (mapcar '(lambda (x) (rtos x 2 16)) lst)
    )
    (setq lst1 (cons (angtos (atan (caddr lst) (sqrt (+ (expt (car lst) 2) (expt (cadr lst) 2)))) (getvar 'aunits) 16) lst1))
    (setq lst1 (cons (angtos (atan (cadr lst) (car lst)) (getvar 'aunits) 16) lst1))
    (setq lst1 (cons (rtos (distance p1 p2) 2 16) lst1))
    (mapcar
      '(lambda (x msg)
	 (princ (strcat msg x))
       )
      lst1
      (list "\nDistance            = "
	    "\nAngle in XY Plane   = "
	    "\nAngle from XY Plane = "
	    "\nDelta X             = "
	    "\nDelta Y             = "
	    "\nDelta Z             = "
	   )
    )
  )
  (*error* nil)
  (textscr)
  (princ)
)

 

Message 11 of 22
kpennell
in reply to: kpennell

This is almost it.  The value that is returned depends on the units.  This tells me that the true angle won't bereturned to do any real calculations.

 

Thanks KC

KP

Message 12 of 22
kpennell
in reply to: Kent1Cooper

Hey KC

 

Here's what I did.  I removed the angtos function, which converts the value to a string based on the units of the drawing, and did the radians-to-degrees calculation.

 

It works out the way I wanted it too, with the added check to see whick point is/was lower than the other.

 

    (setq p1 (getpoint "Select first point: "))
    (setq p2 (getpoint "Select second point: "))

    (setq ang (angle p1 p2))
    (setq p1z (caddr p1))
    (setq p2z (caddr p2))

 

    (setq distinXY (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0)))
    (setq deltaZ (- (caddr p2) (caddr p1)))
    (setq first_angle (atan (/ deltaZ distinXY)))

    (cond
    ((< p1z p2z)(setq first_angle (* -180.0 (/ first_angle pi))))
    ((> p1z p2z)(setq first_angle (* 180.0 (/ first_angle pi))))
    )

 

Thanks so much for the direction.

Message 13 of 22
CADaSchtroumpf
in reply to: kpennell

Hi,

 

I use this, is good for you?

 

(defun C:ID-Angle ( / pt_o pt_f dxf_11 ang ang_z)
  (initget 8)
  (setq pt_o (getpoint "\nGive the first point: "))
  (if (null pt_o) (setq pt_o (getvar "lastpoint")))
  (cond
    (pt_o
      (initget 41)
      (setq pt_f (getpoint pt_o "\nGive the second point: "))
      (cond
        (pt_f
          (setq dxf_11
            (trans
              (mapcar
                '(lambda (x / ) (/ x (distance (trans pt_o 1 0) (trans pt_f 1 0))))
                (mapcar '- (trans pt_f 1 0) (trans pt_o 1 0))
              )
              0 1 T
            )
          )
          (if (zerop (car dxf_11))
            (setq ang "infinity")
            (setq ang (angtos (atan (/ (cadr dxf_11) (car dxf_11)))))
          )
          (if (= (caddr dxf_11) 1.0)
            (setq dev_z "infinity")
            (if (zerop (caddr dxf_11))
              (setq ang_z (angtos 0.0))
              (setq ang_z (angtos (atan (sqrt (/ 1.0 (- (/ 1.0 (* (caddr dxf_11) (caddr dxf_11))) 1.0))))))
            )
          )
          (prompt (strcat "\nAngle in XY Plane = " ang " - Angle from XY Plane = " ang_z))
          (alert (strcat "Angle in XY Plane = " ang " - Angle from XY Plane = " ang_z))
        )
      )
    )
  )
  (prin1)
)

 

Message 14 of 22
Kent1Cooper
in reply to: kpennell


@kpennell wrote:

.... 

Here's what I did.  I removed the angtos function, which converts the value to a string based on the units of the drawing, and did the radians-to-degrees calculation.

 

It works out the way I wanted it too, with the added check to see whick point is/was lower than the other.

 

    (setq p1 (getpoint "Select first point: "))
    (setq p2 (getpoint "Select second point: "))

    (setq ang (angle p1 p2))
    (setq p1z (caddr p1))
    (setq p2z (caddr p2))

 

    (setq distinXY (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0)))
    (setq deltaZ (- (caddr p2) (caddr p1)))
    (setq first_angle (atan (/ deltaZ distinXY)))

    (cond
    ((< p1z p2z)(setq first_angle (* -180.0 (/ first_angle pi))))
    ((> p1z p2z)(setq first_angle (* 180.0 (/ first_angle pi))))
    )

 

Thanks so much for the direction.


You're welcome.  It wasn't clear from the initial message whether you wanted to just report the result to the User [what mine opted for] or make further use of it.  Here's a more concise way to save a value for the latter, consolidating multiple (setq) functions into one, and eliminating some variables that are used only once, so they may as well just have their calculations at the places where they're used, and skip the variables.

 

(setq
  p1 (getpoint "Select first point: ")
  p2 (getpoint "Select second point: ")

  deltaZ (- (caddr p2) (caddr p1))

  first_angle
  (/ ; start of radians-to-degrees conversion
    (*
      (if (> deltaZ 0) 1 -1); p2 above or below p1
      180
      (atan
        (/
          (abs deltaZ); positive whatever the relationship
          (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0)); XY differential
        ); end /
      ); end atan
    ); end *
    pi
  ); end / & first_angle
); setq

Kent Cooper, AIA
Message 15 of 22
phanaem
in reply to: Kent1Cooper

Kent, you can shorten your code a little bit more.

If you use (abs deltaz) in combination with a positive number, ATAN function always returns a number between 0 and pi / 2, so you don't need (if (> deltaZ 0) 1 -1).

Atan function can take 2 arguments, so no need  (/ (abs deltaZ) (distance ...

Further, if you use (atan (/ a b)) and b is zero, you get "divide by zero.." message. (atan a b) will take care of that situation and will return pi / 2. But you already know that...

So, your code may look like:

 

(setq
  p1 (getpoint "Select first point: ")
  p2 (getpoint "Select second point: ")

  deltaZ (- (caddr p2) (caddr p1))

  first_angle
  (/ ; start of radians-to-degrees conversion
    (*
;;;      (if (> deltaZ 0) 1 -1); p2 above or below p1
      180
      (atan
;;;        (/
          (abs deltaZ); positive whatever the relationship
          (distance (list (car p1) (cadr p1) 0) (list (car p2) (cadr p2) 0)); XY differential
;;;        ); end /
      ); end atan
    ); end *
    pi
  ); end / & first_angle
); setq

 

Message 16 of 22
Kent1Cooper
in reply to: phanaem


@phanaem wrote:

Kent, you can shorten your code a little bit more.

If you use (abs deltaz) in combination with a positive number, ATAN function always returns a number between 0 and pi / 2, so you don't need (if (> deltaZ 0) 1 -1).

Atan function can take 2 arguments, so no need  (/ (abs deltaZ) (distance ...

Further, if you use (atan (/ a b)) and b is zero, you get "divide by zero.." message. (atan a b) will take care of that situation and will return pi / 2. But you already know that...

So, your code may look like:

.... 


I think you may have missed part of the purpose.  If the two points are [for example] 0,0,0 and 1,0,-1, with the second point at a downward angle from the first relative to the XY plane, the return is -45.0 from both my routine and kpennell's, but from yours it's 45.0 [positive], the same return as if the second point were 1,0,[+]1.  So you do need the (if (> deltaZ 0) 1 -1) line, or some other way [I can think of at least one] to give a negative return for a second point lower than the first point.

 

No, I wasn't aware of (atan) optionally taking two arguments, so yes, the (/) function could be removed.  Dividing by zero would happen only if the two selected points are the same in the XY coordinates [above/below each other or coincident].  If they are the same point [including Z], yours would return 0,0, implying that the second point is at a 0-degree angle from the first point relative to the XY plane [the same as if they were, say, 0,0,0 and 1,0,0].  Technically, AutoCAD would consider it to be, just as the (angle) function returns 0 if it's given the same point twice, but I would consider it to be at no angle.  I couldn't say what the OP would prefer, but for me, I think I would want to be warned that I had picked the same point twice.  Probably a check on that, before the angle calculation, would be best, because it would preserve the viability of points vertically aligned, whereas leaving it to a divide-by-zero error message wouldn't.

Kent Cooper, AIA
Message 17 of 22
phanaem
in reply to: Kent1Cooper

Yes, I missed that part on the negative angle. In this case, is even easier. The second argument in atan function is always positive so the angle returned is from -pi/2 to pi/2.

 

(setq
  p1 (getpoint "Select first point: ")
  p2 (getpoint "Select second point: ")
  first_angle
  (/ 
    (* 180
      (atan
          (- (caddr p2) (caddr p1))
          (distance (list (car p1) (cadr p1)) (list (car p2) (cadr p2)))
      )
    )
    pi
  )
)

Remains to solve the situation when the same point is picked twice..

 

Message 18 of 22
raulbueno
in reply to: phanaem

You know what would be incredible useful? To have Kent Cooper's lisp "ReportSlope.slp" to give you the data FROM the xy plane, and not OF the xy plane.

https://forums.autodesk.com/autodesk/attachments/autodesk/130/282833/1/ReportSlope.lsp
Message 19 of 22
Kent1Cooper
in reply to: raulbueno


@raulbueno wrote:
You know what would be incredible useful? To have Kent Cooper's lisp "ReportSlope.slp" to give you the data FROM the xy plane, and not OF the xy plane.
....

That should be doable enough.  ReportSlope.lsp is restricted to reporting the angle from the X axis in the XY plane [as described in the comments at the top] because that's what the (angle) function returns, ignoring any Z-direction component.  So it would need to calculate the 3D angle otherwise, but that's not hard.

 

But some questions:

 

Would it be better to report an absolute-value kind of angle, as ReportSlope.lsp does, or would you want to distinguish between upward and downward slopes?  For instance, would a Line from 0,0,0 to 1,0,1 be reported as 45 degrees, but one from 0,0,0 to 1,0,-1 as -45 degrees, or should they both be considered just 45 degrees?

 

What about a Line drawn between the same points, but in the opposite direction?  Should a Line drawn from 1,0,1 to 0,0,0 be -45 degrees because that's its drawn direction, or [+]45 degrees because that's its angle off the XY plane?  What about if neither end is on the XY plane?

Kent Cooper, AIA
Message 20 of 22
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:

@raulbueno wrote:
You know what would be incredible useful? To have Kent Cooper's lisp "ReportSlope.slp" to give you the data FROM the xy plane, and not OF the xy plane.
....

....

Would it be better to report an absolute-value kind of angle...?

....


On the assumption that the answer to the question above is Yes, try the attached ReportSlopeZ.lsp with its RSZ command.  If you want other permutations on how it decides whether an angle is positive or negative, how to deal with things entirely away from the XY plane, etc., describe them, and maybe they can be worked in.  Lightly tested.

Kent Cooper, AIA

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

Post to forums  

Autodesk Design & Make Report

”Boost