Fillet and Trim Just One Entity

Fillet and Trim Just One Entity

JRD-668
Explorer Explorer
2,138 Views
10 Replies
Message 1 of 11

Fillet and Trim Just One Entity

JRD-668
Explorer
Explorer

Seems like this should be simple, but I struggle with LISPS....I am tying proposed contours in to existing contours and thinking there has to be a way to speed up the "rounding out" process.

 

Essentially I want to create a fillet between 2 polylines, then trim and/or extend the first polyline (proposed contour) to meet the fillet, then join the fillet to the proposed contour.  I want to leave the other polyline (the existing contour) completely unchanged.

 

I am attaching a drawing as an example.  I want to create the fillet on the cyan layer, join the cyan polylines/arcs, and leave the red line alone.  

 

Objective.PNG

 

Any help would be greatly appreciated as we spend a lot of time manually rounding out our contours.  (Using Autocad Civil 3D 2019

 

0 Likes
Accepted solutions (2)
2,139 Views
10 Replies
Replies (10)
Message 2 of 11

ВeekeeCZ
Consultant
Consultant

Try this older one... not best, but it does the job. 

First object selected would not be trimmed.

 

; fillet with Radius, First keep, second trim
(vl-load-com)

(defun c:RF (/ *error* adoc oVAR nVAR getval e1 e2 entq p2 l l1 e er ss 1pt 2pt midpt ename param oblouk)
    
  ;********
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break,end"))
      (princ (strcat "\nError: " errmsg)))
    (mapcar 'setvar nVAR oVAR)
    (vla-endundomark adoc)
    (princ))
  
  
  ;;; GETVAL - returns the group value of an entity.
  ;;; like the wellknown (dxf) function but accepts all kinds of
  ;;; entity representations (ename, entget list, entsel list)
  (defun GETVAL	(grp ele)		;"dxf value" of any ent...
    (cond ((= (type ele) 'ENAME)	;ENAME
	   (cdr (assoc grp (entget ele)))
	   )
	  ((not ele) nil)		;empty value
	  ((not (listp ele)) nil)	;invalid ele
	  ((= (type (car ele)) 'ENAME)	;entsel-list
	   (cdr (assoc grp (entget (car ele))))
	   )
	  (T (cdr (assoc grp ele))))
    ); end getval
  
  (vla-startundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  (setq oVAR (mapcar 'getvar (setq nVAR '(CMDECHO TRIMMODE PEDITACCEPT OSMODE))))
  (mapcar 'setvar nVAR 			'(0	  0	   1	       0     ))
  
  (setvar "filletrad" (cond ((getreal (strcat "\nSpecify fillet radius <" (rtos (getvar "filletrad") 2 2) ">: ")))
			    (T (getvar "filletrad"))))
  
  (while (and (null (setq e2 (entsel "\nSelect first RETAINED object: ")))
	      (wcmatch (getval 0 e2) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e2) 3)
  
  (while (and (null (setq e1 (entsel "\nSelect second TRIMMED object: ")))
	      (wcmatch (getval 0 e1) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e1) 3)
  (setq p1 (cadr e1))
  (setq e1 (car e1))
  
  
  ;(setq p2 (cadr e2))
  ;(setq e2 (car e2))
  
  (if (= (getval 0 e1) "LWPOLYLINE")					;if 1nd polyline
    (progn
      (setq l (entlast))
      (command "_.EXPLODE" e1)						;make it line or arc (would be trimed)
      (setq ss (ssadd))
      (ssadd (setq e (entnext l)) ss)
      (while (setq e (entnext e))
	(ssadd e ss))))
  (if (= (getval 0 e2) "LWPOLYLINE") 					;if 2st polyline
    (progn
      (setq ename (car e2)
	    midpt (vlax-curve-getClosestPointTo ename (trans (cadr e2) 1 0))
	    param (vlax-curve-getParamAtPoint ename midpt)
	    1pt (vlax-curve-getPointAtParam ename (fix param))
	    2pt (vlax-curve-getPointAtParam ename (1+ (fix param))))
      (if (> (abs (- (- (vlax-curve-getDistAtPoint ename 2pt)
			(vlax-curve-getDistAtPoint ename 1pt))
		     (distance 2pt 1pt)))
	     0.002)
	(setq oblouk T))
      (if oblouk
	(command "_.ARC" 1pt midpt 2pt)					;make it line or arc (would be keeped)
	(command "_.LINE" 1pt 2pt ""))
      (setq l2 (cons (entlast) (list (cadr e2))))))			;if 1st line or arc
  (if (wcmatch (getval 0 e2) "LINE,ARC,CIRCLE")
    (progn
      (entmake (entget (car e2)))					;duplicat it
      (setq  l2 (cons (entlast) (list (cadr e2))))))
  (setvar "trimmode" 1)
  (command "_.FILLET" (nentselp p1) l2)					;new arc
  (setq er (entlast))
  (entdel (car l2))							;trim substitude of 1st erased
  (if ss (command "_.PEDIT" er "_J" ss "" ""))				;if 2nd was pl, recreate pl
  (if ss (command "_.ERASE" ss ""))					;the rest of it (2nd side) erase
  
  (command "_.REGEN")
  (*error* "end")
  (princ)
  )
0 Likes
Message 3 of 11

Kent1Cooper
Consultant
Consultant
Accepted solution

Here's a far shorter one, though in simplest terms without *error* handling or verification that you picked the right kinds of objects [assuming you can trust yourself to do so]:

(defun C:BICL ; = Blend In Contour {poly}Line
  (/ p1 p2 tmode peac)
  (initget (if *BICLrad 6 7)); no zero, no negative, no Enter on first use
  (setq *BICLrad ; global variable
    (cond
      ( (getdist
          (strcat
            "Blend-in radius"
            (if *BICLrad (strcat " <" (rtos *BICLrad) ">") "")
            ": "
          ); strcat
        ); getdist
      ); User-input condition
      (*BICLrad); prior value when present
    ); cond
    p1 (entsel "\nSelect contour to blend in, near other contour: ")
    p2 (entsel "\nSelect contour to blend it into, near expected blend-in location: ")
    tmode (getvar 'trimmode)
peac (getvar 'peditaccept) ); setq (setvar 'trimmode 0); = Trim option set to No Trim
(setvar 'peditaccept 1); to get new Arc
(setvar 'filletrad *BICLrad) (command "_.fillet" (cadr p1) (cadr p2) "_.pedit" "_multiple" (car p1) (entlast) "" "_join" (* *BICLrad 3) "" ); command (setvar 'trimmode tmode); restore
(setvar 'peditaccept peac) (princ) ); defun

That 3 multiplier for the PEDIT/Join fuzz factor is a guess -- depending on how close your new contours typically get to the existing ones, you may need to increase that, or you may be able to decrease it.

It doesn't deal with the PEDITACCEPT System Variable, but if that's set to accept, the first object can be a Line rather than a Polyline [the second one can be, in any case]. EDIT:  yes it does, now (needs to for the new Arc).

 

If arc segments might be involved other than the newly-created one, more would need to be done, since Fillet doesn't always like working with Polyline arc segments.

 

Kent Cooper, AIA
0 Likes
Message 4 of 11

JRD-668
Explorer
Explorer

You guys are freaking wizards!  Been trying to solve this problem for longer than I care to admit and you both have excellent solutions!  

 

I haven't encountered any problems in my preliminary testing, hopefully all goes well when I start utilizing for production.  

 

I'm being greedy now, but BeekeeCZ, is it a simple matter to change the code so that the first clicked entity is the one that gets modified, but second entity remains the same?  I'm going to be piloting both these LISPS with some team members and people will get confused if the 2 LISP routines use a different order of operations. In general we select the proposed contour first when filleting.

 

Again many thanks!

0 Likes
Message 5 of 11

ВeekeeCZ
Consultant
Consultant

@JRD-668 wrote:

... BeekeeCZ, is it a simple matter to change the code so that the first clicked entity is the one that gets modified, but second entity remains the same?...


 

I believe it is. But it's up to you to find out. 

0 Likes
Message 6 of 11

JRD-668
Explorer
Explorer

Found what I was after.  Switching your "e1" and "e2" in these lines changes the behavior to where the first entity is modified.

(while (and (null (setq e2 (entsel "\nSelect first RETAINED object: ")))
	      (wcmatch (getval 0 e2) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e2) 3)
  
  (while (and (null (setq e1 (entsel "\nSelect second TRIMMED object: ")))
	      (wcmatch (getval 0 e1) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e1) 3)

 Many thanks for the help, it is very much appreciated!!!  You've solved an issue we've had for for quite a while.

0 Likes
Message 7 of 11

JRD-668
Explorer
Explorer

One more item I can't solve for the life of me.....

 

The routine works great, but when it creates the new polyline, it always creates it on the current layer.  I would like the new polyline to be created on the same layer as the first entity that was selected.  In this instance, the new polyline should be created on the cyan layer "Proposed Contours."

 

I've been combing the forums and believe I have the correct way to identify the layer of the first selected entity.  The last step in the routine should be to change the layer of the newly created polyline from the current layer to the identified layer.  What am I messing up?

; fillet with Radius, First keep, second trim

(defun c:FCLL (/ *error* adoc oVAR nVAR getval e1 e2 entq p2 l l1 e er ss 1pt 2pt midpt ename param oblouk LayerName z1)
    
  ;********
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break,end"))
      (princ (strcat "\nError: " errmsg)))
    (mapcar 'setvar nVAR oVAR)
    (vla-endundomark adoc)
    (princ))
  
  
  ;;; GETVAL - returns the group value of an entity.
  ;;; like the wellknown (dxf) function but accepts all kinds of
  ;;; entity representations (ename, entget list, entsel list)
  (defun GETVAL	(grp ele)		;"dxf value" of any ent...
    (cond ((= (type ele) 'ENAME)	;ENAME
	   (cdr (assoc grp (entget ele)))
	   )
	  ((not ele) nil)		;empty value
	  ((not (listp ele)) nil)	;invalid ele
	  ((= (type (car ele)) 'ENAME)	;entsel-list
	   (cdr (assoc grp (entget (car ele))))
	   )
	  (T (cdr (assoc grp ele))))
    ); end getval
  
  (vla-startundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  (setq oVAR (mapcar 'getvar (setq nVAR '(CMDECHO TRIMMODE PEDITACCEPT OSMODE))))
  (mapcar 'setvar nVAR 			'(0	  0	   1	       0     ))
  
  (setvar "filletrad" (cond ((getreal (strcat "\nSpecify fillet radius <" (rtos (getvar "filletrad") 2 2) ">: ")))
			    (T (getvar "filletrad"))))
  
  (while (and (null (setq e1 (entsel "\nSelect first object (TO BE MODIFIED): ")))
	      (wcmatch (getval 0 e1) "LINE,ARC,LWPOLYLINE")))

;Identify the layer of the first selected entity
(setq z1 (entget (car e1)))
(setq LayerName (assoc 8 z1))

  (redraw (car e1) 3)

  (while (and (null (setq e2 (entsel "\nSelect second object (REMAINS THE SAME): ")))
	      (wcmatch (getval 0 e2) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e2) 3)
  
(setq p1 (cadr e1))
(setq e1 (car e1))
 
  
  (if (= (getval 0 e1) "LWPOLYLINE")					;if 1nd polyline
    (progn
      (setq l (entlast))
      (command "_.EXPLODE" e1)						;make it line or arc (would be trimed)
      (setq ss (ssadd))
      (ssadd (setq e (entnext l)) ss)
      (while (setq e (entnext e))
	(ssadd e ss))))
  (if (= (getval 0 e2) "LWPOLYLINE") 					;if 2st polyline
    (progn
      (setq ename (car e2)
	    midpt (vlax-curve-getClosestPointTo ename (trans (cadr e2) 1 0))
	    param (vlax-curve-getParamAtPoint ename midpt)
	    1pt (vlax-curve-getPointAtParam ename (fix param))
	    2pt (vlax-curve-getPointAtParam ename (1+ (fix param))))
      (if (> (abs (- (- (vlax-curve-getDistAtPoint ename 2pt)
			(vlax-curve-getDistAtPoint ename 1pt))
		     (distance 2pt 1pt)))
	     0.002)
	(setq oblouk T))
      (if oblouk
	(command "_.ARC" 1pt midpt 2pt)					;make it line or arc (would be keeped)
	(command "_.LINE" 1pt 2pt ""))
      (setq l2 (cons (entlast) (list (cadr e2))))))			;if 1st line or arc
  (if (wcmatch (getval 0 e2) "LINE,ARC,CIRCLE")
    (progn
      (entmake (entget (car e2)))					;duplicat it
      (setq  l2 (cons (entlast) (list (cadr e2))))))
  (setvar "trimmode" 1)
  (command "_.FILLET" (nentselp p1) l2)					;new arc
  (setq er (entlast))
  (entdel (car l2))							;trim substitude of 1st erased
  (if ss (command "_.PEDIT" er "_J" ss "" ""))				;if 2nd was pl, recreate pl
  (if ss (command "_.ERASE" ss ""))					;the rest of it (2nd side) erase

;Need to switch the layer of the polyline from current layer to the identified layer
;Found code below on forums but can't get it to work

(command "_.CHANGE" sel "" "_properties" "_LAYER" LayerName "")
  
  (command "_.REGEN")
  (*error* "end")
  (princ)
  )
0 Likes
Message 8 of 11

Kent1Cooper
Consultant
Consultant

I don't see the 'sel' variable set anywhere.  Should that be 'er', or (entlast)? 

Kent Cooper, AIA
0 Likes
Message 9 of 11

ВeekeeCZ
Consultant
Consultant
Accepted solution

In addition to Kent's suggestion...

 

There is one more step you need to do when getting a layer name...

(assoc 8 (entget ent)) returns a pair '(8 . "Layer"), but you need to have just a second item: (cdr (assoc 8...

 

; fillet with Radius, First keep, second trim

(defun c:FCLL (/ *error* adoc oVAR nVAR getval e1 e2 entq p2 l l1 e er ss 1pt 2pt midpt ename param oblouk LayerName z1)
  
  ;********
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break,end"))
      (princ (strcat "\nError: " errmsg)))
    (mapcar 'setvar nVAR oVAR)
    (vla-endundomark adoc)
    (princ))
  
  
  ;;; GETVAL - returns the group value of an entity.
  ;;; like the wellknown (dxf) function but accepts all kinds of
  ;;; entity representations (ename, entget list, entsel list)
  (defun GETVAL	(grp ele)		;"dxf value" of any ent...
    (cond ((= (type ele) 'ENAME)	;ENAME
	   (cdr (assoc grp (entget ele)))
	   )
	  ((not ele) nil)		;empty value
	  ((not (listp ele)) nil)	;invalid ele
	  ((= (type (car ele)) 'ENAME)	;entsel-list
	   (cdr (assoc grp (entget (car ele))))
	   )
	  (T (cdr (assoc grp ele))))
    ); end getval
  
  (vla-startundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  (setq oVAR (mapcar 'getvar (setq nVAR '(CMDECHO TRIMMODE PEDITACCEPT OSMODE))))
  (mapcar 'setvar nVAR 			'(1	  0	   1	       0     ))
  
  (setvar "filletrad" (cond ((getreal (strcat "\nSpecify fillet radius <" (rtos (getvar "filletrad") 2 2) ">: ")))
			    (T (getvar "filletrad"))))
  
  (while (and (null (setq e1 (entsel "\nSelect first object (TO BE MODIFIED): ")))
	      (wcmatch (getval 0 e1) "LINE,ARC,LWPOLYLINE")))
  
  ;Identify the layer of the first selected entity
  (setq LayerName (cdr (assoc 8 (entget (car e1)))))
  
  (redraw (car e1) 3)
  
  (while (and (null (setq e2 (entsel "\nSelect second object (REMAINS THE SAME): ")))
	      (wcmatch (getval 0 e2) "LINE,ARC,LWPOLYLINE")))
  (redraw (car e2) 3)
  
  (setq p1 (cadr e1))
  (setq e1 (car e1))
  
  
  (if (= (getval 0 e1) "LWPOLYLINE")					;if 1nd polyline
    (progn
      (setq l (entlast))
      (command "_.EXPLODE" e1)						;make it line or arc (would be trimed)
      (setq ss (ssadd))
      (ssadd (setq e (entnext l)) ss)
      (while (setq e (entnext e))
	(ssadd e ss))))
  (if (= (getval 0 e2) "LWPOLYLINE") 					;if 2st polyline
    (progn
      (setq ename (car e2)
	    midpt (vlax-curve-getClosestPointTo ename (trans (cadr e2) 1 0))
	    param (vlax-curve-getParamAtPoint ename midpt)
	    1pt (vlax-curve-getPointAtParam ename (fix param))
	    2pt (vlax-curve-getPointAtParam ename (1+ (fix param))))
      (if (> (abs (- (- (vlax-curve-getDistAtPoint ename 2pt)
			(vlax-curve-getDistAtPoint ename 1pt))
		     (distance 2pt 1pt)))
	     0.002)
	(setq oblouk T))
      (if oblouk
	(command "_.ARC" 1pt midpt 2pt)					;make it line or arc (would be keeped)
	(command "_.LINE" 1pt 2pt ""))
      (setq l2 (cons (entlast) (list (cadr e2))))))			;if 1st line or arc
  (if (wcmatch (getval 0 e2) "LINE,ARC,CIRCLE")
    (progn
      (entmake (entget (car e2)))					;duplicat it
      (setq  l2 (cons (entlast) (list (cadr e2))))))
  (setvar "trimmode" 1)
  (command "_.FILLET" (nentselp p1) l2)					;new arc
  (setq er (entlast))
  (command  "_.CHANGE" er "" "_P" "_LAyer" LayerName "")		; change layer
  (entdel (car l2))							;trim substitude of 1st erased
  (if ss (command "_.PEDIT" er "_J" ss "" ""				;if 2nd was pl, recreate pl
		  "_.ERASE" ss ""))					;the rest of it (2nd side) erase
  
  (command "_.REGEN")
  (*error* "end")
  (princ)
  )
Message 10 of 11

JRD-668
Explorer
Explorer

Perfect!!! Can't thank you both enough for the education and the help!

0 Likes
Message 11 of 11

devitg
Advisor
Advisor

Hi , it is the first time I see this way to copy an enty 

 

(entmake (entget (car e2)))

Nice way , I often used VLA-copy , but it is simple and effective. No base point , no nothing 

Thanks for the tip 

0 Likes