Interpolate vertex elevation on 3D polylines

Interpolate vertex elevation on 3D polylines

Dexterel
Collaborator Collaborator
8,828 Views
25 Replies
Message 1 of 26

Interpolate vertex elevation on 3D polylines

Dexterel
Collaborator
Collaborator

I have many 3d polylines that are missing elevation in some vertices.

3d poly.jpg

I need a lisp that checks the multiple 3d polylines and interpolate between vertices with elevation greater than -100.00, similar to flatten and constant grade as shown bellow:

flaten.jpg

The lisp should also check if the start and end points elevations are valid (more than -100.00) if not it should change them to the next good elevation on the 3D polyline.

 

The end result should look like this:

good.png

0 Likes
Accepted solutions (3)
8,829 Views
25 Replies
Replies (25)
Message 21 of 26

ВeekeeCZ
Consultant
Consultant

@ВeekeeCZ wrote:

Hi guys, yours routines come handy to me. Thanks for it. Unfortunately I found some issues on my sample.

 

@phanaem

 

Please see attached drawing. Would be possible to add the possibility to count with heights that lay on polyline but not at vertex? It's very common case to me. And second, if the height lays on polyline and at vertex, but in between of arc segments (probably), then it will cut the end of 3dpoly.

 

 

I would be grateful if that will work... it saves me a lot of time to dig into yours algorithms to adjust this... Thanks in advance.


@phanaem I hope you don't mind, I had to do that on my own... I listed the fixes and adjustments I did. Since I took the advantage of your work, I though I would share this for the others...

 

Spoiler
;interpolare polylinii 3D
;Stefan M. - 07.09.2016


; BeekeeCZ  - 2016.10.05
; Fix get_coords: Sometimes arced polylines does not make a last segment
; Fix get_coords: Curve vs. line decision at a vertex - following line is recognise as arc, then missed following vertex

; Add get_coords: Ignoring multiple vertices at the same place
; Add: If a height is on a polyline, but not at a vertex, it will create a vertex at this point
; Removed: Layer filter for texts.
; Commented out: assigning z coordinate to texts


(defun c:PFromHeights ( / *error* acdoc ssp sst i e l elev p z) (vl-load-com)
  (setq acdoc (vla-get-activedocument (vlax-get-acad-object)))
  
  (vla-startundomark acdoc)
  
  (defun *error* (msg)
    (and
      msg
      (not (wcmatch (strcase msg) "*EXIT*,*QUIT*,*CANCEL*,*BREAK*"))
      (princ (strcat "\nError: " msg))
      )
    (vla-endundomark acdoc)
    (princ)
    )
  
  (if
    (and
      (setq ssp (ssget ":L" '((0 . "LWPOLYLINE"))))
      (setq sst (ssget "_X" '((0 . "TEXT"))))
      )
    (progn
      (repeat (setq i (sslength sst))
	(setq e (entget (ssname sst (setq i (1- i))))
	      p (assoc (if (and (zerop (cdr (assoc 72 e))) (zerop (cdr (assoc 73 e)))) 10 11) e)
	      z (atof (cdr (assoc 1 e)))
	      l (cons (list (cdr p) z) l)
	      )
	;;;	(entmod
	;;;	  (mapcar
	;;;	    '(lambda (a)
	;;;	       (if
	;;;		 (member (car a) '(10 11))
	;;;		 (list (car a) (cadr a) (caddr a) z)
	;;;		 a
	;;;		 )
	;;;	       )
	;;;	    e
	;;;	    )
	;;;	  )
	)
      
      (repeat (setq i (sslength ssp))
	(setq en (ssname ssp (setq i (1- i))))
	(foreach x l
	  (if (and (setq pt (vlax-curve-getClosestPointTo en (car x)))
		   (equal 0.0 (distance pt (car x)) 5e-2)
		   (setq par (vlax-curve-getParamAtPoint en pt))
		   (not (equal par (atoi (rtos par 2 0)) 1e-2))
		   )
	    (:PLAddVertex en (car x)))))
      
      (repeat (setq i (sslength ssp))
	(setq e  (ssname ssp (setq i (1- i)))
	      p  (mapcar (function (lambda (a / d z)
				     (setq a (list (car a) (cadr a))
					   d (vlax-curve-getdistatpoint e (vlax-curve-getClosestPointTo e a))
					   z (vl-some (function (lambda (c)
								  (if (equal 0.0 (distance a (car c)) 1e-8)
								    (cadr c))))
						      l))
				     (list (car a) (cadr a) z d)))
			 (get_coords e))
	      p (interpolare p))
	(make_3d_poly p (assoc 8 (entget e)) (= 1 (logand 1 (cdr (assoc 70 (entget e)))))))
      )
    )
  (*error* nil)
  (princ)
  )

(defun interpolare (pct / d1 d2 p1 p2 p3 z1 z2)
  (if
    (and
      (setq p1 (vl-some '(lambda (a) (if (caddr a) a)) pct))
      (setq p2 (vl-some '(lambda (a) (if (caddr a) a)) (cdr (member p1 pct))))
      )
    (mapcar
      '(lambda (p / z1 z2 d1 d2 p3)
	 (setq z1 (caddr p1)
               d1 (cadddr p1)
	       z2 (caddr p2)
               d2 (cadddr p2)
	       )
	 (if
	   (caddr p)
	   (progn
	     (cond
	       ((< (cadddr p) d2)
		(setq p1 p)
		)
	       ((= (cadddr p) d2)
		(if
		  (setq p3 (vl-some '(lambda (a) (if (caddr a) a)) (cdr (member p2 pct))))
		  (setq p1 p p2 p3)
		  )
		)
	       )
	     (list (car p) (cadr p) (caddr p))
	     )
	   (list (car p)
                 (cadr p)
                 (/ (+ (* z2 (- (cadddr p) d1)) (* z1 (- d2 (cadddr p))))
                    (- d2 d1)))
	   )
	 )
      pct
      )
    (mapcar '(lambda (a) (list (car a) (cadr a) (if z1 (caddr z1) 0.0))) pct)
    )
  )

(defun make_3d_poly (lst la c)
  (entmakex
    (list
      '(0 . "POLYLINE")
      (cons 8 (strcat (cdr la) "-3d"))
      '(100 . "AcDbEntity")
      '(100 . "AcDb3dPolyline")
      '(62 . 1)
      (cons 70 (if c 9 8))
      )
    )
  (foreach x lst
    (entmakex
      (list
	'(0 . "VERTEX")
	'(100 . "AcDbEntity")
	'(100 . "AcDbVertex")
	'(100 . "AcDb3dPolylineVertex")
	(cons 10 x)
	'(70 . 32)
	)
      )
    )
  (entmakex '((0 . "SEQEND")))
  )

;;;(defun get_coords (e / l a b)
;;;  (setq a (vlax-curve-getstartparam e)
;;;        b (vlax-curve-getendparam e)
;;;        )
;;;  (while (<= a b)
;;;    (setq l (cons (vlax-curve-getpointatparam e a) l))
;;;    (if
;;;      (equal '(0 0 0) (vlax-curve-getsecondderiv e a) 1e-8)
;;;      (setq a (1+ a))
;;;      (setq a (+ 0.2 a))
;;;      )
;;;    )
;;;  (reverse (if (equal (car l) (last l) 1e-8) (cdr l) l))
;;;  )

(defun get_coords (e / l a b p)
  (setq a (vlax-curve-getstartparam e)
	b (vlax-curve-getendparam e)
	)
  (while (<= (fix (* 10 a)) (fix (* 10 b)))
    
    (if (and (setq p (vlax-curve-getpointatparam e (min a b)))
             (not (equal p (car l) 1e-2)))
      (setq l (cons p l)))
    (if (equal '(0 0 0) (vlax-curve-getsecondderiv e (min (+ 0.1 a) b)) 1e-8)
      (setq a (1+ a))
      (setq a (+ 0.2 a))
      )
    )
  (reverse (if (equal (car l) (last l) 1e-8) (cdr l) l))
  )


;; From Lee Mac's code
(defun :PLAddVertex (e p / tan LM:LWVertices a b e h l n r w x z)

  (defun tan ( x ) (if (not (equal 0.0 (cos x) 1e-10)) (/ (sin x) (cos x))))

(defun LM:LWVertices ( e )
  (if (setq e (member (assoc 10 e) e))
    (cons (list (assoc 10 e)
		(assoc 40 e)
		(assoc 41 e)
		(assoc 42 e))
	  (LM:LWVertices (cdr e)))))


  
  (if (and p
	   e
	   (setq p (vlax-curve-getclosestpointto e (trans p 1 0))
		 n (vlax-curve-getparamatpoint e p))
	   )
    (if (not (equal n (fix n) 1e-8))
      (progn
	(setq e (entget e)
	      h (reverse (member (assoc 39 e) (reverse e)))
	      l (LM:LWVertices e)
	      z (assoc 210 e)
	      )
	(repeat (fix n)
	  (setq a (cons (car l) a)
		l (cdr l)))
	(setq x (car l)
	      r (- n (fix n))
	      w (cdr (assoc 40 x))
	      w (+ w (* r (- (cdr (assoc 41 x)) w)))
	      b (atan (cdr (assoc 42 x)))
	      )
	(entmod
	  (append h
		  (apply 'append (reverse a))
		  (list
		    (assoc 10 x)
		    (assoc 40 x)
		    (cons  41 w)
		    (cons  42 (tan (* r b)))
		    )
		  (list
		    (cons  10 (trans p 0 (cdr z)))
		    (cons  40 w)
		    (assoc 41 x)
		    (cons  42 (tan (* (- 1.0 r) b)))
		    )
		  (apply 'append (cdr l))
		  (list z))))))
  )

 

 

 

 

 

0 Likes
Message 22 of 26

john.uhden
Mentor
Mentor
I take it you wish to find points on the 3DPoly where even contours cross. Too bad there is no function (vlax-curve-getpointatelevation). But I feel pretty sure you could write one.

Find the two adjacent vertices (by parameter) where one Z is greater and one Z is less and interpolate between them by algebra to find the distance along the segment. Then (vlax-curve-getpointatdist).

John F. Uhden

0 Likes
Message 23 of 26

ВeekeeCZ
Consultant
Consultant

@john.uhden wrote:
I take it you wish to ...

No John, no more wishes. The lisp I've posted in the spoiler is just what I need and what I adjusted to my needs posted a message before.

If I be the OP, I would mark that as the solution. 

0 Likes
Message 24 of 26

hosneyalaa
Advisor
Advisor

Hello @phanaem 

A question please

If I have the  closed  POLYLINE and the height is not on the first VERTEX 
As shown in the picture and drawing
Is it possible to modify the code for that?

 

ice_screenshot_٢٠٢٠٠٨٢٧-٠٨٢٦٠٠.jpeg

 

 

 

;interpolare polylinii 3D
;Stefan M. - 05.09.2016
(defun c:test ( / *error* acdoc ssp sst i e l elev p z) (vl-load-com)
  (setq acdoc (vla-get-activedocument (vlax-get-acad-object)))

  (vla-startundomark acdoc)

  (defun *error* (msg)
    (and
      msg
      (not (wcmatch (strcase msg) "*EXIT*,*QUIT*,*CANCEL*,*BREAK*"))
      (princ (strcat "\nError: " msg)) 
    )
    (vla-endundomark acdoc)
    (princ)
    )
    
  (if
    (and
      (setq ssp (ssget ":L" '((0 . "LWPOLYLINE"))))
      (setq sst (ssget "_X" '((0 . "TEXT") (8 . "BT_puho_hoogte"))))
      )
    (progn
      (repeat (setq i (sslength sst))
        (setq e (entget (ssname sst (setq i (1- i))))
              p (assoc (if (and (zerop (cdr (assoc 72 e))) (zerop (cdr (assoc 73 e)))) 10 11) e)
              z (atof (cdr (assoc 1 e)))
              l (cons (list (cdr p) z) l)
        )
        (entmod
          (mapcar
            '(lambda (a)
               (if
                 (member (car a) '(10 11))
                 (list (car a) (cadr a) (caddr a) z)
                 a
               )
             )
            e
          )
        )
      )
      (repeat (setq i (sslength ssp))
        (setq e  (ssname ssp (setq i (1- i)))
              elev (cdr (assoc 38 (entget e)))
              p  (mapcar
                  '(lambda (a / b d z)
                     (setq b (trans (list (car a) (cadr a) elev) e 0)
                           d (vlax-curve-getdistatpoint e b)
                           z (vl-some
                               '(lambda (c)
                                  (if
                                    (equal 0.0 (distance a (car c)) 1e-8)
                                    (cadr c)
                                  )
                                )
                                l
                              )
                     )
                     (list (car b) (cadr b) z d)
                   )
                   (mapcar 'cdr (vl-remove-if '(lambda (a) (/= (car a) 10)) (entget e)))
                 )
              p (interpolare p)
        )
        (make_3d_poly p (assoc 8 (entget e)))
        )
      )
    )
  (*error* nil)
  (princ)
  )

(defun interpolare (pct / d1 d2 p1 p2 p3 z1 z2)
  (if
    (and
      (setq p1 (vl-some '(lambda (a) (if (caddr a) a)) pct))
      (setq p2 (vl-some '(lambda (a) (if (caddr a) a)) (cdr (member p1 pct))))
      )
    (mapcar
        '(lambda (p / z1 z2 d1 d2 p3)
           (setq z1 (caddr p1) d1 (cadddr p1)
                 z2 (caddr p2) d2 (cadddr p2)
           )
           (if
             (caddr p)
             (progn
               (cond
                 ((< (cadddr p) d2)
                  (setq p1 p)
                  )
                 ((= (cadddr p) d2)
                  (if
                    (setq p3 (vl-some '(lambda (a) (if (caddr a) a)) (cdr (member p2 pct))))
                    (setq p1 p p2 p3)
                    )
                  )
                 )
               (list (car p) (cadr p) (caddr p))
               )
             (list (car p) (cadr p) (/ (+ (* z2 (- (cadddr p) d1)) (* z1 (- d2 (cadddr p)))) (- d2 d1)))
             )
           )
        pct
        )
    (mapcar '(lambda (a) (list (car a) (cadr a) (if z1 (caddr z1) 0.0))) pct)
  )
)

(defun make_3d_poly (lst la)
  (entmakex
    (list
      '(0 . "POLYLINE")
      la
      '(100 . "AcDbEntity")
      '(100 . "AcDb3dPolyline")
      '(70 . 8)
     )
  )
  (foreach x lst
    (entmakex
      (list
        '(0 . "VERTEX")
        '(100 . "AcDbEntity")
        '(100 . "AcDbVertex")
        '(100 . "AcDb3dPolylineVertex")
        (cons 10 x)
        '(70 . 32)
      )
    )
  )
  (entmakex '((0 . "SEQEND")))
)

drawing attachment

 

thank you In advance

 

 

0 Likes
Message 25 of 26

phanaem
Collaborator
Collaborator

@hosneyalaa

Hi. To me, it doesn't look the same task as in the original post in this thread.

I suggest to start a new thread, describe your task, eventually put a link to this thread as a partial solution.

Also, beside the polyline example, would be nice to have the solution for that case. I mean, what is expected, a new 3dPoly on top of the old pline? The text with the interpolated Z values? Both?

 

 

 

 

 

 

 

Message 26 of 26

hosneyalaa
Advisor
Advisor

@phanaem  

thank you 

0 Likes