Jump to content

From Centre of the Block draw a polyline to another polyline and to land at 30 degree.


Recommended Posts

Posted

Hi Everyone, 

This forum is the best as everyone is so helpful. I had this crazy idea of a lisp that you will select a number of blocks (Gullies) and a number of polylines (Pipes). Then the lisp will draw a polyline from the centre of the block (gully) towards the polyline nearest to it and land at 45 degree angle.

I do not even have the slightest idea how do I tackle a problem like this. So any help or guidance is appreciated.

Thank you.

Screenshot 2025-05-05 120126.png

Posted

Can you post a .dwg?

  • Like 1
Posted

Sure,

that's not so cazy.

It's just a little vague.  

It would be nice to see dwg example.

 

A few things: you should draw your blocks so that the grip point is in the center. 

And what about those 45° (or 30° in the title) angles?  Is that in any direction?  Any point on the polyline has 4 directions where the block could be on ...  

Posted (edited)

Hi
The first thing, I suppose, is to select the block to consider and its reference point.
Then you should create a set with all the polylines.
From there:
- Analyze each polyline in the set and obtain each of its segments to check if it is possible, from the block's reference point to any point on the segment, to create a vector that forms a 45° angle with it.
- In each case where this occurs, store the vector's point of convergence on the segment + the vector's length in a list.
- When the process is complete, sort the resulting list with 'vl-sort' from shortest to longest: the first element of the resulting list will contain the point from which to draw the line between the block and the correct polyline.

Edited by GLAVCVS
  • Like 1
Posted

Of course: to do this you must first design a function that is capable of returning the point on any segment where what you are looking for might occur. Or else, nil

Posted

Like others having done drainage design. You can get Closestpointto using VL. But as I said in drainage design a Gully joins to a certain pipe not a random one. So you could pick gullys then pick a pipe. The pipe would need to be drawn in the downhill direction so that solves the joining direction.

 

Need to take into account are pipes lines or plines. I may have a play given time.

 

Have a look at "Civil Site design" it has a drainage module, Get pit areas, interactive design of pipe sizes and grades, multiple pit types plot long sections and so on. For Civ3D and Bricscad. https://www.youtube.com/watch?v=sIMfK63yIEk got to the 40 minute mark to see drainage.

  • Like 1
  • 3 weeks later...
Posted

Thanks everyone for the response. Attached dwg.

 

BIGAL, yes! The idea is to select gully blocks (using selectsimilar command) and then select the main pipe run and then draw lines from the gully into that pipe at the 45 degree angle. The pipe is a polyline and polyline have directions, is there a function for a lisp to read the polyline direction to identify which way the gully to connect to?

 

GLAVCVS, thank you the pseudo code break down make the problem more digestible now!

 

image.thumb.png.4fd85022c534b9e15f3f153e64b76d2e.png

Gully to Pipe Example.dwg

Posted

I guess the necessary question in this case is: how do you identify the direction of the polyline? Does it correspond to the order of the points in the drawing's database?

Posted

Ok a few issues I joined all the plines into one else code fails. The code uses a very simple method of working out connection point, the issue is when a join is just past a vertice then angel will not be 45 so need a different approach.

 

In this image can see the 2 answers as the 45 line meets either before or after a vertice so it would make sense at the vertice there is a PIT for change of direction of the pipe so use that point.

 

image.png.85efa3daa771380ecc4bff02aa792fba.png

 

Can you comment please.

 

Something to play with.

(defun c:gully45 ( / )
(setq obj2 (vlax-ename->vla-object (car (entsel "\nPick drain line "))))
(while (setq ent (car (entsel "\nPick block object ")))
(setq obj1 (vlax-ename->vla-object ent))
(setq inspt (vlax-get obj1 'insertionpoint))
(setq objpt (vlax-curve-getclosestpointto obj2 inspt))
(setq dist (distance inspt objpt))
(setq dist2 (vlax-curve-getdistatpoint obj2 objpt))
(setq dist2 (+ dist2 dist))
(setq pt2 (vlax-curve-getpointatdist obj2 dist2))
(command "line" inspt pt2 "")
)
(princ)
)
(c:gully45)

 

  • Like 1
Posted (edited)

One approach to finding the desired point on each of the nearby segments could be as follows:
- Obtain the block's insertion point (p0)
- Obtain the first (p1) and second (p2) points of the segment, in the direction of the polyline.
- Determine whether it is possible to find a point along the segment that, together with p0 and p1, forms a 45° angle.

To do this,
  1) calculate the angular direction from p1 to p2, from p0 to p1, and from p0 to p2 using the 'angle' function.
  2) calculate the range of possible angles for that segment. From p0 to p1 and p2, it will be:
    • for p1 (ap1), the absolute value of the difference between the angles p1-p2 and p0-p1; and...
    • for p2 (ap2), the absolute value of the difference between the angles p1-p2 and p0-p2

    (Note: if ap1 or ap2 are greater than π, it will be necessary to adjust them by subtracting their value         from 2π)
  3) If ap1 is greater than π/4 and ap2 is less than π/4, then the segment IS VALID for our purposes and we will proceed to calculate that point (this is easy and you should be able to do it yourself)

 

-Once the point is calculated, we add it to a list (lstPtsSgmt) where, next to the calculated point, we will add the distance from it to p0. The list lstPtsSgmt might look something like '(((x1 y1) d1) ((x2 y2) d2) ((x3 y3) d3)...)'

- Once we have this list, we apply 'vl-sort' to it to sort it by distance, from lowest to highest: the first member of the resulting list will contain the point we are looking for.

Edited by GLAVCVS
Posted

As I mentioned in my previous comment, you first need to know how to determine the direction of the polyline.
And, of course, the variable names are for guidance only.

Posted

Hi BIGAL, I suppose if the 45 degree line is outside the polyline segment then we can tell it to join the vertex point of that polyline.

 

GLAVCVS, I assumed that since there is a reverse command for a polyline then surely there must be somewhere where that variable is stored. I suppose the only perquisite of the lisp is that the user drew the polylines correctly in terms of direction.

 

Thank you so much for all the help. I will try and have a stab at the writing the full lisp app and can post it here for feedback. 

Posted

As mentioned by @GLAVCVS you can get a pline segment. so when calculate the nearest point, get the segment, if length exceeds what length is left of that segment, so go to next segment at 45 or go to vertice.

 

Have a go come back if you get stuck.

 

 

Posted

@GLAVCVS this what I use to determine direction pick an end of a pline.

 

(setq ent (car (entsel "\nPIck a pline near end ")))
(setq obj2 (vlax-ename->vla-object  ent))
(setq start (vlax-curve-getstartPoint obj2))
(setq end (vlax-curve-getEndPoint obj2))
(setq d1 (distance pt start))
(setq d2 (distance pt end))
(if (< d1 d2)
(command "pedit" ent "R" "")
)

 If using a line then look at object type and can just redo the line by swapping start and end endpoints. In Briscad there is no reverse command. So use a pedit for plines.

 

Posted (edited)

 

10 hours ago, BIGAL said:

@GLAVCVS this what I use to determine direction pick an end of a pline.

 

(setq ent (car (entsel "\nPIck a pline near end ")))
(setq obj2 (vlax-ename->vla-object  ent))
(setq start (vlax-curve-getstartPoint obj2))
(setq end (vlax-curve-getEndPoint obj2))
(setq d1 (distance pt start))
(setq d2 (distance pt end))
(if (< d1 d2)
(command "pedit" ent "R" "")
)

 If using a line then look at object type and can just redo the line by swapping start and end endpoints. In Briscad there is no reverse command. So use a pedit for plines.

 

 

I think I misunderstood  @CivilTechSource 's request. I thought it was about drawings with multiple blocks and polylines, where they wanted to automate the task by minimizing user intervention.
So, perhaps it's also about selecting the block on the screen to which the polyline will be associated.
I think it's a more prudent approach.

 

Edited by GLAVCVS
Posted

It is about drawing road drainage. When exceeds a nearest segment need a choice change angle, join vertice, or downstream at 45 to next segement.

  • 2 weeks later...
Posted

@GLAVCVS Actually you did not misunderstood, automating by selecting from a list of blocks and polylines is actually quite useful! The below is what I managed to get from Gemini(AI). It works quite well to draw straight lines which is half the job, the other half is rotating. I am still writing the full code to check the angle and Join vertice as @BIGAL mentioned.

 


(defun c:LE-Line90 ( / ssBlocks ssPolys iBlock entBlock ptBlock
                            jPoly entPoly minDistance closestPointOnPoly
                            currentClosestPoint currentDistance
                            )
  (vl-load-com) ; Load Visual LISP extensions for COM functions

  ;; --- Step 1: Prompt user to select multiple blocks ---
  (princ "\nSelect Blocks (press Enter when done): ")
  (setq ssBlocks (ssget '((0 . "INSERT")))) ; Select multiple entities of type INSERT (block)

  (if ssBlocks
    (progn
      (princ (strcat "\n" (itoa (sslength ssBlocks)) " block(s) selected."))

      ;; --- Step 2: Prompt user to select multiple polylines ---
      (princ "\nSelect Polylines (press Enter when done): ")
      ;; Allow selection of LWPOLYLINE (2D polyline) and POLYLINE (old style 2D/3D polyline)
      (setq ssPolys (ssget '((0 . "*POLYLINE"))))

      (if ssPolys
        (progn
          (princ (strcat "\n" (itoa (sslength ssPolys)) " polyline(s) selected."))

          ;; --- Step 3: Iterate through each selected block ---
          (setq iBlock 0)
          (while (< iBlock (sslength ssBlocks))
            (setq entBlock (ssname ssBlocks iBlock)) ; Get entity name of the current block
            ;; Get insertion point (center) of the block. For a block, this is typically its origin.
            (setq ptBlock (cdr (assoc 10 (entget entBlock))))
            (princ (strcat "\nProcessing block at: " (vl-princ-to-string ptBlock)))

            ;; Initialize variables for finding the closest point for the current block
            (setq minDistance nil)
            (setq closestPointOnPoly nil)

            ;; --- Step 4: Iterate through each selected polyline to find the closest point ---
            (setq jPoly 0)
            (while (< jPoly (sslength ssPolys))
              (setq entPoly (ssname ssPolys jPoly)) ; Get entity name of the current polyline

              ;; Get the closest point on the current polyline to the block's center
              ;; vlax-curve-getClosestPointTo returns a 3D point
              (setq currentClosestPoint (vlax-curve-getClosestPointTo (vlax-ename->vla-object entPoly) ptBlock))

              ;; Calculate the distance from the block's center to this closest point
              (setq currentDistance (distance ptBlock currentClosestPoint))

              ;; Check if this is the closest point found so far
              (if (or (null minDistance) (< currentDistance minDistance))
                (progn
                  (setq minDistance currentDistance)
                  (setq closestPointOnPoly currentClosestPoint)
                )
              )
              (setq jPoly (1+ jPoly)) ; Move to the next polyline
            ) ; End while (jPoly loop)

            ;; --- Step 5: Draw the new polyline if a closest point was found ---
            (if closestPointOnPoly
              (progn
                (princ (strcat "\nDrawing polyline from block to closest point: " (vl-princ-to-string closestPointOnPoly)))
                ;; Draw 2D polyline from block center to the closest point found on any polyline
                (command "._PLINE" ptBlock closestPointOnPoly "")
                (princ "\nPolyline drawn successfully for current block.")
              )
              (princ "\nNo closest point found on any selected polyline for the current block.")
            )
            (setq iBlock (1+ iBlock)) ; Move to the next block
          ) ; End while (iBlock loop)
          (princ "\nAll blocks processed.")
        )
        (princ "\nNo polylines selected. Aborting.")
      )
    )
    (princ "\nNo blocks selected. Aborting.")
  )
  (princ) ; Suppress the last expression's return value
)

;; Provide a command alias for easier use
(princ "\nType 'DRAWCLOSESTPOLY' to run the LISP routine.")
(princ)

 

Posted

There's something I don't understand: what happens if the polyline can't be rotated to the required angle on the selected segment?
Is that never going to happen?

Posted

@GLAVCVS It would join the end vertex of the closest polyline segment.

Posted

So the real approach is to find the closest segment and define, at the intersection on it, the angle closest possible to those 45º

  • Like 1

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