Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

sweep multple polylines at once. Code does not work *yet*

53 REPLIES 53
Reply
Message 1 of 54
l.l.oldescholtenhuis
6129 Views, 53 Replies

sweep multple polylines at once. Code does not work *yet*

Hi There,

 

I'm using AutoCAD Civil 3D to model inner city utility construction projects. For my research project, I need to include water and storm pipes, but also various sorts of cables. Currently, I'm manually creating cables profiles using plines from existing 2D drawings and the sweep function.. a very cumbersome taks. 

 

I was wondering whether there is a way to speed this process up. At the moment, I draw a circle, copy it myriads of times, and sweep each along the dozens of plines (one by one). I cannot select multiple lines and sweep them all, can I?

 

I posed a this question: "Can anybody tell me whether I can select mutiple plines to sweep all at once?" and was directed at the following code in the civil3D forum.

 

(defun c:sweepm ()
(princ "\PSelect objects to sweep: ")
(setq pick1 (ssget))
(princ "\nSelect sweep paths: ")
(setq ss (ssget '((0 . "LINE,*POLYLINE,3dpoly"))))
(setq NumPath (sslength ss) Count 0)
(repeat NumPath
(setq Ename (ssname ss Count))
(command "sweep" pick1 "" Ename)
(repeat NumPath
(setq Count (+ 1 count))
)
(princ)
)

 

 

I tried to implement it via VLISP. However, although the selection features allow me to select multiple objects and plines, autocad eventually only sweeps one line. Does anybody know why?

 

53 REPLIES 53
Message 2 of 54


@l.l.oldescholtenhuis wrote:

.... "Can anybody tell me whether I can select mutiple plines to sweep all at once?" and was directed at the following code in the civil3D forum.

 

(defun c:sweepm ()
(princ "\PSelect objects to sweep: ")
(setq pick1 (ssget))
(princ "\nSelect sweep paths: ")
(setq ss (ssget '((0 . "LINE,*POLYLINE,3dpoly"))))
(setq NumPath (sslength ss) Count 0)
(repeat NumPath
(setq Ename (ssname ss Count))
(command "sweep" pick1 "" Ename)
(repeat NumPath
(setq Count (+ 1 count))
)
(princ)
)

 

I tried to implement it via VLISP. However, although the selection features allow me to select multiple objects and plines, autocad eventually only sweeps one line. Does anybody know why?


I think you have a duplicate line there.  I don't have Civil3D, but just looking at the code, I would suggest you try removing the line that I made red above.

Kent Cooper, AIA
Message 3 of 54

Thanks for you reaction. I tried the revised code in the normal AutoCAD, but it doesn't work. 

Do you have any other suggestions?

Message 4 of 54

l.l.oldescholtenhuis,
a quick one, select first a circle, then select all the paths you want to apply the sweep command...
Later I'll try a different approach.
Try it, is minimally tested...

 

(defun c:test (/ cir cir1 hnd itm num ss ss1)
  (prompt "\nSelect object to sweep: ")
  (if (setq ss1 (ssget "_:S:E:L" '((0 . "CIRCLE"))))
    (progn
      (prompt "\nSelect sweep paths: ")
      (if (setq ss (ssget '((0 . "LINE,*POLYLINE,3dpoly"))))
	(progn
	  (setq cir (ssname ss1 0))
	  (setq	itm 0
		num (sslength ss)
	  )
	  (while (< itm num)
	    (setq hnd (ssname ss itm))
	    (vl-cmdf "_copy" cir "" "0,0,0" "0,0,0")
	    (setq cir1 (entlast))
	    (command "sweep" cir1 "" hnd)
	    (setq itm (1+ itm))
	  );; while
	);; progn
      );; if
    );; progn
  );; if
  (princ)
);; test

 hope that helps
Henrique

EESignature

Message 5 of 54

l.l.oldescholtenhuis,
A different approach,first have to enter the tube diameter, if any was used previously, is stored in a variable, if the same, just press enter, then select all the paths you want to apply the sweep command...
Minimally tested...

 

(defun c:test (/ cir diam1 hnd itm num ss)
  (if (= diam nil)
    (setq diam 0.25);; change the 0.25 to the diameter you use most
  );; if
  (setq
    diam1 (getreal
	    (strcat "\Enter the tube diameter < " (rtos diam 2 4) " >: ")
	  )
  )
  (if (= diam1 nil)
    (setq diam1 diam)
    (setq diam diam1)
  );; if
  (prompt "\nSelect the sweep paths: ")
  (if (setq ss (ssget '((0 . "LINE,*POLYLINE,3dpoly"))))
    (progn
      (setq itm	0
	    num	(sslength ss)
      )
      (while (< itm num)
	(setq hnd (ssname ss itm))
	(entmakex (list	(cons 0 "Circle")
			(cons 10 '(0.0 0.0 0.0))
			(cons 40 (/ diam 2))
		  )
	)
	(setq cir (entlast))
	(command "sweep" cir "" hnd)
	(setq itm (1+ itm))
      );; while
    );; progn
  );; if
  (princ)
);; test

hope that helps
Henrique

EESignature

Message 6 of 54


@l.l.oldescholtenhuis wrote:

Thanks for you reaction. I tried the revised code in the normal AutoCAD, but it doesn't work. 

Do you have any other suggestions?


Try it in Civil3D.  Normal AutoCAD doesn't have the Sweep command [at least mine doesn't -- maybe it's in some newer versions].

 

It looks from your original posted code as though Sweep works like Extrude with the Path option, bypassing the need to give it the Path option because that's assumed.  If that's the case, I think it would be pretty easy to make something that would do that with multiple paths.  As I'm picturing it, you wouldn't even need to draw the Circles, but only tell it the diameter you want to use [the same for all of them in a single running of the command].

Kent Cooper, AIA
Message 7 of 54
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:
....It looks from your original posted code as though Sweep works like Extrude with the Path option, bypassing the need to give it the Path option because that's assumed.  If that's the case, I think it would be pretty easy to make something that would do that with multiple paths.  ....

Such as this:

(defun C:TUBE (/ ss ent)
  (initget (if *tubedia 6 7)); no 0, no negative, no Enter on first use
  (setq *tubedia
    (cond
      ((getdist
          (strcat
            "\nDiameter of Tubular Cross-Section(s)"
            (if *tubedia (strcat " <" (rtos *tubedia) ">") ""); offer default only on subsequent use
            ": "
          ); strcat
        ); getdist
      ); User-gives-distance condition
      (*tubedia); Enter for default on subsequent use
    ); cond
  ); setq
  (prompt "\nTo make tubular extrusions along paths,")
  (setq ss (ssget '((0 . "*POLYLINE,LINE,ARC,CIRCLE,ELLIPSE,SPLINE"))))
  (repeat (sslength ss)
    (setq ent (ssname ss 0) edata (entget ent))
    (command
      "_.ucs" "_ZA"
        (vlax-curve-getStartPoint ent)
        (mapcar '+
          (getvar 'lastpoint)
          (vlax-curve-getFirstDeriv ent (vlax-curve-getStartParam ent))
        ); mapcar & UCS
      "_.circle" "0,0" (/ *tubedia 2)
      "_.ucs" "_previous"
      "_.extrude" (entlast) "" "_path" ent
    ); command
    (ssdel (ssname ss 0) ss)
  ); repeat
); defun

It does not yet have the usual controls [error handling, object-snap control, command-echo suppression, etc.], nor some less-than-usual controls [e.g. checking whether a Polyline is self-intersecting and can't be used as an Extrude path], but see whether it does what you want, and all that can be added.  Also think about whether it should put the tubes on the same Layers as the path objects [this puts them on the current Layer], whether you would prefer hollow tubes if they're pipes [would ask for both outside and inside diameters], etc.

 

EDIT:  Presumably, if Sweep is like Extrude but assumes a path, this line:

 

"_.extrude" (entlast) "" "_path" ent

 

should be replaceable with this:

 

"_.sweep" (entlast) "" ent

Kent Cooper, AIA
Message 8 of 54

Hi Guys,

 

Thanks a lot. The code provided by Henrique seems to solve my problem. We only need the extra features to complete the code, right?

 

Kent, also thanks a lot for your advice. Just to answer your question: my Audocad (2013) has a sweep command.

Another remark on Kents proposed solution: as I get many drawings containing 2D-lines from drafters and engineers, I need to find a function to convert them in 3D. So I'm not sure whether your solution will work for me. 

 

My next step would be to automatically detect the layer, move the lines on that layer to a specified z-coordinate, and create 3D-pipes/cables out of these.

 

Best,

Léon 

Message 9 of 54

"Thanks a lot. The code provided by Henrique seems to solve my problem".

 

You're welcome, Léon
Wich code, the first or the second?

 

"We only need the extra features to complete the code, right?"

 

Which extra features you have to explain a little more...
And I think [not sure] that the sweep command, was introduced in AutoCAD at the 2007 version.

 

Henrique

EESignature

Message 10 of 54

This really helps us forward! Thanks again! To clarify:

 

Your second code worked well. I was confused while writing 'extra features.' I mean the following: I actually need a function that now moves all the 'sweeped lines' to a new z-coordinate.

 

A little background: ideally, I would like to be able to let AutoCAD identify various layers based on their name (e.g. Electricity, Water, Gas, etc). Subsequently, I want Autocad to move the various layer to predefined z-coordinates. Then, we can apply the sweep-multiple to create 3D-solids. For example: identify water layer, move all plines in water layer to z-coordinate -3, sweep plines. Repeat process for gas (z-coordinate -2,5) etc. 

 

Best,

Léon 

 

 

Message 11 of 54

Ok, understood.
I'm in the middle of a project, later, I'll see what I can do...
One more question, all lines always have the same z, it is possible to have different z's

Henrique

EESignature

Message 12 of 54

Hi Henrique, 

 

I don't expect you do to that, but of course it would be great! I'll just check out the forum later. Have to do some stuff as well 🙂

 

Lines on all drawings have the same z-coordinate (x,y,0). Currently, practitioners are not using any 3D-features at all. 

 

 

Best

Léon

Message 13 of 54

Léon,
the following code is just a demo, and aims to demonstrate a possible way to achieve what you need...
At the beginning of the code, there are two lists, the first "layrl" contains the layer names, and the second "elevl" contains the respective elevations, you need to fill those lists with your layer names [in uppercase], and the elevations, remember that to the first element from "layrl" will correspond the first element from "layrl"  to the second, the other second, and so on...

 

(vl-load-com)
(defun c:test (/ cir diam1 elev elevl ent filter hnd itm lay layrl num ss);; ensure that the number of elements on both lists are equal...
  (setq	layrl '("WATER" "GAS");; list with the layer names
	elevl '(-3.0 -2.5);; list with the elevation
  );; setq
  (if (= (length layrl) (length elevl));; tests if the number of elements in both lists is equal
    (progn
      (if (= diam nil)
	(setq diam 0.25);; change the 0.25 to the diameter you use most
      );; if
      (setq
	diam1
	 (getreal
	   (strcat "\Enter the tube diameter < " (rtos diam 2 4) " >: ")
	 )
      )
      (if (= diam1 nil)
	(setq diam1 diam)
	(setq diam diam1)
      );; if
      (setq filter "")
      (foreach x layrl
	(setq filter (strcat filter (vl-princ-to-string x) ","))
      );; foreach
      (setq filter (vl-string-right-trim "," filter))
      (prompt "\nSelect the sweep paths: ")
      (if (setq	ss
		 (ssget
		   (list '(0 . "LINE,*POLYLINE,3dpoly") (cons 8 (strcat filter)))
		 )
	  )
	(progn
	  (setq	itm 0
		num (sslength ss)
	  )
	  (while (< itm num)
	    (setq hnd  (ssname ss itm)
		  ent  (entget hnd)
		  lay  (strcase (cdr (assoc 8 ent)))
		  elev (nth (vl-position lay layrl) elevl)
	    )
	    (setvar "clayer" lay)
	    (entmakex (list (cons 0 "Circle")
			    (cons 10 '(0.0 0.0 0.0))
			    (cons 40 (/ diam 2))
		      )
	    )
	    (setq cir (entlast))
	    (command "sweep" cir "" hnd)
	    (vl-cmdf "._move" "_L" "" "0,0,0" (strcat "0,0," (rtos (+ elev (/ diam 2)) 2 2)))
	    (setq itm (1+ itm))
	  );; while
	);; progn
      );; if
    );; progn  
    (prompt "\nLists don't have same elements number!!!")
  );; if
  (princ)
);; test

EDIT: add "strcase"  

hope that helps
Henrique

EESignature

Message 14 of 54

Hi Henrique,

It looks great! Thanks a lot. Unfortunately, I cannot try it out this week anymore. I will get back to you next Monday!
Have a great weekend!

Best,
L?on
Universiteit Twente |Faculty of Engineering Technology
Dept. of Construction Management and Engineering
e: l.l.oldescholtenhuis@utwente.nl
t: +31(0)53 489 6857
m: +31(0)6 234 340 67
Message 15 of 54


@l.l.oldescholtenhuis wrote:

....

Another remark on Kents proposed solution: as I get many drawings containing 2D-lines from drafters and engineers, I need to find a function to convert them in 3D. So I'm not sure whether your solution will work for me. 

....


As far as I know, all Lines in AutoCAD are already 3D, that is, there's no difference between a Line that lies with its ends at the same Z-coordinate value and one with its ends at different Z-coordinate values, except the different numbers in those (assoc 10) and (assoc 11) entity-data entries.  I'm not aware of any need for conversion, nor what a conversion would do.  If you just mean moving them to different elevations, or moving an end to a different elevation, the routine won't care.  They're not like Polylines, for which there is a distinct entity type for the 3D variety.  The routine I posted works on all of those entity types listed in the (ssget) filter, 2D or 3D, except that I find it doesn't like 3D Splines, so if they are possible, you could omit Spline from the filter, or any Splines could be checked for being planar before having tubes built on them.

Kent Cooper, AIA
Message 16 of 54

You're welcome, Léon
Have a great weekend too!

Henrique

EESignature

Message 17 of 54
Kent1Cooper
in reply to: hmsilva


@hmsilva wrote:

.... 

....
(foreach x layrl (setq filter (strcat filter (vl-princ-to-string x) ",")) );; foreach (setq filter (vl-string-right-trim "," filter)) ....
(ssget (list '(0 . "LINE,*POLYLINE,3dpoly") (cons 8 (strcat filter))) ....

....


Just for your information, you don't need to remove the comma from the end of the Layer-names list -- it will work with the comma at the end.

 

But I'm also thinking that if the list of Layers is hard-coded into the routine at the beginning, then it may as well be hard-coded into the (ssget) filter, too.  You could eliminate that (foreach) that strings the Layer names together [as well as the expendable end-comma-removal], and just do this:

....

  (ssget
    '((0 . "LINE,*POLYLINE,3dpoly") (8 . "WATER,GAS"))

....

 

Of course, you wouldn't want to do that if you built it as a function with the Layer-name list as an argument that might be different every time you run it.

 

EDIT:  Also, it looks like the routine does the Sweeping and then moves the result to the desired elevation.  I think the sequence should be different, if I'm interpreting Messages 8 and 10 correctly -- the Line/Polyline should be moved to the desired elevation first, then Sweep should be applied.

 

[EDIT 2:  fixed the dotted-pair with the 8]

Kent Cooper, AIA
Message 18 of 54
hmsilva
in reply to: Kent1Cooper

Just for your information, you don't need to remove the comma from the end of the Layer-names list -- it will work with the comma at the end.

 


Kent,
thanks for that information, I thought it would give an error...

 

As to the filter list, I created it this way to avoid too much intervention from the OP, just filling out the two initial lists ...

 

Thank you very much!
Cheers
Henrique

EESignature

Message 19 of 54


@l.l.oldescholtenhuis wrote:

.... I would like to be able to let AutoCAD identify various layers based on their name (e.g. Electricity, Water, Gas, etc). Subsequently, I want Autocad to move the various layer to predefined z-coordinates. Then, we can apply the sweep-multiple to create 3D-solids. For example: identify water layer, move all plines in water layer to z-coordinate -3, sweep plines. Repeat process for gas (z-coordinate -2,5) etc. 

 

and...

 

Lines on all drawings have the same z-coordinate (x,y,0). Currently, practitioners are not using any 3D-features


This seems to do that, in limited testing.  It picks up on another current thread about finding the item in a list that follows a specified item, and thereby contains the Layer names and their associated elevations in one list.  Again, it uses Extrude rather than Sweep [since I can't test the latter], and it may work with more entity types than you need, and it doesn't yet have an error handler, but see what you think.

 

(defun C:TUBE (/ cmde osm elevs ss ent)
  (initget (if *tubedia 6 7)); no 0, no negative, no Enter on first use
  (setq
    *tubedia
      (cond
        ((getdist
            (strcat
              "\nDiameter of Tubular Cross-Section(s)"
              (if *tubedia (strcat " <" (rtos *tubedia) ">") ""); offer default only on subsequent use
              ": "
            ); strcat
          ); getdist
        ); User-gives-distance condition
        (*tubedia); Enter for default on subsequent use
      ); cond & *tubedia
    cmde (getvar 'cmdecho)
    osm (getvar 'osmode)
    clay (getvar 'clayer)
    elevs '("ELECTRICITY" 1 "WATER" -3 "GAS" -2.5); edit numbers as appropriate
  ); setq
  (setvar 'cmdecho 0)
  (setvar 'osmode 0)
  (prompt "\nTo put paths at Layer-based elevations and make tubular extrusions along them,")
  (if
    (setq ss (ssget '((0 . "*POLYLINE,LINE,ARC,CIRCLE,ELLIPSE,SPLINE") (8 . "ELECTRICITY,WATER,GAS"))))
    (repeat (sslength ss)
      (setq ent (ssname ss 0))
      (command
        "_.move" ent ""
        (list 0 0 (cadr (member (strcase (setvar 'clayer (cdr (assoc 8 (entget ent))))) elevs)))
          ; gets elevation value as item following Layer name in elevs list,
          ; setting that Layer current in the process
        "" ; 'point' given was displacement -- finish Move
        "_.ucs" "_ZA"
          (vlax-curve-getStartPoint ent)
          (mapcar '+
            (vlax-curve-getStartPoint ent)
            (vlax-curve-getFirstDeriv ent (vlax-curve-getStartParam ent))
          ); mapcar & UCS
        "_.circle" "0,0" (/ *tubedia 2)
        "_.ucs" "_previous"
        "_.extrude" (entlast) "" "_path" ent
      ); command
      (ssdel (ssname ss 0) ss)
    ); repeat
  ); if
  (setvar 'cmdecho cmde)
  (setvar 'osmode osm)
  (setvar 'clayer clay)
  (princ)
); defun

 

Kent Cooper, AIA
Message 20 of 54
Kent1Cooper
in reply to: Kent1Cooper


@Kent1Cooper wrote:
....

This seems to do that, in limited testing.  ....


Oh, and I should also mention that it does depend on the second thing I quoted from the OP, that everything is starting out at 0 elevation.  If anything might not be, or if you try to run it again and catch any of the objects that were moved before, then adjustments could be made to force things to an absolute elevation, regardless of their initial elevation.

Kent Cooper, AIA

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost