Jump to content

Recommended Posts

Posted

Hi, so my new project was given to me by a civ3d guy. He wants to break a bunch of lines or plines, sometimes contours - by a set distance. Took me a few days to think of how I would approach it. Below is my solution; however I have one small problem.

 

I cannot seem to get the break command to respond using my selection set entity. Does anyone know how I could fix this?

 

;;;March 31, 2012
;;;This program will allow the user to select multiple lines and plines
;;;then it will temporarily move each line and pline to a temporary layer then layer isolate to THAT layer
;;;place points along each line and pline at a given distance by the user
;;;break each line at each point, return all lines and plines to their original layer
;;;and then unisolate and return to the current layer
(defun layerchg	()
 (command "-layer" "m" lyname "")
 (setq n (sslength SS1))
 (repeat n
   (setq ENT (ssname SS1 (- N 1)))
   (setq ENTLIST (entget ENT))
   (setq ENTLIST (subst (cons 8 LYNAME) (assoc 8 ENTLIST) ENTLIST))
   (entmod ENTLIST)
   (setq n (- n 1))
 )
)
(defun breakpt ()
 (command "layiso" SS1 "")
 (setvar "Clayer" Lyname)
 (repeat (setq n (sslength ss1))
   (setq ENT (ssname SS1 (- N 1)))
   (command "measure" ENT MSMT "")
   (setq SSpt (ssget "X" '((0 . "Point"))))
   (repeat (setq nx (sslength SSpt))
     (setq SSPTS (ssname SSpt (- N 1)))
     (setq ptent (entget SSPTS))
     (setq ptloc (cdr(assoc 10 ptent)))
     [color="red"](command "break" ent "f" ptloc ptloc)[/color]
     (setq n (- n 1))
   )					;End breaking repeat
   (command "erase" SSPT)
 )					;End repeat
)
(defun c:Linchg	()
 (setq CurLay (getvar "clayer"))
 (setq Osnmde (getvar "osmode"))
 (setq Cmd-Echo (getvar "cmdecho"))
 (prompt
   "\nSelect all lines and/or plines you wish to change: "
 )
 (setq SS1 (ssget '((0 . "LINE,LWPOLYLINE"))))
 (setq
   Msmt (getreal "Please enter the distance between break points.")
 )
 (setq LYNAME "Temporary")
 (layerchg)
 (breakpt)

)

 

Mind you, this isn't finished or cleaned up yet. It's still a work in progress, but until I can figure out how to get this break command to listen to me - I can't really progress.

 

Silvercloak

Posted

(defun breakpt ()
 (command "layiso" SS1 "")
 (setvar "Clayer" Lyname)
 (repeat (setq n (sslength ss1))
   (setq ENT (ssname SS1 (- N 1)))
   (command "measure" ENT MSMT[color=blue]);;;<-remove ""[/color]
   (setq SSpt (ssget "X" '((0 . "Point"))))
   (repeat (setq nx (sslength SSpt))
     (setq SSPTS (ssname SSpt (- [color=blue]nx[/color] 1)))
     (setq ptent (entget SSPTS))
     (setq ptloc (cdr(assoc 10 ptent)))
     (command "break" ent [color=blue]"_non"[/color] ptloc [color=blue]"_non"[/color] ptloc)[color=#0000ff];;;<-remove "f"[/color]
     [color=blue](entdel SSPTS);;<-- delete point entity as you go    [/color]
[color=blue]    (setq ent (entlast))   [/color]
     [color=blue](setq nx (- nx 1))[/color]
   )     ;End breaking repeat
[color=blue]  ;;;(command "erase" SSPT "");; commented[/color]
   [color=blue](setq n (- n 1))[/color]    
 )     ;End repeat
)

 

HTH

Posted

Thanks pBe!! You even corrected my bugs, that's awesome!

 

edit: Oh crap... I don't know how to get these entities back on their original layers, especially if they've been taken from multiple different layers. As soon as they've been broken they become different entities don't they?

Posted

I haven't gone through the entire code, but you may want to consider using a sub function for your break functionality that accepts two entities and a coordinate list (the break point), pseudo code:

 

(defun _break (e1 e2 coord)
 ;; <-- Do something
 )

 

Other than that, it looks like you need to localize your varibles. Consider using some error handling to restore the original sysvars, and also consider placing the subfunctions you're using underneath the command function (localized) unless you're going to be using them as subs in other command functions too. Just a thought.

 

HTH

Posted

This is my final edit of this, unless I can figure out how to return the line sets to their original layers. :(

 

;;;March 31, 2012
;;;This program will allow the user to select multiple lines and plines
;;;then it will temporarily move each line and pline to a temporary layer then layer isolate to THAT layer
;;;place points along each line and pline at a given distance by the user
;;;break each line at each point, return all lines and plines to their original layer
;;;and then unisolate and return to the current layer
(defun layerchg	()
 (setq ENT (ssname SS1 (- N 1)))
 (setq ENTLIST (entget ENT))
 (setq ENTLIST (subst (cons 8 LYNAME) (assoc 8 ENTLIST) ENTLIST))
 (entmod ENTLIST)
)

(defun breakpt ()
 (command "layiso" SS1 "")
 (setvar "Clayer" Lyname)
 (command "measure" ENT MSMT)
 (setq SSpt (ssget "X" '((0 . "Point"))))
 (repeat (setq nx (sslength SSpt))
   (setq SSPTS (ssname SSpt (- Nx 1)))
   (setq ptent (entget SSPTS))
   (setq ptloc (cdr (assoc 10 ptent)))
   (command "break" ent "_non" ptloc "_non" ptloc)
   (entdel SSPTS)
   ;;<-- delete point entity as you go    
   (setq ent (entlast))
   (setq nx (- nx 1))
   ;;(command "erase" SSPT)

 )					;End repeat
)
;;;/
(defun c:BrkLns	(/ SS1 Lyname ENT MSMT SSpt nx ptent ptloc SSPTS Curlay Osnmde CMD-Echo)
 (setq CurLay (getvar "clayer"))
 (setq Osnmde (getvar "osmode"))
 (setq Cmd-Echo (getvar "cmdecho"))
 (setvar "osmode" 0)
 (setvar "cmdecho" 1)
 (prompt
   "\nSelect all lines and/or plines you wish to change: "
 )
 (setq SS1 (ssget '((0 . "LINE,LWPOLYLINE"))))
 (setq
   Msmt (getreal "Please enter the distance between break points.")
 )
 (setq LYNAME "Temporary")
 (command "-layer" "m" lyname "")
 (setq n (sslength SS1))
 (repeat n
   (layerchg)
   (breakpt)
   (setq n (- n 1))
 )
 (command "layuniso")
 (setvar "osmode" osnmde)
 (setvar "clayer" curlay)
 (setvar "cmdecho" cmd-echo)
 (princ)
)

Posted (edited)

Alright silvercloak, instead of giving you fish, we'll teach you how to fish.

I think the reason why you change the layers of the selected object is because you NEED to ISOLATE and select the "POINT" entities without disturbing the other similar enities

But in my opinion you're approach is too much work.

 

You dont need to create those [point enitites] to identify the break point at a given distance, look into vlax-curve-getPointAtDist

Try this

 
(defun c:sample  ( / ent dist pointlist lnt)
     (setq ent (car (entsel)))
     (setq dist (getdist "\nEnter Distance: ") d dist)
     (while (setq pt (vlax-curve-getPointAtDist  ent d))
           (setq pointlist
                      (cons pt pointlist))
           (setq d (+ dist d))
           )
     (foreach itm pointlist (print itm) (princ)))

 

You can invoke a break while in the loop or after the list is generated.

 

Try it and tell me what you think :)

 

Edit: modify code.. Anyway, with this aproach you dont need to create the temporay layer

Got it?

Edited by pBe
Posted
I haven't gone through the entire code, but you may want to consider using a sub function for your break functionality that accepts two entities and a coordinate list (the break point), pseudo code:

 

(defun _break (e1 e2 coord)
 ;; <-- Do something
 )

 

Other than that, it looks like you need to localize your varibles. Consider using some error handling to restore the original sysvars, and also consider placing the subfunctions you're using underneath the command function (localized) unless you're going to be using them as subs in other command functions too. Just a thought.

 

HTH

 

Totally lost me there...

Posted
Alright silvercloak, instead of giving you fish, we'll teach you how to fish.

I think the reason why you change the layers of the selected object is because you NEED to ISOLATE and select the "POINT" entities without disturbing the other similar enities

But in my opinion you're approach is too much work.

 

You dont need to create those [point enitites] to identify the break point at a given distance, look into vlax-curve-getPointAtDist

Try this

 
(defun c:sample  ( / ent dist pointlist lnt)
     (setq ent (car (entsel)))
     (setq dist (getdist "\nEnter Distance: ") d dist)
     (while (setq pt (vlax-curve-getPointAtDist  ent d))
           (setq pointlist
                      (cons pt pointlist))
           (setq d (+ dist d))
           )
     (foreach itm pointlist (print itm) (princ)))

 

You can invoke a break while in the loop or after the list is generated.

 

Try it and tell me what you think :)

 

Edit: modify code.. Anyway, with this aproach you dont need to create the temporay layer

Got it?

 

Thanks pBe!! I'll give it a look and see what I can do :) Thanks for teaching me how to fish ;)

Posted
Totally lost me there...

 

Perhaps we'll revisit the sub-function discussion(s) once you're 'fishing'... Until then, IMO the most important of my suggestions is for you to properly localize your variables.

 

Familiarize yourself with the DEFUN function to better understand the anatomy of a LISP function, specifically the Symbol, the differences between Arguments, and Variables, and the Expression itself.

 

 

(defun [b]sym [/b]([color=blue][b][arguments][/b][/color] [b][color=red][/ variables...][/color][/b]) [color=seagreen][b]expr[/b][/color]...)

 

In short, by not localizing your variables, when your code has completed, the variables that you've defined retain their assigned value(s)

 

To verify this, from the command line, simply type an exclamation point "!" then the variable name that you'd like to check, and if the variable has any value it will be displayed at the command line:

 

Example:

 

Command: (setq myVar "This is a test.")
"This is a test."

Command: [b][color=red]![/color][/b]myVar
"This is a test."

Command: (setq myVar nil)
nil

Command: [color=red][b]![/b][/color]myVar
nil

Non-localized variables can lead to unintended behavior in subsequent calls to the same function, or even other functions that utilize the same variable(s). It is considered a best practice to localize your variables.

 

By 'nesting' your sub-functions within the main command code, you can properly localize your variables, and feed those variables to the sub-functions all without exposing them (the defined variables) to other functions.

 

This is similar (not exactly the same) to how .NET uses Namespaces, where (generally speaking) only classes, and methods defined within a given namespace can interact.

 

Hopefully *some* of this makes some sense to you... I am sure this will be useful to you once you begin to 'fish' for yourself. ;)

 

HTH

Posted

Now that's pretty neat, Alan - Good job! :beer:

Posted
Now that's pretty neat, Alan - Good job! :beer:

Thanks - change that beer to coffee.

I've posted several curve breaking routines throughout that thread.

Posted
Thanks - change that beer to coffee.

 

Nahh... that's just frothy cappuccino. LoL

 

I've posted several curve breaking routines throughout that thread.

 

I'll have to check them out.

Posted
Nahh... that's just frothy cappuccino. LoL

Good enough. :P

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...