Jump to content

Updating two parallel at the same time when one is amended


CFORD

Recommended Posts

Hello All,

 

Wondering if you can help me automate a problem I have. 

 

I have two layers one layer is always the same as the other but offset 2m inside the other.

 

A lot of the time that outer  polygon needs amending and changing its shape. I then have to amend the inner layer. I could just offset the outer layer again by 2m and match the layer to the one it is meant to be but this has problems with the plugin I am using. So I am wondering if there is anyway to link to polygons so that when I amend one polyline the other also updates.

 

Let me know if you know any tips 

 

 

Link to comment
Share on other sites

On 11/23/2022 at 9:45 AM, CFORD said:

Hello All,

 

Wondering if you can help me automate a problem I have. 

 

I have two layers one layer is always the same as the other but offset 2m inside the other.

 

A lot of the time that outer  polygon needs amending and changing its shape. I then have to amend the inner layer. I could just offset the outer layer again by 2m and match the layer to the one it is meant to be but this has problems with the plugin I am using. So I am wondering if there is anyway to link to polygons so that when I amend one polyline the other also updates.

 

Let me know if you know any tips 

 

 

Please upload your sample.dwg 

Link to comment
Share on other sites

  • 3 weeks later...

Apologies for the slow reply, thank you very much for your replies. The reason I would need to do this is because I work on designing solar farms. A time consuming part of the job is amending the fence line that goes around the solar farm. The area with panels in it is offset 2m from this fence line. I have done a bit more digging and cant find an existing command that does what i want it to do I don't believe. The paneled area is link to a plugin in AutoCad called PVcase, so every time the fence line is changed the paneled area needs changing also. But the paneled area can't be deleted and re offset otherwise there are a few processes in which I need to regenerate the panels in the paneled area.

 

How I think a command would work

click the first line (fence) which is going to be amended

click the second (paneled area) line that wants to be amended 

then make the amendments to the first line and click enter and the second line 

 

fence is pink in this image orange is the paneled area and the blue rectangles are the solar panels

image.thumb.png.cd63bf4d9bd7d7bea0662501660bc54a.png

image.thumb.png.a310b51562463c7b6776c312daddaae3.png

image.thumb.png.d26eefffe8350453028da502aefac08d.png

Let me know if you have any smart ideas about how to go about tackling this problem.

Many thanks Steven and Devitg

Link to comment
Share on other sites

9 minutes ago, CFORD said:

Apologies for the slow reply, thank you very much for your replies. The reason I would need to do this is because I work on designing solar farms. A time consuming part of the job is amending the fence line that goes around the solar farm. The area with panels in it is offset 2m from this fence line. I have done a bit more digging and cant find an existing command that does what i want it to do I don't believe. The paneled area is link to a plugin in AutoCad called PVcase, so every time the fence line is changed the paneled area needs changing also. But the paneled area can't be deleted and re offset otherwise there are a few processes in which I need to regenerate the panels in the paneled area.

 

How I think a command would work

click the first line (fence) which is going to be amended

click the second (paneled area) line that wants to be amended 

then make the amendments to the first line and click enter and the second line 

 

fence is pink in this image orange is the paneled area and the blue rectangles are the solar panels

image.thumb.png.cd63bf4d9bd7d7bea0662501660bc54a.png

image.thumb.png.a310b51562463c7b6776c312daddaae3.png

image.thumb.png.d26eefffe8350453028da502aefac08d.png

Let me know if you have any smart ideas about how to go about tackling this problem.

Many thanks Steven and Devitg

Hi CFORD, please UPLOAD the DWG

 

Link to comment
Share on other sites

update magenta.

Delete other polyline crossing/inside magenta

check for CW or CCW 

Offset magenta in 2m

update offset polyline with new properties

 

Link to comment
Share on other sites

  • 1 month later...

I am sorry I have been away for so long I have had some issues which meant I haven't been working. Sorry for taking so long to get back to you. I believe I can better explain myself now. Attached is a DWG and a break down of what I am trying to achieve. As mentioned before I believe it should work like this.

1. Click the fence and the PV Area to let the rest of the command know this will be the line you are going to edit.

2. Edit the shape of the Fence line using _AeccInsertFeaturePI _AeccDeleteFeaturePI, or just simply editing the vertices manually.

3. When changing the shape is done this new fence line shape needs to be offset by 2m inward.

4. Use the Breakatpoint command where the changed offset 2m fence line intersects with the old PV area. 

5. Delete the PV area line that goes outside the fence lines boundary and delete the remaining 2m offset fence line that is not needed anymore. (unfortunately if I just moved the new 2m offset fence line into the PV Area the add-in I use will not be able to generate the panels again without a very long process taking place so this is some ways is a short cut)

6. move the new 2m offset fence to the PV area

7. join the pvcase area and the new section of pv area in that order. This is because in the add in if I joined the new section to the old section of PV area the panels will not generate.

 

Unfortunately I only know a very basic level of Autolisp I have googled a lot to try and figure this out even tried using ChatGPT.

Let me know if any of you can make this into a a AutoLISP command it is much appreciated.

 

Thank you,

 

Charlie  

Changing the fence line process.dwg

Link to comment
Share on other sites

This is what I managed to get ChatGPT to do so far 

(defun OFFSETANDJOINOBJECTS()
  (setq fence (ssget "L" '((0 . "LINE") (8 . "Fence"))))
  (if (= 0 (sslength fence))
      (alert "No objects found in layer 'Fence'.")
    (setq pvarea (ssget "L" '((0 . "LINE") (8 . "PVcase PV Area"))))
    (if (= 0 (sslength pvarea))
        (alert "No objects found in layer 'PVcase PV Area'.")
      (progn
        (ssetfirst fence)
        (setq obj1 (entsel))
        (ssetfirst pvarea)
        (setq obj2 (entsel))
        (command "_AeccInsertFeaturePI")
        (princ)
        (setq obj1_offset (offset obj1 (list (cons 0 -2.0))))
        (setq breakpts (intersect obj1_offset obj2))
        (if (= 0 (len breakpts))
            (alert "Objects do not intersect.")
          (progn
            (setq obj2_clipped (split obj2 obj1_offset))
            (setq obj1_clipped (split obj1_offset obj2))
            (setq obj3 (cadr obj1_clipped))
            (entdel obj2)
            (entdel obj1)
            (entmod (cadr obj2_clipped))
            (entmod obj3 '((8 . "PVcase PV Area")))
            (entmake (append (entget obj3) (list (cons 0 "LINE") (cons 100 "AcDbEntity") (cons 67 1) (cons 8 "PVcase PV Area"))))
            (entmake (append (entget (cadr obj2_clipped)) (list (cons 0 "LINE") (cons 100 "AcDbEntity") (cons 67 1) (cons 8 "PVcase PV Area"))))
            (entmake (list (cons 0 "JOIN") (cons 330 (entlast)) (cons 330 obj3)))
            (princ)
            )
          )
        )
      )
    )
  )

 

Link to comment
Share on other sites

while chatgpt is pretty incredible it has a long way to go before it spits out reliable code consistently. looking over your reference drawing looks like the addin your using has field data linked to that entity thats why you can just make a new polyline. BUT really all you should need to do is add some vertices to the polyline and your good to go.

 

Example here

Code here

 

-Edit

This looks like this will work, the polyline kept the same handle so it should just be two clicks. copied/edited from here

(defun c:Fence_Update (/ source target)
  (setq source (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
        target (vlax-ename->vla-object (car (entsel "\nFence Polyline: ")))
  )
  (vla-put-Coordinates target (vla-get-Coordinates source))
  (initget "Yes No")
  (if (= (getkword "\nDelete Source Polyline? [Yes/No]: ") "Yes")
    (vla-delete source) ; delete source polyline
  )
  (princ)
)

 

--Edit 2

Above code only works with straight lines. updated the code with last post to work with bulges

(defun c:Fence_Update (/ i obj1 obj2 blug)
  (vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
  (setq i 0) ;; parameter index
  (setq obj1 (vlax-ename->vla-object (setq ent (car (entsel "\nSource Polyline: "))))
        obj2 (vlax-ename->vla-object (car (entsel "\nTarget Polyline: ")))
  )
  (setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 42)) (entget ent))))
  (vla-put-Coordinates obj2 (vla-get-Coordinates obj1))  
  (foreach b bulg
    (vla-setbulge obj2 i (nth i bulg))
    (setq i (1+ i))
  )
  (initget "Yes No")
  (if (= (getkword "\nDelete Source Polyline? [Yes/No]: ") "Yes")
    (vla-delete obj1) ; delete source polyline
  )
  (vla-endundomark Drawing)
  (princ)
)

 

Edited by mhupp
Link to comment
Share on other sites

Oh brilliant that is a much better way of doing it thank you. Far more simple than I was expecting now I think all I need to try and do is make it so it offsets 2m inward and select that as the target. thank you very much.

 

Edited by CFORD
Link to comment
Share on other sites

(defun c:UFP (/ i obj1 obj2 blug offsetEnt)
(vla-startundomark (vla-get-activedocument (vlax-get-acad-object))) ; Start a transaction for undo/redo operations
(setq ent (car (entsel "\nSource Polyline: "))) ; Get the source polyline from the user
(setq obj1 (vlax-ename->vla-object ent)) ; Convert the source polyline's entity name to a VLA-Object
(setq offsetEnt (command "_.offset" "2")) ; Create the offset line 2 meters to the left
(entmake offsetEnt) ; Save the offset line in the drawing
(setq obj2 (vlax-ename->vla-object (car (entsel "\nTarget Polyline: " "offsetEnt")))) ; Get the target polyline from the user
(setq i 0) ; Initialize the parameter index to 0
(setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 42)) (entget ent)))) ; Get the bulge values from the source polyline
(vla-put-Coordinates obj2 (vla-get-Coordinates obj1)) ; Set the coordinates of the target polyline to the source polyline
(foreach b bulg
(vla-setbulge obj2 i (nth i bulg)) ; Set the bulge value of the target polyline
(setq i (1+ i)) ; Increment the parameter index
)
(initget "Yes No") ; Initialize a user input with "Yes" or "No" options
(if (= (getkword "\nDelete Source Polyline? [Yes/No]: ") "Yes") ; Get user input to delete the source polyline
(vla-delete obj1) ; delete source polyline
)
(vla-endundomark Drawing) ; End the transaction
(princ) ; Exit the function
)

Made this but can't seem to get it right if you can help me fix it that would be great. I got ChatGPT to put commentary next to each line to explain what I was trying to do 

Link to comment
Share on other sites

35 minutes ago, CFORD said:

I got ChatGPT to put commentary next to each line to explain what I was trying to do 

 

Would be far better to do that yourself - much better way to learn and work out the problems?

Link to comment
Share on other sites

Their is alot more to offset command. have to check the polyline's direction. (is it clockwise or counter clock wise) then the vla-offset its self is a variant (because their can be multiple offsets) unless you use vlax-invoke then its a list. you shouldn't have multiple offsets unless you have weird shape that has a choke point like this. example creates two new polylines. I test for this in my lisp so it will alert with a popup saying "More Than one Offset Detected" and quit. but this should never happen.

 

image.png.83a08efdf5a7c1309a2d8ca0c4efbd59.png

 

(defun c:Fence_Update (/ i obj1 obj2 ent off blug)
  (vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
  (setq i 0) ;; parameter index
  (setq obj1 (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
        obj2 (vlax-ename->vla-object (car (entsel "\nFence Polyline: ")))
  )
  (setq off (vlax-invoke obj1 'offset (if (CW obj1) 2.0 -2.0))) ;offset to inside
  (if (<= (length off) 1)
    (setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x)(= (car x) 42)) (entget (vlax-vla-object->ename (setq off (car off)))))))
    (progn
      (alert "\nMore Than one Offset Detected")
      (quit)
    )
  )        
  (vla-put-Coordinates obj2 (vla-get-Coordinates off))
  (foreach b bulg
    (vla-setbulge obj2 i (nth i bulg))
    (setq i (1+ i))
  )
  (vla-delete off)
  (vla-endundomark Drawing)
  (princ)
)
;;----------------------------------------------------------------------------;;
; Check Polylines direction is CW or CCW - Writer Evgeniy Elpanov By Bill Gilliss
;(vla-offset (vlax-ename->vla-object ent) (if (CW ent) -0.01 0.01))
(defun CW (poly / lw lst LL UR)
  (if (= (type poly) "ENAME")
    (setq lw (vlax-ename->vla-object poly))
    (setq lw poly)
  )
  (vla-GetBoundingBox lw 'LL 'UR)
  (setq LL (vlax-safearray->list LL)
        UR (vlax-safearray->list UR)
        lst (mapcar
              (function
                (lambda (x)
                        (vlax-curve-getParamAtPoint poly
                                                    (vlax-curve-getClosestPointTo poly x)
                        )
                )
              )
              (list LL (list (car LL) (cadr UR))
                    UR (list (car UR) (cadr LL))
              )
            )
  )
  (if
    (or
      (<= (car lst) (cadr lst) (caddr lst) (cadddr lst))
      (<= (cadr lst) (caddr lst) (cadddr lst) (car lst))
      (<= (caddr lst) (cadddr lst) (car lst) (cadr lst))
      (<= (cadddr lst) (car lst) (cadr lst) (caddr lst))
    ) ;_ or
    t
  )
)

 

  • Agree 1
Link to comment
Share on other sites

Thank you very much @mhupp that is a very good point I did not think about that. Which has made me think of something else as well the PV polyline can be a different shape to the fence line. i.e image.thumb.png.d28f773b239dc6c77f98ab04aedb0948.png

Now if I were to use the Fence_update command here it would change some areas I didn't want to change 

image.thumb.png.7f6db2bd024ec274cd96b06a9f8459bf.png

Like so.

image.thumb.png.d12f0fbf1710b068fd780c967ac2a730.png

Is there anyway of ensuring that does not happen?

 

Link to comment
Share on other sites

Off the top of my head.

 

  • during the UFP lisp make a copy of the original polyline on another layer
  • Then use the first lisp I posted to add vertexes and move grips to correct location.
  • Delete the copied polyline.

 

(defun c:UFP (/ i obj1 obj2 ent off blug)
  (vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
  (setq i 0)  ;; parameter index
  (setq obj1 (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
        obj2 (vlax-ename->vla-object (car (entsel "\nPolyline to Update Polyline: ")))
  )
  (entmake '((0 . "LAYER") (100 . "AcDbSymbolTableRecord") (100 . "AcDbLayerTableRecord") (2 . "CHECK") (70 . 0) (62 . 1) (290 . 0))) ;make new layer that is red and plotting is turned off
  (setq poly (vlax-invoke obj2 'copy))
  (vla-put-layer poly "CHECK")
  (setq off (vlax-invoke obj1 'offset (if (CW obj1) 2.0 -2.0)))  ;offset to inside
  (if (<= (length off) 1)
    (setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 42)) (entget (vlax-vla-object->ename (setq off (car off)))))))
    (progn
      (alert "\nMore Than one Offset Detected")
      (quit)
    )
  )
  (vla-put-Coordinates obj2 (vla-get-Coordinates off))
  (foreach b bulg
    (vla-setbulge obj2 i (nth i bulg))
    (setq i (1+ i))
  )
  (vla-delete off)
  (vla-endundomark Drawing)
  (princ)
)
;;----------------------------------------------------------------------------;;
; Check Polylines direction is CW or CCW - Writer Evgeniy Elpanov By Bill Gilliss
;(vla-offset (vlax-ename->vla-object ent) (if (CW ent) -0.01 0.01))
(defun CW (poly / lw lst LL UR)
  (if (= (type poly) "ENAME")
    (setq lw (vlax-ename->vla-object poly))
    (setq lw poly)
  )
  (vla-GetBoundingBox lw 'LL 'UR)
  (setq LL (vlax-safearray->list LL)
        UR (vlax-safearray->list UR)
        lst (mapcar
              (function
                (lambda (x)
                        (vlax-curve-getParamAtPoint poly
                                                    (vlax-curve-getClosestPointTo poly x)
                        )
                )
              )
              (list LL (list (car LL) (cadr UR))
                    UR (list (car UR) (cadr LL))
              )
            )
  )
  (if
    (or
      (<= (car lst) (cadr lst) (caddr lst) (cadddr lst))
      (<= (cadr lst) (caddr lst) (cadddr lst) (car lst))
      (<= (caddr lst) (cadddr lst) (car lst) (cadr lst))
      (<= (cadddr lst) (car lst) (cadr lst) (caddr lst))
    ) ;_ or
    t
  )
)

 

Edited by mhupp
Link to comment
Share on other sites

That is very clever thank you @mhupp. I guess from the check layer you can automate it even more by including a boundary command in the center of that shape that includes the check layer and then matches the PV area vertices to the boundary made and then delete the check layer after. Do you think that is something that could work?

Link to comment
Share on other sites

(defun c:UFP (/ i obj1 obj2 ent off blug obj3)
  (vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
  (setq i 0)  ;; parameter index
  (setq obj1 (vlax-ename->vla-object (car (entsel "\nSource Polyline: ")))
        obj2 (vlax-ename->vla-object (car (entsel "\nPolyline to Update Polyline: ")))
  )
  (entmake '((0 . "LAYER") (100 . "AcDbSymbolTableRecord") (100 . "AcDbLayerTableRecord") (2 . "CHECK") (70 . 0) (62 . 1) (290 . 0))) ;make new layer that is red and plotting is turned off
  (setq poly (vlax-invoke obj2 'copy))
  (vla-put-layer poly "CHECK")
  (setq off (vlax-invoke obj1 'offset (if (CW obj1) 2.0 -2.0)))  ;offset to inside
  (if (<= (length off) 1)
    (setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 42)) (entget (vlax-vla-object->ename (setq off (car off)))))))
    (progn
      (alert "\nMore Than one Offset Detected")
      (quit)
    )
  )
  (vla-put-Coordinates obj2 (vla-get-Coordinates off))
  (foreach b bulg
    (vla-setbulge obj2 i (nth i bulg))
    (setq i (1+ i))
  )
  (vla-delete off)
(setq obj3 (getpoint "\nPick internal point: "))
   (command "_.-boundary" "_a" "_i" "_n" "" "" "_non" obj3 "")
)
(vla-put-Coordinates obj2 (vla-get-Coordinates obj3))
(foreach b bulg
    (vla-setbulge obj2 i (nth i bulg))
    (setq i (1+ i))
  )
  (vla-endundomark Drawing)
  (vla-delete obj3)
  (princ)
)

So this is how far I got I dont know if you can tell what I was trying to do here but I tried making the boundary command and set it to obj3 and then set obj2 coordinates to obj3. Unfortunately it didn't work it seemed to get stuck after making the boundary command? let me know if you can tell me why it didnt work?

Thank you for all the help so far :)

Link to comment
Share on other sites

I have had another go at this today to try and figure this out? it works mostly except at the end I can't seem to get the bulges to match the boundary that I made.

The code also should delete the "check" layer at the end and obj3 but that did not seem to work either.

If you know a smart way of not having to select the obj3 that was created and instead and re-select the obj2 again to update obj2's coordinates to obj3 that would be really useful as well? 

(defun c:UFP (/ i obj1 obj2 ent off blug obj3)
(vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
(setq i 0) ;; parameter index
(setq obj1 (vlax-ename->vla-object (car (entsel "\nSelect The Fence: ")))
obj2 (vlax-ename->vla-object (car (entsel "\nSelect The Polyline to Update: ")))
)
(entmake '((0 . "LAYER") (100 . "AcDbSymbolTableRecord") (100 . "AcDbLayerTableRecord") (2 . "CHECK") (70 . 0) (62 . 1) (290 . 0))) ;make new layer that is red and plotting is turned off
(setq poly (vlax-invoke obj2 'copy))
(vla-put-layer poly "CHECK")
(setq off (vlax-invoke obj1 'offset (if (CW obj1) 2.0 -2.0))) ;offset to inside
(if (<= (length off) 1)
(setq bulg (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 42)) (entget (vlax-vla-object->ename (setq off (car off)))))))
(progn
(alert "\nMore Than one Offset Detected")
(quit)
)
)
(vla-put-Coordinates obj2 (vla-get-Coordinates off))
(foreach b bulg
(vla-setbulge obj2 i (nth i bulg))
(setq i (1+ i))
)
(vla-delete off)
(setq obj3 (getpoint "\nPick internal point: "))
(command "_.-boundary" "_a" "_i" "_n" "" "" "_non" obj3 "")
(setq obj2 (vlax-ename->vla-object (car (entsel "\nSelect the object to update: ")))
      obj3 (vlax-ename->vla-object (car (entsel "\nSelect the object to use for the new coordinates: "))))
(vla-put-Coordinates obj2 (vla-get-Coordinates obj3))
(foreach b bulg
(vla-setbulge obj2 i (nth i bulg))
(setq i (1+ i))
)
(vla-delete obj3)
(vla-endundomark Drawing)
(setq layer-obj (vla-item (vla-get-layers (vla-get-activedocument (vlax-get-acad-object))) "CHECK"))
(if layer-obj
  (vlax-invoke layer-obj 'delete))
(princ)
)

Any help with this is massively appreciated I have had a good go at this over the last couple days and just cant get it to do what I thought I asked it to do.

Edited by CFORD
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...