Making a script that automatically trims back intersection lines

Making a script that automatically trims back intersection lines

JBW_AIScripts
Contributor Contributor
2,203 Views
34 Replies
Message 1 of 35

Making a script that automatically trims back intersection lines

JBW_AIScripts
Contributor
Contributor

I am attempting to create a script that detects intersecting lines on a specified layer (in the code it is "LED PATH") and removes a specified amount of length from deadends in intersections. I want it to be able to work on a filtered selection and have some tolerance for line ends not being exactly on the crossing line.

For example:

Before

JBW_AIScripts_0-1735675982918.png

After

JBW_AIScripts_1-1735676088437.png

 

I have comments in my attempted code that explains my thought process for how to achieve my desired results but the syntax is all messed up.

 

I think the biggest problems I am facing involve the syntax for creating a polygon point list to check for intersecting lines and if the lines are far enough away to stop trimming. I suspect I can't call commands inside a function that returns a value directly to another command, and also that my point list loop is not using "append" correctly.

 

Thanks for any help or insights you can offer!

0 Likes
Accepted solutions (4)
2,204 Views
34 Replies
Replies (34)
Message 2 of 35

Kent1Cooper
Consultant
Consultant
Accepted solution

A couple of things....

I think you can do without the (splp) function, if you use LENGTHEN with the Delta option and with a negative Delta value.  LENGTHEN won't make a Spline longer, but it will make it shorter.  That would mean you don't need to check whether an object is a Spline, but could just use what you have in the 'else' argument in (pacman) for any object type.  Without studying it in detail, I think it would just mean reversing the arguments in the (angle) function in setting the 'dir' variable.

But if you keep the (splp) function, yes, the syntax is wrong in using it.  This:

(setq outlist splp(obj pt1))

should have one of its parentheses in a different place:

(setq outlist (splp obj pt1))

[I haven't studied (pacman) and its application enough to say whether there might be a better way to find what it's made to look for.]

A small thing:  This, for setting the negative Delta value in LENGTHEN:

(- 0 (/ td p))

can be simply:

(- (/ td p))

A (-) function with only one argument makes the negative of that argument, without the need to explicitly subtract it from zero.

In your R shape in the drawing, the P-shaped red part is a Polyline that dead-ends on itself.  Is it going to be a problem that searching around that endpoint finds something but not a different something than the object in question?  [Maybe I can figure that out if I study (pacman) further.]

In the (repeat) function that starts at line 42, you have (if) functions that are given more than the maximum two arguments they can take.  You need some (progn) wrappers to make some of those multiple operations into single arguments.

Kent Cooper, AIA
0 Likes
Message 3 of 35

JBW_AIScripts
Contributor
Contributor

Thanks for your reply! That is a big help. I knew about the (progn ) wrappers but I totally forgot to apply them there. Good catch!

 

I came up with the "pacman" shape for the selection window in order to exclude the end of the line to be trimmed from the selection, thus being able to detect itself for intersections, as you noted in the "P" shape in the "R." In order for it to really work, the selection window needs that tiny bit of separation from the end it is checking to make sure it is not crossing that end. Also, the circular part of the shape gives a tolerance for the deadend of the intersection to not be exactly on the line(s) that cross there, making the script more user-friendly.

 

Is there a way to get a tangent direction from the endpoint of a curve (including splines) without my lengthening workaround? If so, I could generate that point without calling commands in the subfunction that reports the point list and I would really have no need for splp.

0 Likes
Message 4 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

.... Is there a way to get a tangent direction from the endpoint of a curve (including splines) without my lengthening workaround? ....


Yes.  If 'obj' is the VLA-object conversion of the path object, and 'pt' is the endpoint in question, then this:

(angle '(0 0) (vlax-curve-getFirstDeriv obj (vlax-curve-getParamAtPoint obj pt)))

will give you the direction it's headed at that point, in radians.  If it's at the start of the object, that will aim along it; if the end, away from it.  You'll find many examples of this kind of first-derivative usage for object direction in this Forum.

For one way of determining whether you're at the start or end of a path object, you can see PolylineContinue.lsp, >here<.

Kent Cooper, AIA
0 Likes
Message 5 of 35

JBW_AIScripts
Contributor
Contributor

Thank you! I'm going to try to work that in.

 

Here's a diagram of the selection window I'm trying to use to capture crossing lines. The (pacman) function generates an approximation of the yellow shape as a point list that the (ssget) can use as a selection window.

JBW_AIScripts_0-1735826130810.png

0 Likes
Message 6 of 35

JBW_AIScripts
Contributor
Contributor

Updated version-

 

A few things have been fixed with help from @Kent1Cooper. I removed the (splp) and (pointcast) subfunctions as they are pointless workarounds for the (polar) function and the tangent angle reporter.

 

I am now trying to troubleshoot why it is giving me a "bad argument type: numberp: nil" error.

 

I still need help getting (pacman) to work. My main suspect for what is wrong is still the way I attempted to append the points together in a list.

 

Also, does the polar command need the direction reported in a certain value range, such as 0 to 2pi? If so, is there an operator that translates out-of-range numbers back into that range?

0 Likes
Message 7 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

.... does the polar command need the direction reported in a certain value range, such as 0 to 2pi? ....


No, it will accept angles of greater than 2pi radians.

Kent Cooper, AIA
0 Likes
Message 8 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

....

I still need help getting (pacman) to work. My main suspect for what is wrong is still the way I attempted to append the points together in a list.

....


UNTESTED, and even if correct, there may also be other issues, but try replacing this much:

 

(setq outlist pt2) ;; Set first point - center of "Pac-Man"
(setq j 0)
;; Generate point list from data shaped like "Pac-Man" with a "mouth" angle of 120 degrees, facing the endpoint
(repeat 20 ;; 10 times per side
  (setq outlist
    (append
      (list outlist)
      (list (polar ....

 

with this:

 

(setq outlist (list pt2)) ;; Set first point into a list - center of "Pac-Man"
(setq j 0)
;; Generate point list from data shaped like "Pac-Man" with a "mouth" angle of 120 degrees, facing the endpoint
(repeat 20 ;; 10 times per side
  (setq outlist
    (append
      outlist
      (list (polar ....

Kent Cooper, AIA
0 Likes
Message 9 of 35

JBW_AIScripts
Contributor
Contributor

Oh good. What about negative values? For example, -pi?

0 Likes
Message 10 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

Oh good. What about negative values? For example, -pi?


You can try it yourself easily enough, but yes, it will take negative values.  But -pi is not a valid format as it would be for a raw number with a minus sign preceding -- rather, it would need to be (- pi).

Kent Cooper, AIA
0 Likes
Message 11 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

.... Here's a diagram of the selection window I'm trying to use to capture crossing lines. The (pacman) function generates an approximation of the yellow shape as a point list ....


Another [and I think simpler] approach you could take:  Build a simple Crossing window around the endpoint in question [only two points needed], letting the object in question be part of the resulting selection.  Then if it finds more than one thing, remove the object in question from the set, or if it finds only one, then it must be dead-ending on itself, however you want to handle that.

Kent Cooper, AIA
0 Likes
Message 12 of 35

JBW_AIScripts
Contributor
Contributor

I have examined the logic of how that would work and I'm not convinced it would work for this application. I still need help ensuring my code can be run. It seems that the error is coming from trying to get my selection, and I'm unsure if my (pacman) point list is the problem.

0 Likes
Message 13 of 35

Sea-Haven
Mentor
Mentor

I use the method Kent is talking about all the time I drew 2 lines a "T" so the vertical leg returned an entity <Entity name: 80200220>, I then did a ssget "F" using 2 points and got 2 objects selected. Looking deeper the 2 objects entity names were <Entity name: 80200220> & <Entity name: 80200160> so you can clearly see the vertical leg is matching in the selection set. Just reset the end point to be shorter for entity <Entity name: 80200220>. If only one entity then you have a gap or its an open end, skip do other end etc. 

 

Ps I normally do a 4 point box with ssget "F" Pts

0 Likes
Message 14 of 35

john.uhden
Mentor
Mentor

@JBW_AIScripts ,

I am confused by what you show as "before" vs. what you show (not identified, but presumed to be "after.")

Are you trying to create the centerlines (red) of each element of the outline (white)?

If so, the only thing I see as being "wrong" is that the top most red line should be parallel to the top outside.

Or, more to the point, are we starting off with just the white outline, and we want to create the red centerline?

Are we trying to make a stick figure of the character, and if so, then for what purpose?  Can't you just change the font?

IOW, are we trying to create a collection of polylines, or lines and arcs, or a text entity?

John F. Uhden

0 Likes
Message 15 of 35

Sea-Haven
Mentor
Mentor

Is to do with CNC cutting lettering ?

0 Likes
Message 16 of 35

JBW_AIScripts
Contributor
Contributor

Hopefully this clears up some confusion.

 

I am trying to detect if the end of a red line is close to being in a T with another red line or with itself. I want it to leave ends alone that intersect or are close to a white line.

 

In order to ensure the line can detect if it is crossing itself, it has to be a able to distinguish between the end point and the crossing section. A simple ssget that includes both or just one will add that entity either way, meaning it cannot detect the type of intersection I am looking for.

 

That's why I want the "Pac-Man" shaped selection window. It excludes the deadend of the line from the selection, creating the distinction necessary to create that space.

0 Likes
Message 17 of 35

JBW_AIScripts
Contributor
Contributor

The idea is to shorten lines that already exist. I am not drawing any new lines. The difference between the pictures is that red lines that end on/near red lines need to be shortened by a user-supplied amount from the "crossing" point. Ends of lines that are not near red lines need to be left alone.

 

The examples show one end of a red line near another red line, one red line with both ends near red lines, and a red line with one end crossing itself. All of these ends need to be shortened as seen in the "after" picture. All other ends of these lines need to be left alone. There is also a red line that has no ends in intersections with any red lines - this should be totally left alone.

0 Likes
Message 18 of 35

JBW_AIScripts
Contributor
Contributor

No. This is for placing lighting modules. I'm trying to simplify and speed up the process of drawing a lighting diagram.

0 Likes
Message 19 of 35

Kent1Cooper
Consultant
Consultant

@JBW_AIScripts wrote:

....

I am now trying to troubleshoot why it is giving me a "bad argument type: numberp: nil" error.

....


Back to this....  Can you narrow down where in the sequence of operations that error occurs?  I'm looking at potentially this:

(if (< (sslength csel) 1) (setq enN nil))

The 'csel' variable is a selection set from (ssget).  But if there are no qualifying objects in its search, 'csel' will not be a selection set with nothing in it [of length less than 1] -- it will be nil.  That would explain the error message if it doesn't find anything, whether that's because there's nothing to find or because the (pacman) function isn't working right.  Since I assume there will be something to find in your trials, it seems likely a problem with the subroutine.  I see at least two corrections suggested earlier that haven't been incorporated yet, about the 'outlist' variable and adding to it.

 

And some comments:

 

You don't need the -4 <AND> wrapping around the Layer and object-type entries in the (ssget) filter list.  Just this:

(setq sel

  (ssget
    '(
      (8 . "LED PATH")
      (0 . "LINE,ARC,LWPOLYLINE,POLYLINE,SPLINE")
    )
  )
)

[I think it's "traditional" to put the 0 entry before the 8 entry, but I don't think it matters.]

 

No, it is not necessary to define pi -- that's a predefined symbol in AutoLisp.

Kent Cooper, AIA
0 Likes
Message 20 of 35

JBW_AIScripts
Contributor
Contributor

Here's my latest attempt - I made the "pacman mouth" 90 degrees and reduced the number of points, plus implemented everything you said. I have a comment for where it seems to stop working.

0 Likes