Modify 3D polyline

Modify 3D polyline

carlos_m_gil_p
Advocate Advocate
1,859 Views
18 Replies
Message 1 of 19

Modify 3D polyline

carlos_m_gil_p
Advocate
Advocate

Hello how are you.


I need help modify 3D polyline.
In the attachment it is what I want to achieve.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Accepted solutions (1)
1,860 Views
18 Replies
Replies (18)
Message 2 of 19

marko_ribar
Advisor
Advisor
Accepted solution

Based on your lisp...

 

;;; by Carlos Gil
;;; carlos.m.gil.p@gmail.com

;;;
;;; Funcion que renumera cantidad de vertices en una Polyline o Polyline 3d
;;;

(defun c:xxx (/ cgp-seleccion cgp-cant-vert)
  (vl-load-com)
  (cmd-entrar)
  (cmd-seleccion-polylineas)
  (princ)
)

;;;
;;; Funcion de entrada
;;;

(defun cmd-entrar (/)
  ;; Documento
  (setq cgp-adoc (vla-get-activedocument (vlax-get-acad-object)))
  (setq cgp-activelayspace (vla-get-block (vla-get-activelayout cgp-adoc)))
  ;;
)

;;;
;;; Seleccion de polilineas
;;;

(defun cmd-seleccion-polylineas   (/)
  ;; Seleccion
  (setq cgp-seleccion (entsel "\nEspecifique objeto: "))
  ;; Conversion de seleccion a objeto
  (if cgp-seleccion
    (setq cgp-objeto (vlax-ename->vla-object (car cgp-seleccion)))
  )
  ;; Especifico cantidad de vertices
  (while (< cgp-cant-vert 2)
    (setq cgp-cant-vert
        (getint
          (strcat "\nEspecifique cantidad de vertices < "
              (itoa (vlax-ldata-get
                "CANTIDAD-VERTICES"
                "cgp-cant-vert"
              )
              )
              " >: "
          )
        )
    )
    (if (= cgp-cant-vert nil)
      (progn (setq cgp-cant-vert
              (vlax-ldata-get
                "CANTIDAD-VERTICES"
                "cgp-cant-vert"
            )
          )
          (vlax-ldata-put
            "CANTIDAD-VERTICES"
            "cgp-cant-vert"
            cgp-cant-vert
          )
      )
    )
    (if   (< cgp-cant-vert 2)
      (princ
      "\nLa cantidad de vertices no puede ser menor de dos."
      )
    )
    (if   cgp-cant-vert
      (vlax-ldata-put
      "CANTIDAD-VERTICES"
      "cgp-cant-vert"
      cgp-cant-vert
      )
    )
  )
  ;; Distancia a dividir objeto
  (setq cgp-distancia (/ (ax-longtotal cgp-objeto) (1- cgp-cant-vert)))
  (while (< (length (ax-gradua cgp-objeto cgp-distancia)) cgp-cant-vert)
    (setq cgp-distancia (* 0.99 cgp-distancia))
  )
  ;; Tipo de objeto y funcion a ejecutar
  (cond 
      ((= (vla-get-objectname cgp-objeto) "AcDb2dPolyline")
      (cmd-addpolyline)
      )
      ((= (vla-get-objectname cgp-objeto) "AcDbPolyline")
      (cmd-addlightweightpolyline)
      )
      ((= (vla-get-objectname cgp-objeto) "AcDb3dPolyline")
      (cmd-add3dpoly)
      )
  )
  ;; Eliminar objeto antiguo
  (vla-delete cgp-objeto)
  ;; Regenera pantalla
  (vla-regen cgp-adoc acactiveviewport)
)

;;;
;;; Creacion de 2d polyline
;;;

(defun cmd-addpolyline (/)
  ;; Listado de vertices sobre objeto
  (setq cgp-lista-vert-inicial
      (vl-remove
        nil
        (ax-gradua cgp-objeto cgp-distancia)
      )
  )
  (setq cgp-tmp nil)
  (setq cgp-lista-vert-original
      (foreach x cgp-lista-vert-inicial
        (setq
          cgp-tmp (cons (trans x 1 0) cgp-tmp)
        )
      )
  )
  ;; Listado de vertices unidos
  (setq cgp-lista-vert nil)
  (foreach cgp-vert cgp-lista-vert-original
    (setq cgp-lista-vert (append cgp-vert cgp-lista-vert))
  )
  ;; Array de puntos
  (setq cgp-puntos
    (vlax-safearray-fill
      (vlax-make-safearray
        vlax-vbdouble
        (cons 0 (1- (length cgp-lista-vert)))
      )
      cgp-lista-vert
    )
  )
  ;; create a 3d polyline in model space
  (setq cgp-polyline-obj (vla-addpolyline cgp-activelayspace cgp-puntos))
  ;; Cambia elevacion para dejar la actual
  (vla-put-elevation
    cgp-polyline-obj
    (vla-get-elevation cgp-objeto)
  )
  ;;
)

;;;
;;; Creacion de lwpolyline
;;;

(defun cmd-addlightweightpolyline (/)
  ;; Listado de vertices sobre objeto
  (setq cgp-lista-vert-inicial
    (reverse
      (vl-remove
        nil
        (ax-gradua cgp-objeto cgp-distancia)
      )
    )
  )
  (setq cgp-tmp nil)
  (setq cgp-lista-vert-original
    (reverse
      (mapcar '3d->2d
         (foreach x cgp-lista-vert-inicial
           (setq cgp-tmp
             (cons (trans x 0 1) cgp-tmp)
           )
         )
      )
    )
  )
  ;; Listado de vertices unidos
  (setq cgp-lista-vert nil)
  (foreach cgp-vert cgp-lista-vert-original
    (setq cgp-lista-vert (append cgp-vert cgp-lista-vert))
  )
  ;; Array de puntos
  (setq cgp-puntos
    (vlax-safearray-fill
      (vlax-make-safearray
        vlax-vbdouble
        (cons 0 (1- (length cgp-lista-vert)))
      )
      cgp-lista-vert
    )
  )
  ;; Create a 3d polyline in model space
  (setq cgp-polyline-obj
    (vla-addlightweightpolyline
      cgp-activelayspace
      cgp-puntos
    )
  )
  ;; Cambia elevacion para dejar la actual
  (vla-put-elevation
    cgp-polyline-obj
    (vla-get-elevation cgp-objeto)
  )
  ;;
)

;;;
;;; Creacion de polyline 3d
;;;

(defun cmd-add3dpoly (/)
  ;; Listado de vertices sobre objeto
  (setq cgp-lista-vert-original
    (reverse
      (vl-remove
        nil
        (ax-gradua cgp-objeto cgp-distancia)
      )
    )
  )
  ;; Listado de vertices unidos
  (setq cgp-lista-vert nil)
  (foreach cgp-vert cgp-lista-vert-original
    (setq cgp-lista-vert (append cgp-vert cgp-lista-vert))
  )
  ;; Array de puntos
  (setq cgp-puntos
    (vlax-safearray-fill
      (vlax-make-safearray
        vlax-vbdouble
        (cons 0 (1- (length cgp-lista-vert)))
      )
      cgp-lista-vert
    )
  )
  ;; create a 3d polyline in model space
  (setq cgp-polyline-obj (vla-add3dpoly cgp-activelayspace cgp-puntos))
  ;;
)

;;;
;;; Listado 10.27. Función auxiliar 3d->2d
;;; Togores
;;;

(defun 3d->2d (punto) (list (car punto) (cadr punto)))

;;;
;;; Listado 15.14. Calcular puntos a distancias fijas
;;; Togores
;;; Mod by Carlos Gil
;;; Mod by M.R.
;;;

(defun ax-gradua (obj distancia / longitud tmp k r avance dist avdist)
  (setq longitud (ax-longtotal obj)
   tmp (list (vlax-curve-getstartpoint cgp-objeto))
  )
  (while (< (if (null k) (setq k 0) (setq k (1+ k))) (vlax-curve-getendparam cgp-objeto)) (setq r (cons k r)))
  (foreach segdist (mapcar '(lambda (par) (- (vlax-curve-getdistatparam cgp-objeto (1+ par)) (vlax-curve-getdistatparam cgp-objeto par))) (reverse r)) 
    (setq avance (/ segdist (fix (/ segdist distancia))))
    (if (null dist) (setq dist segdist) (setq dist (+ dist segdist)))
    (if (null avdist) (setq avdist 0.0))
    (while (< (+ avdist 1e-6) dist)
      (if (/= avdist 0.0)
        (setq tmp (cons (vlax-curve-getpointatdist obj avdist) tmp))
      )
      (setq avdist (+ avdist avance))
    )
  )
  (if (equal (nth 0 tmp) (vlax-curve-getendpoint cgp-objeto) 1e-6)
    (reverse tmp)
    (reverse (cons (vlax-curve-getendpoint cgp-objeto) tmp))
  )
)

;;;
;;; Listado 15.1. Determinación de la longitud total de una curva
;;; Togores
;;;

(defun ax-longtotal (objcurva)
  (vlax-curve-getdistatparam
    objcurva
    (vlax-curve-getendparam objcurva)
  )
)

HTH, M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 3 of 19

carlos_m_gil_p
Advocate
Advocate

Hello Brother.


Again thank you very much.

 

Stay perfect.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 4 of 19

carlos_m_gil_p
Advocate
Advocate

Hello Brother how are you.

 

I'm trying to apply the lisp that you modified.

But it does not work.

I'm trying to remunerate 26 vertices.

 

I enclose dwg and lisp, I am using.

 

Thank you.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 5 of 19

marko_ribar
Advisor
Advisor

Hi, check attachments... On some cases it won't work, so you have to find alternate solutions...

 

M.R.

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 6 of 19

carlos_m_gil_p
Advocate
Advocate

Hello Brother how are you.

 

There will be some solution to make direct and not piecemeal.

 

Thank you.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 7 of 19

Kent1Cooper
Consultant
Consultant

@marko_ribar wrote:

Hi, check attachments... On some cases it won't work, so you have to find alternate solutions...

.....


@carlos_m_gil_p, is the idea that if you say you want 26 vertices, you want the overall original Polyline divided up with added vertices, rounding the subdivision lengths to divide evenly into the lengths of existing segments, so that existing vertices remain where they are?  The latest example drawing from marko_ribar divided only the one longest segment, and left the others, ending up with 30 vertices overall.  If the overall original length should be subdivided into 25ths, then the left-most segment is long enough that it should have had a vertex added in the middle of it.  Am I understanding correctly?  [Sorry, I don't speak whatever language the code is written in -- Portuguese? Spanish?]

 

[I'm getting a divide-by-zero error when I try to use the latest XXX command in the latest drawing.]

 

Another question:  Would they ever be closed Polylines?  If so, should the User be asked how many segments they want, or how many vertices?  26 vertices in an open Polyline is 25 segments, but in a closed one, 26.

Kent Cooper, AIA
0 Likes
Message 8 of 19

carlos_m_gil_p
Advocate
Advocate

Hi How Are you.

Thanks also for your help.
I apologize for my English, this is a google translator. I only speak Spanish.

 

You have understood correctly what I want to achieve.

Deputy DWG the original and as it should be and it is as you say.

A vertex is added to the left side.

 

They will never be closed polylines. (Not closed)

 

Herewith the lisp file.
Removing the dictionary.
Indeed the lisp fails with the example sent.

 

Thank you.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 9 of 19

Kent1Cooper
Consultant
Consultant

@carlos_m_gil_p wrote:

.... 

You have understood correctly what I want to achieve.

.... 

Herewith the lisp file.
....
Indeed the lisp fails with the example sent.

.....


The divide-by-zero error is coming from this line:

 

  (setq avance (/ segdist (fix (/ segdist distancia))))

 

When it gets to a segment whose 'segdist' variable value is shorter than the 'distancia' variable, (/ segdist distancia) returns less than 1, and applying (fix) to that returns zero.  When used on a Polyline without any segments shorter than the eventual vertex spacing, it works, because that value is never zero.


If you REPLACE that with this:


  (setq avance (/ segdist (max (fix (/ segdist distancia)) 1)))

 

it will force the number to be at least 1, and it works for me in limited testing.  However, I think something needs to be adjusted about some calculation [maybe that one, maybe something else -- I didn't dig very deeply because of the language issue].  When I use that in your sample drawing, and ask for 26 vertices, the result has 28.  But at least it functions, and you can probably adjust it from there.

Kent Cooper, AIA
0 Likes
Message 10 of 19

carlos_m_gil_p
Advocate
Advocate

Hello brother, how are you, thank you very much for your help.

 

Modify the line that you indicated to me.
The result is 28 vertices in this example.
Deputy lisp again translated into English
If that helps you

 

You do not have to use my lisp specifically.
If you have another that meets the task, it would be very good

 

I have always divide such polylines and do it manually it becomes very complicated.

 

As you can help, I appreciate it.

 

Excuse my English. I hope you can understand.

 

Thank you.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 11 of 19

Kent1Cooper
Consultant
Consultant

@carlos_m_gil_p wrote:

.... 

Modify the line that you indicated to me.
The result is 28 vertices in this example....


I think that must be because of the segments in the original Polyline that are very short compared to the overall length.  It give the correct number of vertices for me on a Polyline that does not have such short segments, and it works without making that correction.  I have not explored it in great detail, and I am not acquainted with some of the functions it uses, but I think this is what it does:

1)  Finds the overall length of the Polyline.

 

2)  Divides that by the number of segments it will have with the requested number of vertices, to find the average length of a segment in the end result.

 

3)  Calculates how many of those fit into each initial segment, rounding to the nearest integer, to determine how many new segments that initial segment should be divided into in the end result.  [For any initial segments that are very short, it will be 1, meaning don't add any vertices within that segment.]

 

4)  Adds vertices within each segment that's long enough to need it, to get that many smaller segments within it.

 

What I think it needs to do before step 4) above is:

3A)  Add up the total number of new segments it calculated for each initial segment.  Those that are too short add 1 to this, even though they do not add vertices -- that is where I think the problem is.

 

3B)  If that total is more than the end result should have, reduce the number of segments somewhere, for the correct total.  The too-short segments mean that the average new segment length, within segments that do get subdivided, needs to be longer than the length calculated by dividing the overall length into the right number of segments.

 

In your example, it would obviously be the longest segment that should be divided into fewer segments than the original calculation for it.  But in some cases, it may be better to adjust the subdivision of more than one initial segment.  It may not be easy to find a way to do that, or to decide whether that should be done.

 

I think I will leave it to @marko_ribar to further alter his code, since he understands better than I do how it works.  It could be that the calculation that results in 0 for a short segment, which I suggested a correction to, needs to be kept with its zero result for purposes of adding up how many new segments each initial segment gets divided into, with a separate variable of some kind used in a different calculation to avoid the divide-by-zero error.

 

Or maybe all initial segments should be evaluated for length first, and only the lengths of those that are long enough to need new vertices within them should be included in the calculation of the overall length to be divided, and therefore of the average new segment length to divide them into.

Kent Cooper, AIA
0 Likes
Message 12 of 19

Kent1Cooper
Consultant
Consultant

I played around with this, and came up with the attached DivPLVerts.lsp with its DPV command, which takes a different approach to several aspects of the problem, and which [in limited testing]:

1)  results in the right total number of vertices whether or not there are initial segments short enough not to need vertices added within them;

2)  works on lightweight and heavy [both 2D & 3D] Polylines;

3)  works in any Coordinate System, and on Polylines drawn in any [same or other] Coordinate System;

4)  remembers your choice of how many vertices you want, and offers it as default on subsequent use;

5)  preserves Polyline width if present [though with some alteration if it has varying width];

6)  is quite a bit shorter.

 

Read the comments at the top of the file.  It does it by PEDITing the existing Polyline, adding vertices at calculated distances along the segments within it, rather than making another one.  So it doesn't need to concern itself with what function to use to make it, what space you're in, its elevation, or any of that stuff, and it remains on its Layer on with all its other properties intact.

 

[It will "work" on Polylines with arc segments, though that results in some peculiarities because of how PEDIT handles them.]

 

You may well run into some peculiar situation I didn't test, in which it doesn't get it right -- if so, let me know, and I'll try to figure out how to fix it.

Kent Cooper, AIA
0 Likes
Message 13 of 19

carlos_m_gil_p
Advocate
Advocate

Hello, how are you.

Thanks for the help.

It works well.

In case of an error, I will inform you.

Regards.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 14 of 19

carlos_m_gil_p
Advocate
Advocate

Hello Brother how are you.

 

Using routine today.
I found a new error.
When the polyline has curve is drawn wrong.

Please could you check.

 

Thank you and excuse my English, I only speak Spanish.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 15 of 19

Kent1Cooper
Consultant
Consultant

@carlos_m_gil_p wrote:

.... When the polyline has curve is drawn wrong. ....


Yes, that is what I was referring to in [the sentence in brackets] in Post 12.  Since the Subject of the thread is about 3D Polylines, which can't have arc segments, I only mentioned that in passing, but described the routine as working on 2D Polylines [lightweight or heavy], because the approach it takes does work on them, and just as expected when they are like 3D Polylines in having only line segments.

 

To get it to work on arc segments would require some different approach than PEDIT, because the problem is just a part of the way PEDIT adds vertices when arc segments are involved.  It may require constructing a new Polyline, rather than changing the selected one.  I will have to think about that....

Kent Cooper, AIA
0 Likes
Message 16 of 19

carlos_m_gil_p
Advocate
Advocate

Hello how are you.

 

Thanks for your answer.

 

I'll try seeing how I can solve it better.

 

Greetings.


AutoCAD 2026
Visual Studio Code 1.99.3
AutoCAD AutoLISP Extension 1.6.3
Windows 10 (64 bits)

0 Likes
Message 17 of 19

braudpat
Mentor
Mentor

 

Hello Kent

 

1) I like your DPV routine whick keeps XDATAs & ODs (Object Data of MAP/CIVIL) !

 

2) Could you confirm that the original vertex are maintained ?

 

3) Please is it possible to get a NEW version able to run on N PLines simultaneously ?

First the question about the number of vertex and THEN the selection ...

 

Thanks in advance, Regards, Patrice

 

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes
Message 18 of 19

Kent1Cooper
Consultant
Consultant

@braudpat wrote:

.... 

1) I like your DPV routine whick keeps XDATAs & ODs (Object Data of MAP/CIVIL) !

 

2) Could you confirm that the original vertex are maintained ?

 

3) Please is it possible to get a NEW version able to run on N PLines simultaneously ?

First the question about the number of vertex and THEN the selection ...

....


1)  That's an added benefit that I hadn't thought of, in addition to what I was thinking about [keeping Layer, linetype, color, width, etc.].

 

2)  Yes, since it uses PEDIT and only Inserts vertices in that, it doesn't do anything to the existing ones -- have you had it do otherwise?

 

3)  Attached is a version edited for multiple-Polyline selection.  I tested it rather lightly [just to confirm that it works on multiple objects, and adding the reporting of how many it left alone in place of the single reporting when one already has enough vertices], without trying it against all imaginable circumstances.  I left the file name and command name as they were, so if anyone has reason to want both varieties, they should change those for one of them.

Kent Cooper, AIA
0 Likes
Message 19 of 19

braudpat
Mentor
Mentor

 

Hello Kent

 

THANKS it works like a charm !

 

Thanks to your PEDIT solution which keeps XDATAs & ODs ...

 

Regards, Patrice

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


0 Likes