Hi,
I need to divide thousands of lines into half, but AutoCAD divide command can only allow you to select one line at a time.Is there any way we can divide multiple lines at once.
Thanks
@Patchy wrote:I used the one Kent wrote.
In the future, perhaps it would be prudent for you not fail to specify that... The OP thanked Dbroad for his routine, asked for the revisiong to include Polylines, and you offer advise for someone else's routine.
I'm sure you can see how you comment may have confuesed someone less adept at coding LISP.
In any event, thanks for clarifying here.
Cheers
"How we think determines what we do, and what we do determines what we get."
Hey Dbroad,
If I might offer another suggestion for your consideration... Following your iteration of the ActiveSelectionSet Object, your should use vla-Delete, as there's a finite number of allowed SelectionSets, and each iteration of the routine otherwise adds another one to the stack:
(vlax-for x (setq ss (vla-get-activeselectionset acDoc)) ;;<-- do work ) (vla-delete ss)
Cheers
"How we think determines what we do, and what we do determines what we get."
Here is one that handles arcs, lines, and lwpolylines.
(vl-load-com) (defun c:mdivide (/ doc spc blk) ;;D. C. Broad, Jr. 4/2013 (setq doc (vla-get-activedocument (vlax-get-acad-object)) spc (vla-get-activespace doc) blk (if (= spc 1) (vla-get-modelspace doc) (vla-get-paperspace doc) )) (if (ssget '((0 . "LINE,LWPOLYLINE,ARC"))) (progn (vla-startundomark doc) (vlax-for n (vla-get-activeselectionset doc) (setq name (vla-get-objectname n)) (cond ((member name '("AcDbLine" "AcDbArc")) (vlax-invoke blk 'addpoint (vlax-curve-getpointatparam n (/ (+ (vlax-curve-getstartparam n) (vlax-curve-getendparam n)) 2.0) ))) ((= name "AcDbPolyline") (setq end (vlax-curve-getendparam n)) (setq d 0.5) (while (< d end) (vlax-invoke blk 'addpoint (vlax-curve-getpointatparam n d)) (setq d (1+ d)) )) ) )) (vla-endundomark doc) ) (princ) )
As a demonstration, here's a speed test using a selection set of a single Line object, and slight modification to both routines to accept said selection set as an argument.
Disclaimer: If I've incorrectly modified another's code, which may be responsible for a discrepancy in performance, please correct me where I am wrong.
Speed test:
(defun _DL2 ( ss / cmde ss1) (setq cmde (getvar 'cmdecho)) (setvar 'cmdecho 0) (command "_.undo" "_begin") (setq ss1 ss) (repeat (sslength ss1) (command "_.divide" (ssname ss1 0) 2) (ssdel (ssname ss1 0) ss1) ) (command "_.undo" "_end") (setvar 'cmdecho cmde) ) (defun _PointAtMid (ss / *error* ss acDoc oSpace tab) (defun *error* (msg) (if acDoc (vla-endundomark acDoc) ) (cond ((not msg)) ; Normal exit ((member msg '("Function cancelled" "quit / exit abort"))) ; <esc> or (quit) ((princ (strcat "\n** Error: " msg " ** "))) ; Fatal error, display it ) (princ) ) (vla-startundomark (setq acDoc (vla-get-activedocument (vlax-get-acad-object))) ) (setq oSpace (apply (if (setq tileMode (= 1 (getvar 'tilemode))) 'vla-get-modelspace 'vla-get-paperspace ) (list acDoc) ) ) (vlax-for x (setq ss (vla-get-activeselectionset acDoc)) (vla-addpoint oSpace (vlax-3d-point (vlax-curve-getpointatdist x (* 0.5 (vla-get-length x))) ) ) ) (vla-delete ss) (*error* nil) ) (bench '(_DL2 _PointAtMid) '(ss) 1000)
... Results from console:
_DL2 Elapsed: 109746 Average: 109.7460 _POINTATMID Elapsed: 670 Average: 0.6700
Disregarding the Polyline support, etc... On pure performance alone, this is a no brainer... More specifically, _PointAtMid could have run +/-160 times in the same time required for _DL2 to complete only a single (1) iteration, over a single (1) line:
(bench '(_DL2) '(ss) 1) (bench '(_PointAtMid) '(ss) 200)
... Yields:
_DL2 Elapsed: 125 Average: 125.0000 _POINTATMID Elapsed: 125 Average: 0.6250
Further, while I have not made the time to check out the per-segment routine receiving such a hard-sell here (perhaps I should?), one can easily refactor my offering to allow for both total length, and per-segment point orientation as desired. Lemon squeezy.
Cheers
"How we think determines what we do, and what we do determines what we get."
Hope you don't mind guys .
(defun c:Test (/ ss i sn) (or doc (setq doc (vla-get-activedocument (vlax-get-acad-object)))) (if (setq ss (ssget '((0 . "ARC,LINE,LWPOLYLINE")))) (progn (vla-StartUndoMark doc) (repeat (setq i (sslength ss)) (setq sn (ssname ss (setq i (1- i)))) (entmakex (list '(0 . "POINT") (cons 10 (vlax-curve-getpointatdist sn (/ (vlax-curve-getdistatparam sn (vlax-curve-getendparam sn)) 2.) ) ) ) ) ) (vla-endUndomark doc) ) ) (princ) ) (vl-load-com)
Dbroad, there's no need to distinguish between ObjectNames... Consider this slight modification to my original code:
(vl-load-com) (defun c:PointAtMid (/ *error* ss acDoc oSpace) (defun *error* (msg) (if acDoc (vla-endundomark acDoc) ) (cond ((not msg)) ; Normal exit ((member msg '("Function cancelled" "quit / exit abort"))) ; <esc> or (quit) ((princ (strcat "\n** Error: " msg " ** "))) ; Fatal error, display it ) (princ) ) (if (setq ss (ssget '((0 . "ARC,LINE,*POLYLINE")))) (progn (vla-startundomark (setq acDoc (vla-get-activedocument (vlax-get-acad-object))) ) (setq oSpace (apply (if (getvar 'tilemode) 'vla-get-modelspace 'vla-get-paperspace ) (list acDoc) ) ) (vlax-for x (setq ss (vla-get-activeselectionset acDoc)) (vla-addpoint oSpace (vlax-3d-point (vlax-curve-getpointatparam x (* 0.5 (+ (vlax-curve-getstartparam x) (vlax-curve-getendparam x) ) ) ) ) ) ) (vla-delete ss) ) (prompt "\n** Nothing selected ** ") ) (*error* nil) )
"How we think determines what we do, and what we do determines what we get."
@_Tharwat wrote:Hope you don't mind guys .
(defun c:Test (/ ss i sn) (or doc (setq doc (vla-get-activedocument (vlax-get-acad-object)))) (if (setq ss (ssget '((0 . "ARC,LINE,LWPOLYLINE")))) (progn (vla-StartUndoMark doc) (repeat (setq i (sslength ss)) (setq sn (ssname ss (setq i (1- i)))) (entmakex (list '(0 . "POINT") (cons 10 (vlax-curve-getpointatdist sn (/ (vlax-curve-getdistatparam sn (vlax-curve-getendparam sn)) 2.) ) ) ) ) ) (vla-endUndomark doc) ) ) (princ) ) (vl-load-com)
Not at all, Tharwat... That's an excellent adaptation.
Cheers
"How we think determines what we do, and what we do determines what we get."
@BlackBoxCAD wrote:
@_Tharwat wrote:Hope you don't mind guys .
Not at all, Tharwat... That's an excellent adaptation.
Cheers
Thank you mate , it's very kind of you .
@BlackBoxCAD wrote:As a demonstration, here's a speed test using a selection set of a single Line object, and slight modification to both routines to accept said selection set as an argument.
....
... Results from console:
_DL2 Elapsed: 109746 Average: 109.7460 _POINTATMID Elapsed: 670 Average: 0.6700
... _PointAtMid could have run +/-160 times in the same time required for _DL2 to complete only a single (1) iteration, over a single (1) line:
(bench '(_DL2) '(ss) 1) (bench '(_PointAtMid) '(ss) 200)... Yields:
_DL2 Elapsed: 125 Average: 125.0000 _POINTATMID Elapsed: 125 Average: 0.6250....
Yes, certainly the approach used in DL2 takes longer as acknowledged, but in at least one way, that benchmark test is not a valid indicator of the time it takes either routine to mark 1000 Lines, and therefore maybe not a very meaningful comparison. It runs the entire routines 1000 times, including, in the case of _DL2, the turning off and back on of command-line echoing, and in the case of _PointAtMid, the defining and running of the error handler, and in both cases, the Undo begin/end switching, all of those occurring 999 times more than they would if either routine were used on 1000 Lines in a single selection. If the 'Elapsed' values are in milliseconds, your benchmark on _DL2 took roughly 25 times as long as it took my computer to mark 1000 Lines in a single selection ["measured" by counting off the roughly 4 seconds it took in my head, not by a benchmark test]. That would suggest to me that the 999 extra CMDECHO/Undo togglings in the benchmark test take up the great bulk of the excess time, which in turn suggests that with those occurring only once, as would be the case in actual operation, the time difference between the two routines would be considerably less. But _PointAtMid should also take less time [whether proportionally less, I couldn't say], and _DL2 will definitely still take longer. I'd be interested in the results of a similar test, using a selection set of 1000 Lines and running once.
Another consideration is whether the amount of time saved amounts to anything worth worrying about, which again depends largely on how many Lines you're likely to be marking. For the single Line, run once, again if the 'Elapsed' value is in milliseconds, _DL2 takes a very cumbersome 1/8 of a second. Even if PointAtMid takes only about 1/1300 of a second to do the same, such a time savings would be functionally meaningless to a User selecting a single Line.
@Kent1Cooper wrote:Yes, certainly the approach used in DL2 takes longer as acknowledged, but in at least one way, that benchmark test is not a valid indicator of the time it takes either routine to mark 1000 Lines, and therefore maybe not a very meaningful comparison. It runs the entire routines 1000 times, including, in the case of _DL2, the turning off and back on of command-line echoing, and in the case of _PointAtMid, the defining and running of the error handler, and in both cases, the Undo begin/end switching, all of those occurring 999 times more than they would if either routine were used on 1000 Lines in a single selection. If the 'Elapsed' values are in milliseconds, your benchmark on _DL2 took roughly 25 times as long as it took my computer to mark 1000 Lines in a single selection ["measured" by counting off the roughly 4 seconds it took in my head, not by a benchmark test]. That would suggest to me that the 999 extra CMDECHO/Undo togglings in the benchmark test take up the great bulk of the excess time, which in turn suggests that with those occurring only once, as would be the case in actual operation, the time difference between the two routines would be considerably less. But _PointAtMid should also take less time [whether proportionally less, I couldn't say], and _DL2 will definitely still take longer. I'd be interested in the results of a similar test, using a selection set of 1000 Lines and running once.
Another consideration is whether the amount of time saved amounts to anything worth worrying about, which again depends largely on how many Lines you're likely to be marking. For the single Line, run once, again if the 'Elapsed' value is in milliseconds, _DL2 takes a very cumbersome 1/8 of a second. Even if PointAtMid takes only about 1/1300 of a second to do the same, such a time savings would be functionally meaningless to a User selecting a single Line.
That's a valid argument... Repeat is quite efficient, as compared to obtaining the VL Selection Set Object, the erro handler is of little consequence, and I cannot speak for the Command invocation. I would think that the former alone you'd see similar speeds over large data sets, but that's not how most users work (with exception to the occasional batch process).
As is the case with most speed tests... Hardware configuration, and effeciency of user, and/or repeated calls will dictate, and usually lend to the speed difference being negligible in the real-world. I do it mostly to challenge myself.
In any event, this has been a fun little excercise... Makes me wonder what the gain in efficiency will be when I port this sample to .NET API. *geek*
"How we think determines what we do, and what we do determines what we get."
"Dbroad, there's no need to distinguish between ObjectNames..."
It depends on what you want to do. I do know what I'm doing. Consider the images below.
But technically there might be a problem with my last loop on polylines. I do believe it works though.
Deleting selection sets IMO is of virtually no value. AutoCAD cleans itself up.
@dbroad3 wrote:Deleting selection sets IMO is of virtually no value. AutoCAD cleans itself up.
For the purposes of truth, and clarity, I must correct my earlier statement, as it is not fully acurate... To paraphrase R. Robert Bell:
AutoCAD only supports 128 selections sets, and does clean itself up for those selection sets that are bound to a local variable, when said variable goes out of scope.
AutoCAD does not clean itself up when ActiveX selection sets are created via the Add method:
(setq foo (vla-add (vla-get-selectionsets acDoc) "foo"))
... Even when this Object is bound to a local variable, it is not automatically closed when the variable goes out of scope. This is the reason for the Delete method on created ActiveX selection sets.
This however, is not as issue when using the ActiveSelectionSet Property Object, as that is not an Object created by you, and is managed by AutoCAD.
My usage of the Delete Method stems back to when I first learned of iterating Selection Sets from Robert (I didn't know what a Defun was until litteraly a few years ago), and in that discussion, it was identified as a 'no harm, no foul' addition to one's code, thus I chose to include it regardless, but technically the Delete method is not necessary in my offering.
Sorry for any confusion my earlier statement may have caused.
"How we think determines what we do, and what we do determines what we get."
@dbroad3 wrote:
It depends on what you want to do. I do know what I'm doing.
Agreed... I never said you don't know what you're doing... I chose to offer code that does exactly what the OP requested, in lieu of what has been twice offered by others with no response from OP... Take from it what you like.
Cheers
"How we think determines what we do, and what we do determines what we get."
No problem. I typically try to leave the cleanup to the processor as much as possible. I did forget to scope a few variables that were intended to be local in the last version I posted. There was a time when storing ActiveX objects did lock up lots of storage. I believe they have fixed some of the memory problems that were prone to happen in earlier versions.
@dbroad3 wrote:No problem. I typically try to leave the cleanup to the processor as much as possible. I did forget to scope a few variables that were intended to be local in the last version I posted. There was a time when storing ActiveX objects did lock up lots of storage. I believe they have fixed some of the memory problems that were prone to happen in earlier versions.
It is always appreciated to not only see others' code, but to have an opportunity to have an honest discussion about the logic and tradeoffs of the 'how and why' behind a given implementation... Knowledge gained offers greater possability of earning wisdom.
Cheers, Dbroad
"How we think determines what we do, and what we do determines what we get."