June 21, 2026

Add Vertices to 2D Polylines

An AutoLisp utility for preserving LWPOLYLINE geometry while inserting new vertices.

At a Glance

Motivation Utility to insert vertices on Polyline segments.
Software AutoCAD and its Verticals
Supports: Line & Arc segments, Self-intersecting Polylines, and uniform width segments.

Do you frequently need to add vertices to existing 2D polylines? Then what follows may help you perform this task more reliably.

While casually browsing Forums, I came across a post asking for code to do exactly this. The responses in the post didn't quite convince me. So, I decided to have a go at it.

A doubtful starter, there were questions in my mind - Do people really need it? Which people need it? How frequently do they need it?
And my journey began with finding answers to these questions.
 

Finding the ‘Raison d'être’ For the Application:

Why this Application was Needed

To find answers to my questions, I decided to do a quick internet search. Results weren't discouraging. 

The search revealed that AutoCAD users across multiple domains frequently perform the task of adding vertices to plines.

People insert additional nodes (vertices) into an AutoCAD polyline segment for several practical reasons:

  • Match surveyed coordinates, design constraints, or construction details.
  • Provide more grip points, making it easier to stretch, move, or align specific portions of the polyline.
  • Civil engineering, GIS, CNC machining, and other applications sometimes require vertices at specific locations for calculations, staking, machine paths, or data exchange.
  • Roads, property boundaries, utility lines, contours, and similar features often need multiple vertices to capture changes in direction or geometry.
  • Additional vertices create exact points that can be used as object snaps (OSNAP) when drawing or positioning other objects.
Click to display details of survey

Domain

Tasks

Typical Vertices per Polyline

Typical Segment Length

Civil Engineering & Surveying
  • Road alignments
  • Parcel/property boundaries
  • Topographic contours
  • Drainage and utility networks
20–500+ 5–50 m
4–100 1–200 m
GIS
  • Mapping roads, rivers, administrative boundaries, and pipelines.
  • Accurate geographic features often require many inserted vertices.
20–1000+ 5–50 m
Architecture
  • Building footprints
  • Site plans
  • Landscape layouts
4–50 0.5–20 m
Mechanical Drafting Custom profiles, sheet-metal outlines, and tool paths. 10–200 1–100 mm
Electrical and Utility Design
  • Cable routes
  • Power distribution layouts
  • Telecom networks
10–300 2–50 m

An observation that caught my eye: For AutoCAD usage patterns, civil engineering, surveying, and GIS users typically insert vertices into polylines more frequently than other domains because they need to model irregular real-world geometry accurately.

Preparing the ground – Revisiting the basics:

Background and Fundamentals

Before divulging into the scope, I needed to refresh / relearn a couple of basic concepts about LWPOLYLINE (called pline for in the remainder of the article).

A Polyline (Lightweight Polyline) is a single, planar AutoCAD graphic entity defined by a sequence of 2D coordinates.

The LWPOLYLINE entity / object in a drawing can be created by using any of the following methods:
  • Native AutoCAD commands like pline / pedit
  • Data generated by a Custom program
  • Imported data (like .dxf)
I would, intuitively look at a pline basically as an 'assembly' of 'segments'.
- The properties Elevation, Endpoint and Global width are defined at assembly level. These are delegated to the segments. (Width is an exception. It can be overridden at segment level.)
- The properties Start point, Bulge (internal representation of included angle of the arc segment) & per segment width are defined at the segment (node) level.

A segment does not have end point. Start point of connected next segment is the implied end point of current segment.

With this, I was ready to begin.
 

Begin with end in mind – The Scope:

Application Scope

A programming / coding activity, like many others, needs to follow the second habit dictated by Covey.

Based on the problem described in the forum post, the basic scenario (scope of the Application) I envisioned was that the User needs to add vertices on every segment based on some criteria - add vertices only if the length of that particular segment is larger than a predefined length.

I, thus, began with writing down a couple of lines as scope:

Scope: The proposed Application ('AddVertices') will insert vertices on a segment of an existing pline at fixed or equal intervals as specified by the User.

As the things stand, it was not even 20% of the final scope. After multiple iterations of code testing /rewriting / retesting, the final version of the scope evolved.

Here is that final version of scope that I would have configured had I known everything about AutoCAD & plines and AutoLISP at the beginning:

The Final Scope: The proposed code ('AddVertices') will insert vertices on a segment of an existing pline at fixed or equal intervals as specified by the User.

It will insert vertices using one of the following two rules:
  1. Insert vertices at fixed distance. The length of the last new segment may be different and at the end of the current segment.
  2. Insert vertices at equal distances along a segment.
Original And Modified Plines retain original geometry perfectly.

It will:

  1. Work with arc segments. (I was very particular about this because most of the pline processing codes skip arcs and self- intersecting plines for obvious reasons)
    Many utilities that insert vertices into polylines simplify the problem by avoiding difficult cases. This application was designed to address those cases rather than bypass them.
    These situations occur regularly in production drawings, but many utilities either ignore them or handle them only partially because they significantly increase implementation complexity
    Supports arc segments
    , allowing curved polylines to be processed without converting them into straight-line approximations.
    Preserves uniform-width representation, avoiding unexpected changes to polyline width behavior.
  2. Retain the original status of drawing (except new vertices) and create no new anomaly in the drawing.
  3. Ensures polyline dependent activities continue to works with modified pline exactly as they were working with original pline. - hatch / region / Offset / area / break / explode
  4. Maintain integrity (status / values of properties as displayed in the 'Properties Pallet') of original pline with no side effects after inserting vertices:
    These properties are
    length, area, 'Closed' state, elevation, start and end vertex, arcs stability (radius and center), only uniform widths, pline direction (cw / ccw), node sequence, layer, original width representation.The modified pline retains original status across all sgments.
Click to display Explainer: Maintaining Status

I will explain why maintaining status is important with a very interesting example. We will do an interactive exercise so you don't need any proof.
In any open drawing, create a trivial pline. Open 
the Properties palette. 
You will see a value of 0.0000 in the Global width box as well as Start width and End width at all nodes. (Decimal places controlled by 'luprec')
If you change the value of Global width to any other positive value, same uniform value is assigned to all places mentioned above.
This is a consistent behavior as long as you enter positive values in the Global width box.
Let use call this as Global width behavior
In this behavior the Global width box displays non-negative value and same value is applied as start and end width of every node.

Things get a little tricky from now on-wards.
At any node change the start value to a different value.
You will immediately notice that the Global width value box becomes blank. 
And we will call this as Per segment width behavior

The important point to note is that the presence or absence of value in the Global width box indicates the current width behavior of the pline - Global or Per Segment..

This causes a little inconvenience while writing code. Many times Programmers may overlook this. The code may end up changing the width behavior.

The 'AddVertices' application takes care of this and maintains the behavior exactly as it was - retaining the original value in the Global width box.

Note: I have seen some codes inadvertently changing the start point / direction of the pline - especially when it involves reversing the pline. 

More importantly, here is what the Application will not do:

  • Replace the original pline with a new one, but will strictly modify it.
  • Create temporary geometry which needs to be deleted subsequently.
  • Do any quality checks or repair 'faults' in the pline. (It will strictly follow the principle 'Garbage In, Garbage Out').

Note: This and not creating a new polyline (or any object) are interrelated concepts. Shifting the first node or replacing existing polyline with a new polyline breaks the original data of the polyline. This may break any existing Application that may be referring to the first node or the entity name / handle of the original polyline.

Walking the Talk – How Application Works:

These are the basic steps (algorithm) the Application internally follows:

  1. Collect from the pline.
  2. Generate data for each segment by processing the pline data (including segment length).
  3. Generate new vertices by dividing segment lengths by distance.
  4. Calculate modified bulges (representation of included angle of arc) if it's an arc.
  5. Collect all node related data sequentially and apply that to original pline to modify it.

Note: The code is unaffected by current status of drawing - the system variables.
Also, it does not require that pline must be visible on the screen.

Trial By Fire - The Choke Test:

Testing and Validation

I designed a 'Choke' test (crash test) for testing the Application.

The express purpose of the test was to verify that the Application behaves consistently irrespective of the amount of data to process - It does not 'choke' up and cause frustration and feeling of uncertainty to the User. The input parameters used for the test were - Insertion interval 10 with 0.1 as tolerance and equal length segments (which I believe is that bit tougher than fixed distance method.)

I also created a test case drawing specifically for this test. (It is included as .dxf file in the download.)

Click to display contents of test drawing

Domain

Tasks

Typical Vertices per Polyline

Typical Segment Length

Civil Engineering & Surveying
  • Road alignments
  • Parcel/property boundaries
  • Topographic contours
  • Drainage and utility networks
20–500+ 5–50 m
4–100 1–200 m
GIS
  • Mapping roads, rivers, administrative boundaries, and pipelines.
  • Accurate geographic features often require many inserted vertices.
20–1000+ 5–50 m
Architecture
  • Building footprints
  • Site plans
  • Landscape layouts
4–50 0.5–20 m
Mechanical Drafting Custom profiles, sheet-metal outlines, and tool paths. 10–200 1–100 mm
Electrical and Utility Design
  • Cable routes
  • Power distribution layouts
  • Telecom networks
10–300 2–50 m
The table (Contents of test drawing) lists the plines included in the drawing:

The 'Choke Test' repeatedly processes the drawing in each cycle and modifies the original plines.

Click to display summary of modifications
    Before Modification After Modification Additions
Length   2386.0249 2386.0249 0.0
Segments Line segments 28 62 34
Arc segments 20 197 177
Total 48 259 211
Nodes   45 255 210

The table 'Modification Summary' below, displays consolidates geometric parameters before and after modification by Application in each cycle of the 'Choke Test'.

And here are the results of Choke test

Choke Test Results

No. of cycles

Time (in MilliSeconds)

No. of Cycles Total Per Cycle
1  < 0.0000  < 0.0000
100 516.0000 5.1600
1000 5162.0000 5.1620
5000  25165.0000 5.0330
10000 50590.0000 5.0590
30000 148947.0000 4.9649

The absolute values may differ due to various factors like hardware configurations and working environment (multiple applications running simultaneously. The focus here is on consistency of time taken per cycle.

Also, to just give you in idea, when the test drawing is processed for 30000 cycles, it deals with (255 * 30000 = 7, 650, 000 nodes - yes more than 7 million nodes) in 148947 milliseconds (150 seconds / 2.5 minutes)

Evaluation:

During the evolution process of the Application, I submitted the Application for evaluation 4 times to ChatGPT. Here are some of the selected comments posted by ChatGPT:

I would classify the code as production-quality AutoLISP, not merely a working utility.
This is **strong production-quality AutoLISP code** with good geometric reasoning. It goes well beyond typical hobby scripts and shows real CAD automation experience.
For a utility intended for **native AutoCAD LWPOLYLINEs**, the code you've shown demonstrates a strong understanding of both AutoLISP and polyline geometry. The arc-center/radius verification is probably the strongest piece of evidence you've presented that the geometric side is implemented correctly.
Those (Choke Test) results significantly strengthen the case that the implementation is mature from a geometric and algorithmic perspective.
The evidence you've provided suggests the implementation is doing exactly what it claims to do, and doing it efficiently. The fact that the per-cycle timing stays flat out to 10,000 iterations is probably the strongest rebuttal to concerns about the list-building strategy.

This affair with ChatGPT was an unusual cocktail of satisfaction, revelations, elation, disappointments, anger, frustration & disgust. But that's another story. (As way say in Hindi, 'Woh kissa fir kabhee'.)

Using the Application:

You can download and extract the contents of the attached .zip file. The 'AddVerices.vlx file is the application file. Note: The other files included are the sample test drawing 'AddVertecisChokeTest.dxf' & a sample calling function 'CallAdvertices.lsp'.

This Application is primarily designed as core function that will be called from a wrapper calling function to process multiple plines in the drawing. A typical way to call this Application is to use (SanKul_addVertices <entity name of pline> distance tolerance ifFixedDistance) at command prompt or from the calling function.

The arguments:

  1. entity name of the pline to process.
  2. The interval (spacing) at which to insert vertices
  3. Spacing Tolerance
  4. True / Nil flag to indicating the use of fixed / equal interval

The Application will return any one of the values in the AutoLISP list format '(pline handle . “Status message.)'

Here is an example of typical feedback: (plineHandle . "Skipped: insertSpacing not numeric OR not +ve")

A User without coding knowledge can use it for processing a single pline using following steps:

  1. Using 'appload' command load the vlx file.
  2. At command prompt, type (SanKul_addVertices (car (entsel)) distance tolerance ifFixedDistance)
  3. If you miss selecting the pline, Application will immediately respond to you with (plineHandle . "Skipped: not a pline."). You can repeat the step until you get the result.
  4. When successful, the feedback message will appear at the command prompt - (plineHandle . "Done: x node(s) inserted")

If you want to process multiple plines using complex selection (all plines in the drawing, plines only on specific layer etc.), you will need to write a calling wrapper function that typically creates a selection set. It then calls the vlx file in a loop to process each pline in the selection set.

I have attached a sample calling function (using AutoLISP) that explains this in more detail.

Roadmap For the Future:

Now that the basic infrastructure is well established, it is possible add few variations if strongly needed:

Use .dxf file as direct input. This will work without any installation of AutoCAD.
Batch processing multiple drawings
Adding vertices only to specific segment(s) of a pline.
Inserting vertices at specific locations on or near a pline.
In fixed distance, locate the unequal segment at the start / end or middle of the segment.
But this can complicate things - what exactly is middle when no of segments are even. (In case of 4 segments, which position is middle position - second or third?
Inserting vertices at irregular interval.
Insert vertices at fixed (not calculated) equal length ignoring segment boundaries.
Insert vertices so that each segment is converted into equal no. of segments.
Generate a virtual selection Window / Crossing for selection from a pline that contains arcs.
Break or Divide plines at uniform / randomly specified intervals / vertices.

 

Final Thoughts:

Feedback

As the cliche' goes, 'The real test - I mean taste - of pudding is in eating'.

So, I request you to test this Application and give honest feedback - especially where this Application does not work as expected (bugs). Your suggestions for improvement or addition of features are most welcome.

Note: I have not tested but I this Application will work without hitch with other softwares like BricsCAD / ZWCAD. So, feedback by users of these softwares is most welcome.

Suggestions, bug reports and enhancement requests are welcome. Real-world testing feedback helps improve the application and future releases.