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

Skew lines -shortest distance

24 REPLIES 24
SOLVED
Reply
Message 1 of 25
klosow
3035 Views, 24 Replies

Skew lines -shortest distance

Hello I create the LISP script (attached) to find the shortest distance between two skew lines.

Finnally, I want to draw a segment which represents this shortest distance. It should be a line between apperen intersections of:  PR1 and PR2 lines and PR2 and PR1 lines (on the screen they will be visible in the same point). Lines were indicated before, so I want to write proper LISP expression without indicating them again. What is proper form of line command?

(command "_line"  ???????? "")

Pawel Klosowski

 

24 REPLIES 24
Message 2 of 25
pbejse
in reply to: klosow


@klosow wrote:

Hello I create the LISP script (attached) to find the shortest distance between two skew lines.

Finnally, I want to draw a segment which represents this shortest distance. It should be a line between apperen intersections of:  PR1 and PR2 lines and PR2 and PR1 lines (on the screen they will be visible in the same point). Lines were indicated before, so I want to write proper LISP expression without indicating them again. What is proper form of line command?

(command "_line"  ???????? "")

Pawel Klosowski

 


Hi Klosow.

looking at your code, Its not really clear what you want to accomplish, since you prompted for two points on screen, it defeats the purpose of computing for the shortest distance., those two points will be enough information for you to draw the line.

if you can show an illustration maybe we can better suggest.

 

if you're tryng to get the start point and endpoint of a line, you can use

 

(setq XX1      (entsel "\nIndicate first line:")
		      start_pt1 (cdr (assoc 10 (entget (car xx1))))
		      end_pt1   (cdr (assoc 11 (entget (car xx1))))
		)
(setq XX2      (entsel "\nIndicate second line:")
        start_pt2 (cdr (assoc 10 (entget (car xx2))))
        end_pt2   (cdr (assoc 11 (entget (car xx2))))
  )

 then you can compute from that list the nearest distance wihtout prompting for points on the screen

 

 hope this helps

 

 

 

 

 

Message 3 of 25
pbejse
in reply to: pbejse

then you use this

 

 

(command "_.line" "none" (*your_point1*) "none" (*your_point2*))

;;	or VL	


(vla-addline (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object)))
(vlax-3d-point (*your_point1*));<----		result of computation
(vlax-3d-point (*your_point2*));<----		result of computation
			  
				 )

 


Notice the "None" on there? This will avoid errors on dealing with osnaps

hope this helps

 

Message 4 of 25
klosow
in reply to: klosow

This way I can comput the shortest distance, but iI also want to draw proper segment.

Message 5 of 25
klosow
in reply to: pbejse

I improved my algorithm (see new version of nwek_En.lsp file) and try two proposed versions of solution. Non of them work. Works line

(command "_line" "_appint" pause "_appint" pause "")

but in this wariant I need to pick up twice both segments again.

Message 6 of 25
pbejse
in reply to: klosow

geez klosow, :smileysad:

 

I did not mean for you to paste it on your code on its face value

 

This line tells you to put your variable point after processing the list.

 

 (vlax-3d-point (*your_point1*));<----  result of computation

 

*yourpoint1* means the result of your computation. I dont fully understand your intent thats why i cant tell you how exaclty the code will be written.

 

if you can describe it better it will help us here a lot (and help you)

  • :smileyhappy:
  • btw your code deals with math functions, i.e.. -,+,*... be careful with negative values as this will affect your results

    thats why i suggest ed that you work with point list, the function "distance" can be use for your test routine

     

     

     

     

     

     

     

    Message 7 of 25
    Kent1Cooper
    in reply to: klosow

    I haven't figured out the mathematics behind the vector calculations, but I'll assume they're valid, and that they're establishing only a direction, not any specific points.  A couple of things:
     

    As you have it, it seems the User could choose the end point of a Line that is the same as the end nearer to the point by which the Line itself was selected.  In that case, P1 and P2 would be the same, and the routine would fail.  You should probably get the endpoints from the entity data as pbejse suggested, rather than ask the User to designate an end point.  But if you really want the User to pick and end for some reason, you should prompt them for the end farther from where they selected the Line.

     

    After establishing a UCS view looking along the shortest-distance vector and with line 1 as its basis, the start point for the shortest-distance Line uses APPINT and has a pause, apparently for the User to select the apparent intersection.  That will use the point in the current UCS, which will lie on line 1.  For the second point, rather than use APPINT again and another pause [which will find the same point as the first one], you should probably use PERpendicular Osnap and a pause, but how you can ensure that the User will snap to the second Line, I'm not sure.

     

    Maybe the (vlax-curve-getClosestPointToProjection) function could be helpful, but I'm not sure about that, either.

    Kent Cooper, AIA
    Message 8 of 25
    klosow
    in reply to: Kent1Cooper

    Probably I haven't described problem clear enough. In fact I have two skew lines and I want to construct the segment which links them and has the shortest length. At the beginning I had to pick my two lines (XX1 and XX2) then according to math formulas I put the local coordinate system is such position that Z axis is normal to XX1 and XX2 (command ucs) and I take a view from the top of Z axis (command plan). Now the segment which I want can be constructed as linking apparent intersection of XX1 versus XX2 and XX2 versus XX1 (as perpendicular to XX2 - it also correct). I can easy make is using command

     (command "_line" "_appint" pause "_appint" pause "")

    but in this situation I will have to pick both lines once more (for a large drawing it can be difficult as the plan command will change the scale of the actual view).

    The problem is how to make it without picking lines once more. I want to draw the segment  using information which I provided picking them at the beginning of the algorithm (XX1 and XX2).

    The problem is general: how to make reference (e.g. in line command) to objects which have been selected before?

    Message 9 of 25
    Kent1Cooper
    in reply to: klosow


    @klosow wrote:

    ....

    The problem is general: how to make reference (e.g. in line command) to objects which have been selected before?


    The general answer is that you use the variables in which you have stored the objects' entity names [in this case, PR1 and PR2].  HOWEVER, in this particular situation, you can't use them for the apparent intersection, because APPINT doesn't accept entity names as input.  [I assume Osnap in general doesn't, but I haven't tested the possibilities.]

     

    I had assumed that your "appint" followed by one pause would be for the User to position the aperture box over the apparent intersection itself [one pick] rather than pick on the two Lines separately.  That's the approach that would find the same location for both Osnaps.  But I was pleased to find, in experimenting a little, that if you pick on an object at a place where nothing appears to intersect it, it allows you to pick another object within the same pause, and that if you do that with two Lines in opposite order between the two APPINT calls, it correctly finds the two different locations, rather than using the projection onto the current plane that it does if you do one pick on an apparent intersection.

     

    Since you can't use entity names as input for APPINT, but you can use point locations, you can just use your P1 and P3, which are each an end of the two different Lines.  This seems to work if there's nothing else around that it might snap to instead of the two intended Lines:

     

    (command "_.line" "appint" P1 P3 "appint" P3 P1 "")

     

    But I can't imagine you can count on having nothing else around that might confuse things.  To overcome that problem, I suspect there's a way to do the entire thing without using Osnap, all by calculation.  I will play with that and get back if I figure it out.

    Kent Cooper, AIA
    Message 10 of 25
    Kent1Cooper
    in reply to: Kent1Cooper


    @Kent1Cooper wrote:
    ....I suspect there's a way to do the entire thing without using Osnap, all by calculation.  I will play with that and get back if I figure it out.

    This seems to do that, in limited testing:

     

    (defun C:LSBSL ; = Line - Shortest Between Skewed Lines
      (/ L1 L2 1data 2data 1A 1B 2A 2B 2Y)
      (setq
        L1 (car (entsel "\nSelect a Line: "))
        L2 (car (entsel "\nSelect another Line: "))
        1data (entget L1)
        2data (entget L2)
        1A (cdr (assoc 10 1data)); start of first Line
        1B (cdr (assoc 11 1data)); end of first Line
        2A (cdr (assoc 10 2data)); start of second Line
        2B (cdr (assoc 11 2data)); end of second Line
      )
      (setvar 'osmode 0)
      (command
        "_.ucs" "_za" 1A 1B; looking along first Line
        "_.ucs" "_z" (trans 2A 0 1) (trans 2B 0 1)
          ; make second Line horizontal in first-Line view
      ); end command
      (setq 2Y (cadr (trans 2A 0 1)))
        ; Y position of second Line relative to first, current UCS
      (command
        "_line"
          (inters ; closest point on second Line to first
             (trans 2A 0 1); ends of second Line
             (trans 2B 0 1)
             (list 0 2Y 0); parallel to first Line, in plane of second
             (list 0 2Y 1)
             nil
          ); end inters
          (list 0 0 (caddr (getvar 'lastpoint)))
            ; on first Line at current-Z location of closest point
          ""
        "_.ucs" "_previous"
        "_.ucs" "_previous"
      ); end command
    )

    It does not yet have error handling, or save or reset OSMODE, or have object-type selection controls, or turn off UCSFOLLOW, or any of the other usual stuff, but if it does what you want, those can be included easily enough.  It could even be made to work with Polyline line segments, or even with those or Lines that are parts of Blocks/Xrefs, if that's desirable.

     

    It might also be desirable to build something in to alert the User if the two Lines are parallel, or if they actually intersect, or maybe some other possibilities.

    Kent Cooper, AIA
    Message 11 of 25
    hgasty1001
    in reply to: klosow

    Hi,

     

    The shortest distance between 2 lines it's NOT the apparent intersection, just check this link:

     

    http://mathworld.wolfram.com/Line-LineDistance.html

     

    Very easy to program in plain Autolisp.

     

     

    Gaston Nunez

    Message 12 of 25
    pbejse
    in reply to: Kent1Cooper


    @Kent1Cooper wrote:

    @Kent1Cooper wrote:
    ....I suspect there's a way to do the entire thing without using Osnap, all by calculation.  I will play with that and get back if I figure it out.

    This seems to do that, in limited testing:

     

    (defun C:LSBSL ; = Line - Shortest Between Skewed Lines
      (/ L1 L2 1data 2data 1A 1B 2A 2B 2Y)
      (setq
        L1 (car (entsel "\nSelect a Line: "))
        L2 (car (entsel "\nSelect another Line: "))
        1data (entget L1)
        2data (entget L2)
        1A (cdr (assoc 10 1data)); start of first Line
        1B (cdr (assoc 11 1data)); end of first Line
        2A (cdr (assoc 10 2data)); start of second Line
        2B (cdr (assoc 11 2data)); end of second Line
      )
      (setvar 'osmode 0)
      (command
        "_.ucs" "_za" 1A 1B; looking along first Line
        "_.ucs" "_z" (trans 2A 0 1) (trans 2B 0 1)
          ; make second Line horizontal in first-Line view
      ); end command
      (setq 2Y (cadr (trans 2A 0 1)))
        ; Y position of second Line relative to first, current UCS
      (command
        "_line"
          (inters ; closest point on second Line to first
             (trans 2A 0 1); ends of second Line
             (trans 2B 0 1)
             (list 0 2Y 0); parallel to first Line, in plane of second
             (list 0 2Y 1)
             nil
          ); end inters
          (list 0 0 (caddr (getvar 'lastpoint)))
            ; on first Line at current-Z location of closest point
          ""
        "_.ucs" "_previous"
        "_.ucs" "_previous"
      ); end command
    )

    It does not yet have error handling, or save or reset OSMODE, or have object-type selection controls, or turn off UCSFOLLOW, or any of the other usual stuff, but if it does what you want, those can be included easily enough.  It could even be made to work with Polyline line segments, or even with those or Lines that are parts of Blocks/Xrefs, if that's desirable.

     

    It might also be desirable to build something in to alert the User if the two Lines are parallel, or if they actually intersect, or maybe some other possibilities.


     

    Wow... now i understand.

    its 3dimension, thats whats thowing me off

     

    nice code btw Kent Smiley Happy

     

     

     

    Message 13 of 25
    klosow
    in reply to: pbejse

    To message 9:

    code

     

    (command "_.line" "appint" P1 P3 "appint" P3 P1 "")

    produces an error

     

    To message 10:

     

    Yes, this is what I wanted!!  As the idea of the algorithm is different than mine I must analyze it and learn (I have not big experience in Lisp programming) THANK YOU!!

    Message 14 of 25
    pbejse
    in reply to: hgasty1001


    @hgasty1001 wrote:

    Hi,

     

    The shortest distance between 2 lines it's NOT the apparent intersection, just check this link:

     

    http://mathworld.wolfram.com/Line-LineDistance.html

     

    Very easy to program in plain Autolisp.

     

     

    Gaston Nunez


    Very informative, now how would you derive the location of the 2 points? any formula for that?

     

    Message 15 of 25
    Kent1Cooper
    in reply to: hgasty1001


    @hgasty1001 wrote:

     

    The shortest distance between 2 lines it's NOT the apparent intersection, just check this link:

    http://mathworld.wolfram.com/Line-LineDistance.html

    Very easy to program in plain Autolisp.

     

    Gaston Nunez


    And that's exactly what the OP was doing, to turn the Coordinate System so that it looks straight down in the direction of the shortest distance.  From that point of view, the apparent intersections at each of the two skewed Lines' Z positions are the endpoints of the shortest-distance Line.  It was a question of getting AutoCAD to find both of them without User input other than selecting the Lines.  Osnapping to the apparent intersection ought to be achievable if the skewed Lines are not encumbered by other entities near their ends, but it was the unlikelihood of that that got me going in a different direction.

    Kent Cooper, AIA
    Message 16 of 25
    Kent1Cooper
    in reply to: klosow


    @klosow wrote:

    To message 9:

    code

    (command "_.line" "appint" P1 P3 "appint" P3 P1 "")

    produces an error

     

    To message 10:

    Yes, this is what I wanted!!  As the idea of the algorithm is different than mine I must analyze it and learn (I have not big experience in Lisp programming) THANK YOU!!


    That line of code works for me, back here in Acad2004.  But that's with P1 and P3 being an endpoint of each Line, with nothing else around either one, so Osnap can't find an apparent intersection with just one pick.  That's part of the nature of APPINT Osnap -- if there are two things it can find an apparent [or actual] intersection of within aperture-box range, it doesn't ask for another pick.  Maybe that's what's happening for you, and that's why I went another way.

     

    The algorithm of it is to look at the situation straight along one of the Lines, rather than along the shortest-distance direction, find how far the other Line is from that, and establish a virtual Line parallel to the first one and intersecting the second -- one end of the shortest-distance Line is at that virtual intersection.  Have fun with it.

    Kent Cooper, AIA
    Message 17 of 25
    stevor
    in reply to: klosow

    One method, using dot products, with a 3D lsp solution: http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/
    S
    Message 18 of 25
    hgasty1001
    in reply to: klosow

    Hi,

     

    A non UCS solution to the problem to find  the shortest line between 2 skewed lines in plain Autolisp:

     

    (defun dotproduct(u v)
      (apply '+ (mapcar '* u v))
    )

     

    (defun getdirection(p1 p2)
      (mapcar '- p2 p1)
    )

    (defun plus(p1 p2)
      (mapcar '+ p1 p2)
    )

    (defun mult(s v)
      (mapcar '(lambda(x)(* s x)) v)

     

    (defun c:drawMinDistanceLine()
      (setq osmode (getvar "osmode"))
      (setvar "osmode" 0)
      (setq ent1 (entget (car(entsel))))
      (setq ent2 (entget (car(entsel))))
      (setq p10 (cdr (assoc 10 ent1)))
      (setq p11 (cdr (assoc 11 ent1)))
      (setq q10 (cdr (assoc 10 ent2)))
      (setq q11 (cdr (assoc 11 ent2)))
      (setq u (getdirection p10 p11))
      (setq v (getdirection q10 q11))
      (setq w (getdirection q10 p10))
      (setq a (dotproduct u u))
      (setq b (dotproduct u v))
      (setq c (dotproduct v v))
      (setq d (dotproduct u w))
      (setq e (dotproduct v w))
      (setq disc (- (* a c) (* b b))) ;check for disc=0 (parallel lines)
      (setq ss (- (* b e) (* c d)))
      (setq ss (/ ss disc))
      (setq tt (- (* a e)(* b d)))
      (setq tt (/ tt disc))
      (setq p1 (plus p10 (mult ss u)))
      (setq p2 (plus q10 (mult tt v)))
      (command "line" p1 p2 "")
      (setvar "osmode" osmode)
      (princ)
    )

    Message 19 of 25
    pbejse
    in reply to: Kent1Cooper


    @Kent1Cooper wrote:

    The algorithm of it is to look at the situation straight along one of the Lines, rather than along the shortest-distance direction, find how far the other Line is from that, and establish a virtual Line parallel to the first one and intersecting the second -- one end of the shortest-distance Line is at that virtual intersection.  Have fun with it.


    yeah.. tell me about... just for kicks i tried the equation.. and throw in (on what i think is a solution) an equation to compute

    x,y and z, which failed miserably... Smiley Sad

     

    (defun c:test (/ L1 L2 1data 2data 1A 1B 2A 2B s_t X1 X2 X3 X4 line_distance)
    (while (not (and
    	      (setq L1 (car (entsel "\nSelect a Line: "))
    		    L2 (car (entsel "\nSelect another Line: "))
    	      )
    	    )
           )
    )	    
      	(cond
    	  ((setq
    	     1data (entget L1)
    	     2data (entget L2)
    	     1A	   (cdr (assoc 10 1data)) ; start of first Line
    	     1B	   (cdr (assoc 11 1data)) ; end of first Line
    	     2A	   (cdr (assoc 10 2data)) ; start of second Line
    	     2B	   (cdr (assoc 11 2data)) ; end of second Line
    	     s_t   0
    	   )
    
    	   (repeat 3
    	     (setq x1 (nth s_t 1A)
    		   x2 (nth s_t 1B)
    		   x3 (nth s_t 2A)
    		   x4 (nth s_t 2B)
    	     )
    	     (setq vts
    		    (/ (* (abs (- x3 x1))
    			  (* (abs (- x2 x1)) (abs (- x4 x3)))
    		       )
    		       (* (abs (- x2 x1)) (abs (- x4 x3)))
    		    )
    	     )
    	     (set (setq vv (read (strcat "D" (itoa (+ s_t 1))))) vts)
    	     (setq s_t (1+ s_t))
    	   )
    	   (setq line-distance (sqrt (+ (* d1 d1) (* d2 d2) (* d3 d3))))
    	   (Princ
    	     (strcat "\Shortest Distance is " (rtos line-distance 2 4))
    	   )
    	   (princ)
    	  )
    	)
    
    )

     

    Math is killing me Smiley Happy

    Message 20 of 25
    pbejse
    in reply to: hgasty1001

    nice code gasty1001

     

    only thing is, it wont work if your on a different UCS other than world, but nevertheless a impressive piece of code writing

    at least you got it to work.. whilst I failed Smiley Sad

     

     

     

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

    Post to forums  

    Autodesk Design & Make Report

    ”Boost