Rounding all polylines from snap selection

Rounding all polylines from snap selection

tomaszbartosz93
Contributor Contributor
950 Views
15 Replies
Message 1 of 16

Rounding all polylines from snap selection

tomaszbartosz93
Contributor
Contributor

Rounding of 4 polylines according to the criteria:
- radii from inside 420 , 560, 588 , 728
- if the outer polyline becomes the inner then round 728,588 ,560, 420
The point is to detect with 4 polylines are next to each other, determine which is internal and which is external. Then for each polyline round the hatches alternately according to the above criteria.
Also i am looking for a way to sort polylines according to selection cords. Right now if i select every polylines clicking one by one its fillet according to selection but if i try to snap selection then its all messed up its going like 1-1 , 2-3  ,3 -4 , 4-2

(defun c:changefillet () 
  (setq ss (ssget '((0 . "LWPOLYLINE"))))

  (setq num (sslength ss))
  (if (= num 4) 
    (progn 
      (setq pl1 (ssname ss 0))
      (setq pl2 (ssname ss 1))
      (setq pl3 (ssname ss 2))
      (setq pl4 (ssname ss 3))
      (progn  ;lewo
             (setvar "FILLETRAD" 420)
             (command "_.fillet" "_polyline" pl1)
             (setvar "FILLETRAD" 560)
             (command "_.fillet" "_polyline" pl2)
             (setvar "FILLETRAD" 588)
             (command "_.fillet" "_polyline" pl3)
             (setvar "FILLETRAD" 728)
             (command "_.fillet" "_polyline" pl4)
      )
    )
  )
  (princ)
)


 Rn its look like that:

tomaszbartosz_0-1677267551204.png
And i want to achive something like that 

tomaszbartosz_1-1677267642992.png

 

 

0 Likes
Accepted solutions (2)
951 Views
15 Replies
Replies (15)
Message 2 of 16

devitg
Advisor
Advisor

@tomaszbartosz93 Please upload your sample.dwg

0 Likes
Message 3 of 16

komondormrex
Mentor
Mentor

'tis better to fillet innermost or outmost pline with respective radius and then offset 3 times to get remaining 3, imho.

0 Likes
Message 4 of 16

Kent1Cooper
Consultant
Consultant

@tomaszbartosz93 wrote:

...  for each polyline round the hatches alternately ....


I don't think you really want them alternately.  In your sample, just within range of what is in view, each outer Polyline is either inboard or outboard for two successive corners, so the radius should be the same for those.  That's the really big challenge here, I think -- how to figure out for each bend in each Polyline whether it's the inside or outside.

Kent Cooper, AIA
0 Likes
Message 5 of 16

tomaszbartosz93
Contributor
Contributor

Here you go 🙂

0 Likes
Message 6 of 16

tomaszbartosz93
Contributor
Contributor

In normal scenario yes, but i use this for drawing ventilation schemes and its quite differentiated channel allocations which is impossible. Also i would have to maunaly change every curve of first polyline (bend to outer and inner line) to make good offset for this to work.
for example

tomaszbartosz_0-1677316523081.png
also i am using this code 

(defun offset-lines (ale /) 
  (setq offset-distance ale)
  (if lines 
    (progn 
      (setq i 0)
      (while (< i (sslength lines)) 
        (setq sel (ssname lines i))
        (command "odsuń" offset-distance sel basept "")
        (setq i (1+ i))
      )
      (setq newobjs (ssget "_L"))

      (if newobjs 
        (progn 
          (setvar "FILLETRAD" 0)
          (repeat (setq n (sslength newobjs)) 
            (command "_.fillet" "_polyline" (ssname newobjs (setq n (1- n))))
          )
          (princ "\nNo new objects created.")
        )
      )
      (princ "\nNo lines selected.")
    )
    (princ)
  )
)



(defun delaypoint () 
  (initget "200 28 bez")
  (setq chosenOption (getkword "\n odsunięcie o ile: [200/28/bez] <28>: "))
  (cond 
    ((equal chosenOption "200")
     (progn 
       (setq lines (ssget '((0 . "LINE,ARC,LWPOLYLINE"))))
       (setq basept (getpoint "\nSelect base point: "))
       (offset-lines "270")
     )
    )
    ((equal chosenOption "28")
     (progn 
       (setq lines (ssget '((0 . "LINE,ARC,LWPOLYLINE"))))
       (setq basept (getpoint "\nSelect base point: "))
       (offset-lines "98")
     )
    )
    ((equal chosenOption "bez"))
  )
  (princ)
)
(defun c:dpipe (/ oldWd oldFil oldEch lEnt pl1 pl2 vLst1 vLst2 *error*) 
  (vl-load-com)
  (delaypoint)
  (defun GetPlineVer (plObj) 
    (mapcar 'cdr 
            (vl-remove-if-not 
              '(lambda (x) (= (car x) 10))
              (entget plObj)
            )
    )
  ) ; end of GetPLineVer


  (defun *error* (msg) 
    (setvar "CMDECHO" oldEch)
    (setvar "FILLMODE" oldFil)
    (princ)
  ) ; end of *error*

  (setq duct:pWd 140.0)
  (setq oldFil (getvar "FILLMODE")
        oldEch (getvar "CMDECHO")
  ) ; end setq
  (mapcar 'setvar 
          '("CMDECHO" "FILLMODE")
          '(0 0)
  )
  (if (entlast) (setq lEnt (entlast)))
  (princ "\nSpesify start point: ")
  (command "_.pline" pause)
  (command "_w" duct:pWd duct:pWd)
  (while (= 1 (getvar "CMDACTIVE")) 
    (command pause)
    (princ "\nSpecify next point: ")
  ) ; end while
  (if 
    (not 
      (equal lEnt (entlast))
    )
    (progn 
      (setq promien "420")
      (setq promien2 (+ (atoi promien) 70))
      (setq lEnt (entlast))
      (command "_.fillet" "_r" promien2)
      (command "_.fillet" "_p" lEnt)
      (setq lEnt  (vlax-ename->vla-object lEnt)
            pl1   (car 
                    (vlax-safearray->list 
                      (vlax-variant-value 
                        (vla-Offset lEnt (/ duct:pWd 2))
                      )
                    )
                  )
            pl2   (car 
                    (vlax-safearray->list 
                      (vlax-variant-value 
                        (vla-Offset lEnt (- (/ duct:pWd 2)))
                      )
                    )
                  )
            vLst1 (GetPlineVer 
                    (vlax-vla-object->ename pl1)
                  )
            vLst2 (GetPlineVer 
                    (vlax-vla-object->ename pl2)
                  )
      ) ; end setq
      (vla-put-ConstantWidth pl1 0.0)
      (vla-put-ConstantWidth pl2 0.0)
      (vla-Delete lEnt)
    ) ; end progn
  ) ; end if
  (setvar "CMDECHO" oldEch)
  (setvar "FILLMODE" oldFil)
  (princ)
) ; end 

which draw vent pipes (1 pipe is 2 seperate polylines filleted with 420/560) also i am using offsets to make "support lines" to draw other channels next to eachother, or next to wall for example

0 Likes
Message 7 of 16

tomaszbartosz93
Contributor
Contributor

yeah its quite difficult i think script has to go like this:

1- detect all curves and set them in a list (varriable) - treat every curve as a seperate case scenario
a) for this to work i think program should use option to fillet 2 lines connected to arc in polyline instead of changing filletrad of whole polyline
2. Get start point end point of curve for single polyline.
3. Adjust bend angle by comparying location (Compare start /end points of curves for all polylines to detect their location (outer inner etc)) in ssget selection according to other selected polylines and then operate on those data
Or meabe 
just detect if 1 polyline changed its bend angle and then reverse list of radius and apply to polylines in every case of curve

in that example i provided its should be like this

tomaszbartosz_0-1677317431705.png

 

Raw concept: (this wont work ofc but something to start with )

 

 

 

(defun c:changefillet () 
  (setq ss (ssget '((0 . "LWPOLYLINE"))))
  (setq num (sslength ss))

  (if (> num 1)  ; Check if there are multiple polylines selected
    (progn 
      (setq polylines '()) ; Initialize an empty list to store polylines
      ; Loop through all selected polylines and store their start and end points in a list
      (repeat num 
        (setq polyline (ssname ss (setq i (1- i))))
        (setq vertices (vlax-invoke polyline 'vertices))
        (setq startpt (vlax-get-property (car vertices) 'coordinates))
        (setq endpt (vlax-get-property (car (last vertices)) 'coordinates))
        (setq polylines (cons (list polyline startpt endpt) polylines))
      )

      ; Loop through all polylines and set the fillet radius based on their location
      (foreach polyline polylines 
        (setq polyline (car polyline))
        (setq startpt (cadr polyline))
        (setq endpt (caddr polyline))

        (setq outerpolylines '())
        (setq innerpolylines '())

        ; Loop through all other polylines and check their location relative to the current polyline
        (foreach otherpolyline polylines 
          (setq otherpolyline (car otherpolyline))
          (setq otherstartpt (cadr otherpolyline))
          (setq otherendpt (caddr otherpolyline))

          ; Check if the other polyline is inside or outside the current polyline
          (if (vlax-curve-getClosestPointTo otherstartpt polyline)  ; Check if start point is inside
            (setq innerpolylines (cons otherpolyline innerpolylines))
            (if (vlax-curve-getClosestPointTo otherstartpt polyline)  ; Check if end point is inside
              (setq innerpolylines (cons otherpolyline innerpolylines))
              (setq outerpolylines (cons otherpolyline outerpolylines))
            )
          )
        )

        ; Set the fillet radius based on the location of the polyline
        (if (= (length outerpolylines) 2)  ; If there are two outer polylines
          (setvar "FILLETRAD" 728)
          (if (= (length innerpolylines) 2)  ; If there are two inner polylines
            (setvar "FILLETRAD" 420)
            (setvar "FILLETRAD" 560) ; Otherwise, set the default fillet radius
          )
        )

        ; Fillet the polyline
        (command "_.fillet" "_polyline" polyline)
      )
    )
  )

  (princ)
)

 

 

 

 

0 Likes
Message 8 of 16

ВeekeeCZ
Consultant
Consultant
Accepted solution

@tomaszbartosz93 wrote:

...Also i am looking for a way to sort polylines according to selection cords. Right now if i select every polylines clicking one by one its fillet according to selection but if i try to snap selection then its all messed up its going like 1-1 , 2-3  ,3 -4 , 4-2 ...


 

 

The simplest way is to use a FENCE selection. 

 

(and (setq p1 (getpoint "\nSpecify first point: "))
     (setq p2 (getcorner p1 "\nSpecify other point: "))
     (setq ss (ssget "_F" (list p1 p2) '((0 . "LWPOLYLINE"))))
     )

 

 

For filleting you can use this sub. I suggest to go backwards.

 

  (defun :plfillet (ent par rad / tan enx v1 v2 v3 a1 a2 p1 p2 p3 ) ;; Lee Mac, mods
    (defun tan (x) (if (not (equal 0.0 (cos x) 1e-10)) (/ (sin x) (cos x)))) ;; Lee Mac
    (if (and (setq v1 (vlax-curve-getpointatparam ent (1- par)))
	     (setq v2 (vlax-curve-getpointatparam ent par))
	     (setq v3 (vlax-curve-getpointatparam ent (1+ par)))
	     (setq a1 (angle v2 v1)
		   a2 (angle v2 v3)
		   p1 (polar v2 a1 rad)
		   p2 (polar v2 a2 rad)
		   p3 (inters p1 (polar p1 (+ a1 (/ pi 2)) 1) p2 (polar p2 (+ a2 (/ pi 2)) 1) nil)
		   enx (entget ent)
		   v2 (list 10 (car v2) (cadr v2))
		   v3 (list 10 (car v3) (cadr v3))))
      (entmod (setq enx (append (reverse (cdr (vl-member-if '(lambda (x) (equal x v2 1e-6)) (reverse enx))))
				(list (cons 10 p1) (cons 42 (tan (/ (- pi (abs (- a1 a2))) (if (minusp (- a1 a2)) -4. 4.))))
				      (cons 10 p2))
				(vl-member-if '(lambda (x) (equal x v3 1e-6)) enx))
		    enx (subst (cons 90 (1+ (cdr (assoc 90 enx)))) (assoc 90 enx) enx)))))

 

Message 9 of 16

tomaszbartosz93
Contributor
Contributor

Fence selection works great thanks,
I didnt quite figure it out yet how to use plfillet but i think i get the point of this function. Just have how to correctly  set arguments to work on polyline. Great start for sure! Thanks 🙂

0 Likes
Message 10 of 16

tomaszbartosz93
Contributor
Contributor

 

(defun :plfillet (ent par rad / tan enx v1 v2 v3 a1 a2 p1 p2 p3)  ;; Lee Mac, mods
  (defun tan (x) (if (not (equal 0.0 (cos x) 1e-10)) (/ (sin x) (cos x)))) ;; Lee Mac
  (if 
    (and (setq v1 (vlax-curve-getpointatparam ent (1- par))) 
         (setq v2 (vlax-curve-getpointatparam ent par))
         (setq v3 (vlax-curve-getpointatparam ent (1+ par)))
         (setq a1  (angle v2 v1)
               a2  (angle v2 v3)
               p1  (polar v2 a1 rad)
               p2  (polar v2 a2 rad)
               p3  (inters p1 
                           (polar p1 (+ a1 (/ pi 2)) 1)
                           p2
                           (polar p2 (+ a2 (/ pi 2)) 1)
                           nil
                   )
               enx (entget ent)
               v2  (list 10 (car v2) (cadr v2))
               v3  (list 10 (car v3) (cadr v3))
         )
    )
    (entmod 
      (setq enx (append 
                  (reverse 
                    (cdr 
                      (vl-member-if '(lambda (x) (equal x v2 1e-6)) (reverse enx))
                    )
                  )
                  (list (cons 10 p1) 
                        (cons 42 
                              (tan 
                                (/ 
                                  (- pi (abs (- a1 a2)))
                                  (if (minusp (- a1 a2)) -4. 4.)
                                )
                              )
                        )
                        (cons 10 p2)
                  )
                  (vl-member-if '(lambda (x) (equal x v3 1e-6)) enx)
                )
            enx (subst (cons 90 (1+ (cdr (assoc 90 enx)))) (assoc 90 enx) enx)
      )
    )
  )
)

(defun c:plxfillet (/ ss ent) 
  (and (setq p1 (getpoint "\nPodaj pierwszy punkt: ")) 
       (setq p2 (getcorner p1 "\nPodaj drugi punkt: "))
       (setq ss (ssget "_F" (list p1 p2) '((0 . "LWPOLYLINE"))))
  )
  (setq num (sslength ss))
  (setq i 0)
  (if (setq ent (ssname ss i)) 
    (progn 
      (setq par (getreal "\nFillet parameter: "))
      (setq rad (getreal "\nFillet radius: "))
      (while (or (< par 0.0) (> par 1.0)) 
        (setq par (getreal "\nFillet parameter (between 0 and 1): "))
      )
      (:plfillet ent par rad)
    )
    (prompt "\nNo polyline selected.")
  )
)

 

 

 
Exception has occurred.
  •  
 <Selection set: 2b>
  (if (setq ent (ssname ss i))

Why?
0 Likes
Message 11 of 16

ВeekeeCZ
Consultant
Consultant

Cant test it right now but google what parameter of lwpolyline actually is.

Message 12 of 16

ВeekeeCZ
Consultant
Consultant

Btw THIS func you might also find helpful at some point.

Message 13 of 16

komondormrex
Mentor
Mentor

So vent channel is 140 units and the gap between collinear channels is 28 units, right? And you draw channels with straight segment plines which are filleted afterwards? 

0 Likes
Message 14 of 16

tomaszbartosz93
Contributor
Contributor

Yes, also only 2  vents channels  can align to eachother ( which means 4 polilynes 420,560 588,728)then 200 gap and repeat 

So far :

https://youtu.be/ZS8z3eNkre0

But the problem is here

tomaszbartosz_0-1677364874755.png

I move this vent quite often that's why i need a way to fast change their fillet.

 

0 Likes
Message 15 of 16

ВeekeeCZ
Consultant
Consultant
Accepted solution

A few steps ahead, just quickly.

 


(defun c:Channel ( / LM:fillet e+ e- e o f)
  
  
  ;; Fillet - Lee Mac			Args: p1-2,p34: WCS points defining 1st and 2nd Line	Retr: list for entmake  ;; mods
  (defun LM:Fillet ( ent par rad / LM:Clockwise-p tan a1 a2 di ip zv p1 p3 v1 v2 enx)
    
    ;; Clockwise-p - Lee Mac 		Retr: T if p1,p2,p3 are clockwise oriented
    (defun LM:Clockwise-p ( p1 p2 p3 )
      (<  (* (- (car  p2) (car  p1)) (- (cadr p3) (cadr p1)))
	  (* (- (cadr p2) (cadr p1)) (- (car  p3) (car  p1)))))
    
    ;; Tangent - Lee Mac  		Args: x - real
    (defun tan ( x )
      (if (not (equal 0.0 (cos x) 1e-10))
	(/ (sin x) (cos x))))
    
    (if (and (setq p1 (vlax-curve-getpointatparam ent (1- par)))
	     (setq ip (vlax-curve-getpointatparam ent par))
	     (setq p3 (vlax-curve-getpointatparam ent (1+ par)))
	     (setq rd ((if (LM:Clockwise-p p1 ip p3) car last) rad))
	     (< rd (:FilletRadiusMax p1 ip ip p3))
	     )
      (progn
	(setq a1 (angle ip p1)
	      a2 (angle ip p3)
	      di (abs (/ rd (tan (/ (- a1 a2) 2.0))))
	      v1 (polar ip a1 di)
	      v2 (polar ip a2 di)
	      ip (list 10 (car ip) (cadr ip))
	      p3 (list 10 (car p3) (cadr p3))
	      enx (entget ent))
	
	(entmod (setq enx (append (reverse (cdr (vl-member-if '(lambda (x) (equal x ip 1e-6)) (reverse enx))))
				  (list (cons 10 v1)
					(cons 42 (tan (/ (- pi (abs (- a1 a2))) (if (minusp (- a1 a2)) -4.0 4.0))))
					(cons 10 v2))
				  (vl-member-if '(lambda (x) (equal x p3 1e-6)) enx))
		      enx (subst (cons 90 (1+ (cdr (assoc 90 enx)))) (assoc 90 enx) enx)))))
    )
  
  ;; FilletMax - Kent Cooper		Args: entdef of 2 lines
  (defun :FilletRadiusMax (beg1 end1 beg2 end2 / ed1 ed2 beg1 beg2 end1 end2 far1 far2 int leg1 leg2 ang1 ang2 ang.5 angtg rmax)
    (setq int 	(inters beg1 end1 beg2 end2 nil)
	  far1	(if (> (distance int end1)
		       (distance int beg1))
		  (progn
		    (setq q1c 10)
		    end1)
		  (progn
		    (setq q1c 11)
		    beg1))
	  far2	(if (> (distance int end2)
		       (distance int beg2))
		  (progn
		    (setq q2c 10)
		    end2)
		  (progn
		    (setq q2c 11)
		    beg2))
	  leg1	(distance int far1)
	  leg2	(distance int far2)
	  ang1 	(angle int far1)
	  ang2 	(angle int far2)
	  ang.5 	(if (< (abs (- ang1 ang2)) pi)
			  (/ (abs (- ang1 ang2)) 2)
			  (/ (- (* pi 2) (abs (- ang1 ang2))) 2))
	  angtg 	(/ (sin ang.5)
			   (cos ang.5))
	  rmax 	(min (* leg1 angtg)
		     (* leg2 angtg))
	  ))
  
  
  (command-s "_.pline")
  (setq e (entlast)
	o (vlax-ename->vla-object e)
	f 154.)
  (vla-offset o f)
  (setq e+ (entlast))
  (vla-offset o (- f))
  (setq e- (entlast))
  (entdel e)
  
  (repeat (max 0 (1- (setq v (1- (cdr (assoc 90 (entget e+))))))) ;; right
    (LM:Fillet e+ (setq v (1- v)) '(420 728)))
  (repeat (max 0 (1- (setq v (1- (cdr (assoc 90 (entget e-))))))) ;; left
    (LM:Fillet e- (setq v (1- v)) '(728 420)))
  
  (princ)
  )

 

Message 16 of 16

tomaszbartosz93
Contributor
Contributor
Cant try it right now out becouse my cad licence is expired at home. I will try it out on monday on my office pc. But as far as i can see this should work just fine. Impressive thanks a lot!
0 Likes