Replace Polyine Geometry With Another Polylines Geometry - Lisp?

Replace Polyine Geometry With Another Polylines Geometry - Lisp?

ceethreedee.com
Collaborator Collaborator
5,288 Views
40 Replies
Message 1 of 41

Replace Polyine Geometry With Another Polylines Geometry - Lisp?

ceethreedee.com
Collaborator
Collaborator

I am using Civil 3D and quite often we use polylines as targets/boundaries etc. Can be quite annoying if you want to change them. 

 

I am curious if it would be possible via lisp to maintain the same object handle of a polyline and but replace all of its geometry with another selected polyline. Anyone got anything they have currently written that might do that?

Civil 3D 2025 / Infraworks 2025
Win 10 -DELL Precision Notebook 7680

Want FREE TOOLS! Come get my free productivity tools for civil 3d from the appstore here Ceethreedee tools
Or from my website below!
https://ceethreedee.com/ceethreedee-tools
Accepted solutions (1)
5,289 Views
40 Replies
Replies (40)
Message 2 of 41

marko_ribar
Advisor
Advisor

For LWPOLYLINES... Just watch, source and destination LWPOLYLINES will be finally overlapped - like source one was erased, but it's not - geometry data was transferred and handle preserved, so actually at destination poly place you'll have 2 polys as result...

 

(defun c:steallw2lwgeometry ( / lw1 lw2 prefdata suffdata )

  (prompt "\nPick LWPOLYLINE you want to change and keep handle on unlcoked layer...")
  (setq lw1 (ssget "_+.:E:S:L" '((0 . "LWPOLYLINE"))))
  (while (not lw1)
    (prompt "\nMissed... Pick LWPOLYLINE you want to change and keep handle on unlcoked layer again...")
    (setq lw1 (ssget "_+.:E:S:L" '((0 . "LWPOLYLINE"))))
  )
  (prompt "\nPick LWPOLYLINE you want to steal geometry data from...")
  (setq lw2 (ssget "_+.:E:S" '((0 . "LWPOLYLINE"))))
  (while (not lw2)
    (prompt "\nMissed... Pick LWPOLYLINE you want to steal geometry data from...")
    (setq lw2 (ssget "_+.:E:S" '((0 . "LWPOLYLINE"))))
  )
  (setq lw1 (ssname lw1 0) lw2 (ssname lw2 0))
  (setq prefdata (reverse (member (assoc 100 (reverse (entget lw1))) (reverse (entget lw1)))))
  (setq suffdata (cdr (member (assoc 100 (reverse (entget lw2))) (entget lw2))))
  (entupd (cdr (assoc -1 (entmod (append prefdata suffdata)))))
  (princ)
)

HTH., M.R.

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

Kent1Cooper
Consultant
Consultant

How involved is the "geometry" of the Polylines in question?  If they're geometrically rather simple Polylines, that is, without width(s) or arc segments, you should be able to simply impose the 'Coordinates VLA Property from one onto the other.  But I guess [without trying it] that could have trouble if they don't have the same number of vertices, and there may be other complications I haven't thought of....

Kent Cooper, AIA
0 Likes
Message 4 of 41

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:

....  If they're geometrically rather simple Polylines, that is, without width(s) or arc segments, you should be able to simply impose the 'Coordinates VLA Property from one onto the other.  But I guess [without trying it] that could have trouble if they don't have the same number of vertices....


I just tried it.  It doesn't mind different numbers of vertices [the target Polyline ends up with the same number as the source], but [as I expected] it transfers only vertex locations.  if any segments in the source Polyline are arcs, that doesn't come through into the target one, and if any of the target Polyline's segments are arcs, they remain so even if the corresponding segment of the source is a line, or if that segment in the source is also an arc, the one in the target retains its original bulge factor, rather than matching the one in the source.  And similarly, any widths remain per vertex in the re-positioned target Polyline, regardless of any [or lack thereof] in the source.

 

But if you're using only-line-segment Polylines without widths [in simplest terms]:

 

(setq
  source (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
  target (vlax-ename->vla-object (car (entsel "\nTarget Polyline: ")))
)
(vla-put-Coordinates target (vla-get-Coordinates source))

Kent Cooper, AIA
Message 5 of 41

Ranjit_Singh
Advisor
Advisor

Here is a very crude way of doing this. Get rid of the move part if position does not matter. No error checking and very lightly tested.

(defun c:somefunc  (/ pl1 pl2 bp)
 (setq pl2 (entget (car (entsel "\nSelect polyline to change: ")))
       pl1 (entget (car (entsel "\nSelect polyline to copy property: ")))
       bp  (cdr (assoc 10 pl2)))
 (entmod (append (reverse (member (assoc 5 pl2) (reverse pl2))) (member (assoc 100 pl1) pl1)))
 (command "._move" (entlast) "" (cdr (assoc 10 (entget (entlast)))) bp)
 (princ))
0 Likes
Message 6 of 41

john.uhden
Mentor
Mentor

You are mostly there.  After transferring the coordinates, one must transfer a list of bulges from the source.  Most subdivisions I have dealt with have plenty of right-of-way curves.  It's easy; just have to do one parameter at a time which programatically (sp?) might take a couple of milliseconds.

John F. Uhden

0 Likes
Message 7 of 41

ceethreedee.com
Collaborator
Collaborator

@marko_ribar thanks mate. Be good if this worked with 3d polylines as well? how easy would that be to change?

 

Im not too concerned about width etc.. but arcs would be nice..

 

Be also awesome if it gave you had an option to delete the object you steal the geometry from..

Civil 3D 2025 / Infraworks 2025
Win 10 -DELL Precision Notebook 7680

Want FREE TOOLS! Come get my free productivity tools for civil 3d from the appstore here Ceethreedee tools
Or from my website below!
https://ceethreedee.com/ceethreedee-tools
0 Likes
Message 8 of 41

Kent1Cooper
Consultant
Consultant

@ceethreedee.com wrote:

.... Be good if this worked with 3d polylines as well? .....

 

Be also awesome if it gave you had an option to delete the object you steal the geometry from..


The code in Post 4 works for 3D as well as both kinds of 2D Polylines, provided the source and target are of the same variety.

 

You can add this to delete the one you steal from:

 

(vla-delete source)

Kent Cooper, AIA
Message 9 of 41

ceethreedee.com
Collaborator
Collaborator
Accepted solution

Shame about the arcs. But Kent your solution was definitely the most elegant.

 

This is my finished lisp for anyone else that wants to use it. REPOLY (replace polyline)

 

It will also prompt you if you want to delete the source polyline afterwards.

 

Big thanks to @Kent1Cooper and everyone else that helped out.

 

Now i wonder if we could do the same with civil 3d featurelines and alignments! maybe that's for another post though..

 

(defun c:repoly ()
	(setq 	source (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
			target (vlax-ename->vla-object (car (entsel "\nTarget Polyline: ")))
	)
	(vla-put-Coordinates target (vla-get-Coordinates source))
	(initget "Y N  _Yes No")
	(setq dp (getkword "\nDo you want to delete the source polyline? (Yes/No): "))
	(if (= dp "Yes")
	  (progn
		(vla-delete source) ; delete source polyline
	  )
	)
)
Civil 3D 2025 / Infraworks 2025
Win 10 -DELL Precision Notebook 7680

Want FREE TOOLS! Come get my free productivity tools for civil 3d from the appstore here Ceethreedee tools
Or from my website below!
https://ceethreedee.com/ceethreedee-tools
0 Likes
Message 10 of 41

Kent1Cooper
Consultant
Consultant

@ceethreedee.com wrote:

.....

 

....
	(initget "Y N  _Yes No")
(setq dp (getkword "\nDo you want to delete the source polyline? (Yes/No): "))
(if (= dp "Yes")
  (progn
(vla-delete source) ; delete source polyline
  )
)
....

By the way, all you need for that is (initget) function is:

 

(initget "Yes No")

 

That will return "Yes" whether the User types Y or y or YES or yes or YeS or yEs or Ye or ....  Read more about (initget) & (getkword) in Help to understand why.

 

Also, the (progn) isn't doing anything for you -- that's only needed if more than one operation needs to be "wrapped" together to make them into a single 'then' or 'else' expression in an (if) function.

 

And you can do without that dp variable:

 

  (if (= (getkword "\nDo you want to delete the source polyline? [Yes/No]: ") "Yes")

    (vla-delete source) ; delete source polyline

  ); if

 

Note the square brackets around the options -- in newer versions, that will put them up where you can pick one on-screen as an option in addition to typing an answer.

 

There are some other things -- localize variables, verify valid selection before trying to work with something, etc. -- but enough for now.

Kent Cooper, AIA
0 Likes
Message 11 of 41

ceethreedee.com
Collaborator
Collaborator

Yeah i'm a horrible "copy/paste" coder. 😛

Civil 3D 2025 / Infraworks 2025
Win 10 -DELL Precision Notebook 7680

Want FREE TOOLS! Come get my free productivity tools for civil 3d from the appstore here Ceethreedee tools
Or from my website below!
https://ceethreedee.com/ceethreedee-tools
0 Likes
Message 12 of 41

ceethreedee.com
Collaborator
Collaborator
(defun c:repoly ()
	(setq 	source (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
			target (vlax-ename->vla-object (car (entsel "\nTarget Polyline: ")))
	)
	(vla-put-Coordinates target (vla-get-Coordinates source))
	(if (= (getkword "\nDo you want to delete the source polyline? [Yes/No]: ") "Yes")
    (vla-delete source) ; delete source polyline
	)
)

Clean version thanks to @Kent1Cooper

Civil 3D 2025 / Infraworks 2025
Win 10 -DELL Precision Notebook 7680

Want FREE TOOLS! Come get my free productivity tools for civil 3d from the appstore here Ceethreedee tools
Or from my website below!
https://ceethreedee.com/ceethreedee-tools
0 Likes
Message 13 of 41

Kent1Cooper
Consultant
Consultant

Pared down a little too far this time -- you left out the

 

(initget "Yes No")

 

which will be necessary for a User entry of, for example, just "y" to return the full word "Yes" that the (if) test is looking for.

Kent Cooper, AIA
0 Likes
Message 14 of 41

Anonymous
Not applicable

Have you find a Way tô do the same for 3dpolylines?

0 Likes
Message 15 of 41

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

Have you find a Way tô do the same for 3dpolylines?


Have you tried it?  See Messages 7 & 8.

 

But since there were some suggestions and edits and further correction not yet incorporated, here's a consolidated version:

(defun c:repoly (/ source target)
  (setq
    source (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
    target (vlax-ename->vla-object (car (entsel "\nTarget Polyline: ")))
  ); setq
  (vla-put-Coordinates target (vla-get-Coordinates source))
  (initget "Yes No")
  (if (= (getkword "\nDo you want to delete the source polyline? [Yes/No]: ") "Yes")
    (vla-delete source) ; then -- delete source polyline
  ); if
  (princ)
); defun
Kent Cooper, AIA
0 Likes
Message 16 of 41

john.uhden
Mentor
Mentor

Well done, Kent.

Being kinda old style, the only thing I would change is [Yes/<No>]:

Someone should mention that unlike 2D polylines, 3Ds don't have bulges, so you don't have to tend to them at all.

John F. Uhden

0 Likes
Message 17 of 41

damian_dymczyk
Contributor
Contributor

Hi guys, very helpful piece of code, almost entirely solve my issue with exchanging data between Autocad and Inventor. Almost because the geometry I work with is filled with bulges. Is there a way to preserve them while recreating the geometry? 

0 Likes
Message 18 of 41

Kent1Cooper
Consultant
Consultant

@damian_dymczyk wrote:

.... the geometry I work with is filled with bulges. Is there a way to preserve them while recreating the geometry? 


See Message 4 for some discussion of the complications.  Do you need the entity name and handle of the target/altered Polyline to remain the same?  If not, does COPY not do what you need, or just something like changing the Layer of the source Polyline?

Kent Cooper, AIA
0 Likes
Message 19 of 41

john.uhden
Mentor
Mentor

I like using the following technique...

;; Function to return LWpolyline data in the format...
;; '((b1 x1 y1)(b2 x2 y2) ... (bn xn yn))
(defun @Anonymous (E / plist blist)
  (setq ent (entget e))
  (setq plist (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 10)) ent)))
  (setq blist (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 42)) ent)))
  (setq plist (mapcar 'cons blist plist))
)
;; Then to apply that data to another LWpolyline...
;; where obj is a polyline vla-object
(defun @Anonymous_data (obj plist / param)
  (vlax-put obj 'Coordinates (apply 'append (mapcar 'cdr plist)))
  (setq param 0) ;; parameter index
  (repeat (length plist)
    (vla-setbulge obj param (car (nth param plist)))
    (setq param (1+ param))
  )
)

John F. Uhden

Message 20 of 41

damian_dymczyk
Contributor
Contributor
thanks for sharing! I have difficulties to set it up. I load it as a LISP but I cannot find command to execute it within autocad.
0 Likes