Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Is there a way to subtracting a line from a line?

16 REPLIES 16
SOLVED
Reply
Message 1 of 17
alexanderKPNQU
1272 Views, 16 Replies

Is there a way to subtracting a line from a line?

Quick question here. I have looked around and have not found what I am looking for. 

(using AutoCAD 2020)

 

I am interested to know if there is a way to subtract one line from another. 

 

For example, I draw a line/polyline that is 5 units long. Above this line/polyline, I draw another line/polyline that is 4 units long, one unit shy from completely covering the remainder of the line/polyline. Is there a command or common lisp to subtract the line/polyline above from the line/polyline below leaving a line/polyline that is 1 unit long?

 

Thank you for the help.

Labels (3)
16 REPLIES 16
Message 2 of 17

@alexanderKPNQU ,

 

Is grips, trim, or lengthen not an option.



Please select the "Accept as Solution" button if my post solves your issue or answers your question.


Emilio Valentin
Message 3 of 17

Emilio Valentin thank you for the reply.

 

Yes, you are right. Doing this just a few times would be easy enough.

 

I should have mentioned that I need to do this too many lines at once. Sometimes hundreds.

 

I have a bit of a dirty workaround now. I was just hoping to find a way to clean up my drawing.

 

Thanks

 

 

Message 4 of 17


@alexanderKPNQU wrote:

.... I am interested to know if there is a way to subtract one line from another. ....


[EDIT: Written before seeing Message 3, but anyway, as a start...]

Here's a way, in simplest terms:

 

(defun C:SOL ; = Subtract Overlapping Line
  (/ ss line1 line2 longer shorter)
  (prompt "\nTo Subtract a shorter Overlapping [Poly]Line from a longer one,")
  (if
    (and
      (setq ss (ssget "_:L" '((0 . "LINE,*POLYLINE"))))
      (= (sslength ss) 2)
    ); and
    (progn ; then
      (setq line1 (ssname ss 0) line2 (ssname ss 1))
      (if (> (getpropertyvalue line1 "Length") (getpropertyvalue line1 "Length"))
        (setq longer line1 shorter line2); then
        (setq longer line2 shorter line1); else
      ); if
      (command "_.break" longer (vlax-curve-getStartPoint shorter) (vlax-curve-getEndPoint shorter))
    ); progn
  ); if
  (princ)
); defun

 

Either "line" can be either a Line or a Polyline of any variety.  If needed, it could be made to verify that the two objects actually overlap, and/or for either that if it's a Polyline, it's of one line segment only, or if in multiple segments that they are collinear.

Kent Cooper, AIA
Message 5 of 17

Kent Cooper,

 

Thanks for the help.

 

I must have loaded in the command wrong or I am using it incorrectly. Please let me know where I went astray. 

 

- Pasted the command into notepad and saved it as a LISP file format.

- Loaded it via APPLOAD

- Typed in command SOL with two lines selected. Also, I typed in command SOL then selected both lines. Both times nothing seemed to happen.

 

Am I missing something?

 

Thanks again

 

 

 

Message 6 of 17

It won't look like anything happened, but if you select the originally-longer Line/Polyline afterwards, is it still full length?

 

I think the only situation in which you would see a visible change would be if the two objects are different colors and the longer one is "on top" so that you don't see the shorter one "under" it, but after the command would see it because that part of the longer one has been cut away.

 

[It is designed for selection of objects after calling the command, but it could be made to work with a pre-selection instead.]

Kent Cooper, AIA
Message 7 of 17

Kent Cooper,

 

Just so you know how items are set up.

 

A long line (5 units) is above a shorter line (4 units). Both are different colors. 

 

After I run the command, SOL, then select both lines and press enter. Both lines are still their starting length.

 

When I run the command the two lines are still the same length. One that is 5 units and the other that is 4 units and not one 1 unit line and one 4 unit line.

 

Message 8 of 17

It doesn't do that for me.  Post the command-line history when you run it -- does it look any different from this?

 

Command: SOL
To Subtract a shorter Overlapping [Poly]Line from a longer one,
Select objects: Specify opposite corner: 2 found {I picked with a Crossing window}

Select objects: {Enter to complete selection}

_.break
Select object:
Specify first break point:
Specify second break point:

 

EDIT:  Does it make any difference if you ensure that Object Snap is off first?  I'm skeptical, because I would think it's very common to have ENDpoint included in your running Osnap modes, in which case it shouldn't matter.  But if you had, for instance, MIDpoint mode on and not ENDpoint, it might not remove anything from the longer line, though it should still break it into two pieces.

Kent Cooper, AIA
Message 9 of 17

Kent Cooper,

 

The problem must rest on my end somehow.

 

The commands I have are listed below:

 

Command: <Osnap off> (I turned of OSNAP just in case)
Command: SOL
To Subtract a shorter Overlapping [Poly]Line from a longer one,
Select objects: Specify opposite corner: 2 found (Like you I window selected both lines. While the lines are highlighted I pressed enter to complete the command)
Select objects:
_.break
Select object:
Specify first break point:
Specify second break point:

 

After I run the command I still have my two lines, both the same length they started.

Message 10 of 17

Very puzzling.  I would ask whether a Layer is locked, but the selection function prevents that.  Can you post a small drawing file in which this happens?

Kent Cooper, AIA
Message 11 of 17

Kent,

 

Easy enough.

 

Attached is a file that I created and tried the LISP with no results.

 

Seems strange I cannot get it to work on my end.

Message 12 of 17
hak_vz
in reply to: alexanderKPNQU

@Kent1CooperI think you need to add this line at the end

 

(entdel shorter)

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
Message 13 of 17

Well, duh on me....  Correct this:

 

      (if (> (getpropertyvalue line1 "Length") (getpropertyvalue line1 "Length"))

 

to this:

 

      (if (> (getpropertyvalue line1 "Length") (getpropertyvalue line2 "Length"))

 

[1 to 2 in the second (get...) function].

 

I copied that second function from the first, and failed to change the number.  It must have been a coincidence in the drawing order of the lines I tried it on that allowed it to work.  As it was, it was not simply not shortening your longer line, but it was eliminating the shorter one [breaking it from end to end of the longer one]!

 

Now the challenge will be to figure out how to let you choose larger numbers of lines collectively, and do this to the overlapping ones.  The difficulty will be in determining which of them overlap with which others.

Kent Cooper, AIA
Message 14 of 17

Kent,

 

This works like a charm! The shorter line is being subtracted from the longer!

 

It also looks like I can only do it two lines at a time.

 

You have already been very generous with your time but, do you know of a way for me to do this to many sets of lines at once?

 

If you take the file I sent over. Is there a way for me to run the operation on all of the lines simultaneously?

 

Thanks again for all the help.

Message 15 of 17
alexanderKPNQU
in reply to: hak_vz

I went ahead and added this to the back of the code. It is a nice addition.

 

Thank you.

Message 16 of 17


@alexanderKPNQU wrote:

.... do you know of a way for me to do this to many sets of lines at once? ....


Well, here's another curiosity, this time without a stupid-me solution.  I worked something up, and tested it in your sample drawing, but it didn't work -- no apparent effect on any of the Polylines.  It occurred to me to wonder whether they were not overlapping accurately enough, so I applied a "quantizing" routine I have that forces endpoint coordinates to the nearest multiple of a specified increment [I used 1 drawing unit, because all yours were drawn to that increment].  Then it worked:

SOL.gif

And it works on things that I draw to try it on, in the same drawing.

 

But I backed up to your drawing's original state when it didn't work, and looked at the coordinates of your objects, and they were already far more precisely where they should be for overlapping than the code asks for, and just as accurate as they appear after my quantizing routine is applied.  So it doesn't look like the quantizing routine moved any of the endpoints, at least not down to 8 decimal places, yet before doing that, it didn't work, but after doing that, it did.

 

I'm at a loss to explain what made the difference.  But anyway, here it is:

 

(defun C:SOL (/ isOn overlap ss inc line1 line2 longer shorter)

  (defun isOn (pt lin / s e) ; is the point on the line?
    (setq
      s (vlax-curve-getStartPoint lin)
      e (vlax-curve-getEndPoint lin)
    ); setq
    (or ; [(angle) of 2 points at same location always 0]
      (equal pt s 1e-3); at start
      (equal pt e 1e-3); at end
      (equal (angle s pt) (angle pt e) 1e-3); between ends
    ); or
  ); defun

  (defun overlap (line1 line2 / s1 e1 s2 e2); Lines/1-line-segment Polylines only
    (setq
      s1 (vlax-curve-getStartPoint line1)
      e1 (vlax-curve-getEndPoint line1)
      s2 (vlax-curve-getStartPoint line2)
      e2 (vlax-curve-getEndPoint line2)
    ); setq
    (or
      (and (isOn s1 line2) (isOn e1 line2))
      (and (isOn s2 line1) (isOn e2 line1))
      (and
        (isOn s1 line2) (not (or (equal s1 s2 1e-3) (equal s1 e2 1e-3)))
        (equal (angle e1 s2) (angle e1 e2) 1e-3)
      ); and
      (and
        (isOn e1 line2) (not (or (equal e1 s2 1e-3) (equal e1 e2 1e-3)))
        (equal (angle s1 s2) (angle s1 e2) 1e-3)
      ); and
    ); cond
  ); defun

  (prompt "\nTo Subtract shorter Overlapping [Poly]Lines from longer ones,")
  (if
    (setq ss
      (ssget "_:L"
        '(
          (-4 . "<OR")
            (0 . "LINE")
            (-4 . "<AND") (0 . "LWPOLYLINE") (90 . 2) (42 . 0.0) (-4 . "AND>")
          (-4 . "OR>")
        )
      ); ssget
    ); setq
    (progn ; then
      (while (> (sslength ss) 0); still any left
        (setq line1 (ssname ss 0) inc 0)
        (while (and (setq line2 (ssname ss (setq inc (1+ inc)))) (not (overlap line1 line2))))
        (if line2
          (progn ; then
            (if (> (getpropertyvalue line1 "Length") (getpropertyvalue line2 "Length"))
              (setq longer line1 shorter line2); then
              (setq longer line2 shorter line1); else
            ); if
            (command "_.break" longer
              (vlax-curve-getStartPoint shorter)
              (vlax-curve-getEndPoint shorter)
            ); command
            (ssdel line1 ss) (ssdel line2 ss); remove both from set
            (entdel line2)
          ); progn
          (ssdel line1 ss); else -- didn't find one overlapping with this one - remove from set
        ); if [found an overlapping one]
      ); while
    ); progn
  ); if

  (princ)
); defun

 

It limits Polylines to those of only a single line segment, so as not to deal with the need to verify that one with multiple segments is collinear.

Kent Cooper, AIA
Message 17 of 17

Kent,

 

What a dream! This works great. All the kudos I have are being sent your way!

 

Thanks again!

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report