Jump to content

How to iterate points over a pline


broncos15

Recommended Posts

I had a quick question on how to iterate over a pline's entire distance. What I mean is that I want to set pt1 as the beginning of the line. Then I want to iterate and want to set pt1 again as pt1 + a small incremental distance like 0.01 and do this until the end of the pline. For example

 (setq pt1 (+ pt1 0.01))

. I also want to do this on another pline that is parallel to the first. How do I:

1)Set pt1 as the end point of pline1

2)Set pt2 as the end point of pline2, but it has to be on the same "side" as pt1 (ie pt1 and pt2 both should start on the left side and work right).

Link to comment
Share on other sites

The easiest route is to use the vlax-curve-* functions, specifically vlax-curve-getpointatdist.
Thanks Lee! So if I understand correctly I would do something like this:
(defun c:test ()
 (setq ss1 (LM:ssget "\nSelect 1st Polyline: " '("_+.:E:S" ((0 . "POLYLINE")))))
 (setq ss2 (LM:ssget "\nSelect 2nd Polyline: " '("_+.:E:S" ((0 . "POLYLINE")))))
 (if (and ss1 ss2)
   (progn
     (setq ent1 (vlax-ename->vla-object (ssname ss 0))
    ent2 (vlax-ename->vla-object (ssname ss 0))
    delta 0
    maxdist 0
          pt1 (vlax-curve-getPointAtDist ent1 delta)
    pt2 (vlax-curve-getPointAtDist ent2 delta))
     (Repeat (vla-get-Length ss1)
(setq maxdist1 (vlax-curve-getdistatpoint pt1 pt2))
(setq delta (+ delta 0.01))
(setq pt1 (vlax-curve-getPointAtDist ent1 delta)
      pt2 (vlax-curve-getPointAtDist ent2 delta))
(if (< maxdist maxdist1)
  (setq maxdist maxdist1)
  ))
     )
   )
 (if (> maxdist 0)
   (strcat "The maximum distance between the entities is:\n\n"
 (rtos maxdist 2 2)
    )
   )
   
 )

My issue is that I can't seem to get this working correctly. Am I misunderstanding how to use the vlax-curve functions?

Link to comment
Share on other sites

Look at these no need for ssget as you only have 2 plines, fix for repeat

 

use

(setq obj (vlax-ename->vla-object (car (entsel "\nPick pline"))))
(setq Pt (vlax-curve-getPointAtDist Obj dist))

(Repeat (fix (/ (vla-get-Length obj) 0.01))

this wont work (setq maxdist1 (vlax-curve-getdistatpoint pt1 pt2))

this is checking for a point at 90 degrees which may be more accurate than your method

(setq Pt (vlax-curve-getPointAtDist Obj Chain))
(setq fd (vlax-curve-getFirstDeriv obj (vlax-curve-getparamAtPoint obj pt)))
(setq angR (- (angle '(0 0 0) fd) (* pi 0.5)))
(setq pt2 (polar pt angr 1.0))
(command "line" pt pt2 "")
(setq obj3 (vlax-ename->vla-object (car (entlast))))
(setq pt3 (vlax-invoke obj3 'intersectWith obj2 acExtendThisEntity))
setq Pt (vlax-curve-getPointAtDist Obj Chain))
(setq fd (vlax-curve-getFirstDeriv obj (vlax-curve-getparamAtPoint obj pt)))
(setq angR (- (angle '(0 0 0) fd) (* pi 0.5)))
(setq pt2 (polar pt angr 1.0))
(command "line" pt pt2 "")
(setq obj3 (vlax-ename->vla-object (car (entlast))))
(setq pt3 (vlax-invoke obj3 'intersectWith obj2 acExtendThisEntity))
(vla-put-endpoint obj3 pt3)

Link to comment
Share on other sites

Thanks Lee! So if I understand correctly I would do something like this...

You're welcome - here is some feedback on your code:

 

(defun c:test ()

Remember to declare your local variables - see my tutorial if unsure.

 

 (setq ss1 (LM:ssget "\nSelect 1st Polyline: " '("_+.:E:S" ((0 . "POLYLINE")))))
 (setq ss2 (LM:ssget "\nSelect 2nd Polyline: " '("_+.:E:S" ((0 . "POLYLINE")))))
 (if (and ss1 ss2)

 

I would suggest enclosing the two setq expressions within the and expression: currently the user will be prompted twice even if the user fails to select an object at the first prompt; whereas, since and is a Special Form, the arguments will be evaluated synchronously with the AND logic, resulting in the second expresssion only being evaluated following a valid response to the first.

 

Also note that you are filtering for 3D Polylines or 2D [Heavy] Polylines, not the standard lightweight polyline (LWPOLYLINE) as created by the PLINE command.

 

   (progn
     (setq ent1 (vlax-ename->vla-object (ssname ss 0))
    ent2 (vlax-ename->vla-object (ssname ss 0))
    delta 0
    maxdist 0
          pt1 (vlax-curve-getPointAtDist ent1 delta)
    pt2 (vlax-curve-getPointAtDist ent2 delta))

 

This is syntactically correct, though be careful if one of the polylines is reversed.

 

(Repeat (vla-get-Length ss1)

 

ss1 is a selection set and doesn't have an ActiveX Length property (a geometric property); you may be getting confused with sslength which returns the number of items in a selection set.

 

However, repeat requires an integer argument for the number of times the enclosed expressions should be repeated, so a length would need to be fix'd if proceeding in this way.

 

If I've understood what you are looking to achieve, I would instead recommend something along the lines of:

(setq len (vlax-curve-getdistatparam ent1 (vlax-curve-getendparam ent1))
     dis 0.0
)
(while (<= dis len)
   ...
   (setq dis (+ dis 0.01))
)

 

(setq maxdist1 (vlax-curve-getdistatpoint pt1 pt2))

 

Please read the documentation on the vlax-curve-getdistatpoint function - this function returns the length along a given entity from the start point to the given point, not the distance between two points (that would be the distance function).

Link to comment
Share on other sites

Lee and BigAl thank you both so much for the help and additional information, it is super useful to me and a good way for me to improve my coding.

Remember to declare your local variables - see my tutorial if unsure.[/Quote] I usually don't make them local until the end of coding so that I can see the values of them while I am debugging. How do you typically code it in the beginning because I would love suggestions to improve my debugging abilities? That tutorial is awesome by the way!
you are filtering for 3D Polylines or 2D [Heavy] Polylines, not the standard lightweight polyline (LWPOLYLINE) as created by the PLINE command.[/Quote] Yeah I know, I am trying to find the vertical distance between the two lines. Thank you so much for the additional vlax-curve function and Repeat function explanation that was super useful and it definitely gave me a better understanding of those functions. I got my code up and running, however it errors out whenever I have two polylines that are perpendicular, but not the same length, which is what I am assuming BigAl is pointing out. However, I am having a difficult time understanding how to incorporate his ideas into the code. My code is as follows:
(defun c:maxheight (/ *error*)
 (defun *error* (msg)
   (if (not
  (member msg '("Function cancelled" "quit / exit abort"))
)
     (princ (strcat "\nError: " msg))
   )
   (princ)
 )
 (if (and (setq ss1
   (LM:ssget "\nSelect 1st 3D Polyline/Feature Line: "
      '("_+.:E:S" ((0 . "POLYLINE,AECC_FEATURE_LINE")))
   )
   )
   (setq ss2
   (LM:ssget "\nSelect 2nd 3D Polyline/Feature Line: "
      '("_+.:E:S" ((0 . "POLYLINE,AECC_FEATURE_LINE")))
   )
   )
     )
   (maxheight:mainprogram)
 )
 (if (> maxdist 0)
   (progn
     (command "line" pt3 pt4 "")
     (princ
(strcat "\nThe maximum distance between the entities is: "
 (rtos maxdist 2 2)
)
     )
   )
 )
 (princ)
)
(defun maxheight:mainprogram ()
     (setq ent1    (vlax-ename->vla-object (ssname ss1 0))
    ent2    (vlax-ename->vla-object (ssname ss2 0))
    len     (vlax-curve-getdistatparam
       ent1
       (vlax-curve-getendparam ent1)
     )
    dis     0.0
    delta   0.0
    maxdist 0.0
    pt1     (vlax-curve-getPointAtDist ent1 delta)
    pt2     (vlax-curve-getPointAtDist ent2 delta)
     )
     (While (<= dis len)
(setq z1 (caddr pt1)
      z2 (caddr pt2))
(setq maxdist1 (abs (- z1 z2)))
(setq delta (+ delta 0.01))
(setq pt1 (vlax-curve-getPointAtDist ent1 delta)
      pt2 (vlax-curve-getPointAtDist ent2 delta)
)
(if (< maxdist maxdist1)
  (setq maxdist maxdist1
 pt3 pt1
 pt4 pt2
  )
)
(setq dis (+ dis 0.01))
     )
   )

Link to comment
Share on other sites

So I have thought about this some more and I think what I need to do to get rid of this error and ensure that it is always 90 degrees is that I always make the shorter entity's end point be point 1 with something like this:

(if (<= (vlax-curve-getdistatparam
  ent1
  (vlax-curve-getendparam ent1)
)
(vlax-curve-getdistatparam
  ent2
  (vlax-curve-getendparam ent2)
)
   )
 (setq pt1 (vlax-curve-getPointAtDist ent1 delta))
 (setq pt1 (vlax-curve-getPointAtDist ent2 delta))
)

What I am having difficulties with is making point 2 be at the perpendicular point to point 1. Is there anyway to do this without drawing lines each time? I feel like drawing lines will really bog down the code. I have tried doing it with something like this, but it doesn't work

(if (<= (vlax-curve-getdistatparam
      ent1
      (vlax-curve-getendparam ent1)
    )
    (vlax-curve-getdistatparam
      ent2
      (vlax-curve-getendparam ent2)
    )
)
     (progn
(setq pt1 (vlax-curve-getPointAtDist ent1 delta))
(setq pt2 (osnap (cadr (ssname ss1 0) "per")))
)
     (progn
(setq pt1 (vlax-curve-getPointAtDist ent2 delta))
(setq pt2 (osnap (cadr (ssname ss2 0) "per")))
)
   )

Edited by broncos15
Link to comment
Share on other sites

A couple of suggestions just check that intersectwith returns a value you have 4 options like extend or not use 0 1 2 3, if not keep going till it gets to end ie x + 0.01.

 

Intersectwith requires 2 objects, Inters uses 4 points but more complicated to calculate the 4 points required.

 

(if (= nil (setq pt3 (vlax-invoke obj3 'intersectWith obj2 acExtendThisEntity))) ; dont extend
(progn
.......
)

Edited by BIGAL
Link to comment
Share on other sites

I usually don't make them local until the end of coding so that I can see the values of them while I am debugging. How do you typically code it in the beginning because I would love suggestions to improve my debugging abilities?

 

I would advise against this for the reasons that I give in my tutorial: if local variables are not declared as such, this would give a misrepresentation of the program behaviour and therefore hinder the debugging process, as any setq or set expressions which reference the variable they are defining would compound existing data assigned to the variable on a previous evaluation of the expression. Also, consider functions which use a 'return' variable which remains undefined unless a condition is met (hence returning nil for some cases) - the entire behaviour of such a function would be altered if the scope of such variable extends beyond the function.

 

For checking values held by variables, I would instead suggest including simple princ/prin1 expressions interspersed within the code to test the variable values as various points. Alternatively, you can use the Watch Window in the VLIDE, with appropriate break points set in order to test the value held by a symbol at the break point.

 

That tutorial is awesome by the way!

 

Thanks!

Link to comment
Share on other sites

A couple of suggestions just check that intersectwith returns a value you have 4 options like extend or not use 0 1 2 3, if not keep going till it gets to end ie x + 0.01.

 

Intersectwith requires 2 objects, Inters uses 4 points but more complicated to calculate the 4 points required.

 

(if (= nil (setq pt3 (vlax-invoke obj3 'intersectWith obj2 acExtendThisEntity))) ; dont extend
(progn
.......
)

Thanks BigAl for the suggestion, but I'm still kind of confused. I thought intersectwith only works if the two objects actually intersect, not if they are parallel? And how does that give the perpendicular point?
Link to comment
Share on other sites

I would advise against this for the reasons that I give in my tutorial: if local variables are not declared as such, this would give a misrepresentation of the program behaviour and therefore hinder the debugging process, as any setq or set expressions which reference the variable they are defining would compound existing data assigned to the variable on a previous evaluation of the expression. Also, consider functions which use a 'return' variable which remains undefined unless a condition is met (hence returning nil for some cases) - the entire behaviour of such a function would be altered if the scope of such variable extends beyond the function.

 

For checking values held by variables, I would instead suggest including simple princ/prin1 expressions interspersed within the code to test the variable values as various points. Alternatively, you can use the Watch Window in the VLIDE, with appropriate break points set in order to test the value held by a symbol at the break point.

That makes sense now, I hand't thought about the times where loops are based on nil expressions. I will definitely be incorporating this style when I write code in the future. Thanks again!
Link to comment
Share on other sites

1st like lee (princ "wow1")(princ "wow 2") in code see wow 1, no wow 2 good place to start looking. Vlide use debug, last break source.

 

2nd the firstderiv is used to get the 90 degrees angle from object so draw a false line at this direction.

(setq fd (vlax-curve-getFirstDeriv obj (vlax-curve-getparamAtPoint obj pt)))
(setq angR (- (angle '(0 0 0) fd) (* pi 0.5)))

Link to comment
Share on other sites

Hi, maybe post an example dwg 2 polylines showing which part is maximum distance (2D or 3D?)

Let's try any method: command or code etc.. learning from debugging

Link to comment
Share on other sites

So this is where my code is at now. You can see that I just use the vlax-curve-getClosestPointto for pt2. However, this doesn't actually always give the perpendicular point because it takes into the account the distance including the z value.

(defun c:maxheight (/ *error* maxdist ss1 ss2 pt3 pt4)
 (defun *error* (msg)
   (if (not
  (member msg '("Function cancelled" "quit / exit abort"))
)
     (princ (strcat "\nError: " msg))
   )
   (princ)
 )
 (if (and (setq ss1
   (LM:ssget "\nSelect 1st 3D Polyline/Feature Line: "
      '("_+.:E:S" ((0 . "POLYLINE,AECC_FEATURE_LINE")))
   )
   )
   (setq ss2
   (LM:ssget "\nSelect 2nd 3D Polyline/Feature Line: "
      '("_+.:E:S" ((0 . "POLYLINE,AECC_FEATURE_LINE")))
   )
   )
     )
   (progn
     (maxheight:mainprogram)
     (maxheight:ans)
     )
 )
 (princ)
)
;;;This is the answer portion of the code
(defun maxheight:ans ()
 (initget "Yes No")
 (setq *maxheightans*
 (cond
   (
    (getkword
      (strcat "\nDraw a line at max height location [Yes/No] <"
       (setq *maxheightans*
       (cond (*maxheightans*)
      ("Yes")
       )
       )
       ">: "
      )
    )
   )
   (*maxheightans*)
 )
 )
 (if (= *maxheightans* "Yes")
   (progn
     (command "._line" pt3 pt4 "")
     (command "._zoom" "_W" pt3 pt4)
   )
 )
 (alert
(strcat
  "\nThe maximum vertical distance between the entities is: "
  (rtos maxdist 2 2)
)
     )
 (princ
(strcat
  "\nThe maximum vertical distance between the entities is: "
  (rtos maxdist 2 2)
)
     )
)
;;;Main code portion
(defun maxheight:mainprogram (/ ent1 ent2 len delta pt1 pt2 z1 z2 maxdist1)
 (setq ent1 (vlax-ename->vla-object (ssname ss1 0))
ent2 (vlax-ename->vla-object (ssname ss2 0))
delta 0.0
maxdist 0.0
 )
 (if (<= (vlax-curve-getdistatparam
    ent1
    (vlax-curve-getendparam ent1)
  )
  (vlax-curve-getdistatparam
    ent2
    (vlax-curve-getendparam ent2)
  )
     )
   (setq len (vlax-curve-getdistatparam
 ent1
 (vlax-curve-getendparam ent1)
      )
   )
   (setq len (vlax-curve-getdistatparam
 ent2
 (vlax-curve-getendparam ent2)
      )
   )
 )
 (While (<= delta len)
   (if (<= (vlax-curve-getdistatparam
      ent1
      (vlax-curve-getendparam ent1)
    )
    (vlax-curve-getdistatparam
      ent2
      (vlax-curve-getendparam ent2)
    )
)
     (progn
(setq pt1 (vlax-curve-getPointAtDist ent1 delta))
(setq pt2 (vlax-curve-getClosestPointto ent2 pt1))
)
     (progn
(setq pt1 (vlax-curve-getPointAtDist ent2 delta))
(setq pt2 (vlax-curve-getClosestPointto ent1 pt1))
)
   )
   (setq z1 (caddr pt1)
  z2 (caddr pt2)
   )
   (setq maxdist1 (abs (- z1 z2)))
   (if (< maxdist maxdist1)
     (setq maxdist maxdist1
    pt3     pt1
    pt4     pt2
     )
   )
   (setq delta (+ delta 0.01))
 )
)

Example.JPG

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...