(SSGET "_X") Rotate at angle

(SSGET "_X") Rotate at angle

Anonymous
Not applicable
1,935 Views
17 Replies
Message 1 of 18

(SSGET "_X") Rotate at angle

Anonymous
Not applicable

Hello guys,
Is there a way with the (SSGET "_X")

I rotate all my blocks in the (pline, line, arc ...) angle that the same is together.

ba.png

 

I'll attach a .dwg file that will be easier to understand.

0 Likes
Accepted solutions (3)
1,936 Views
17 Replies
Replies (17)
Message 2 of 18

Kent1Cooper
Consultant
Consultant

The problem I see is that the Blocks on one  side of each (whatever they are -- roadways?) need their rotation to be in the direction the Polyline is running, but those on the other  side need to be the opposite  direction.  Those on the "northeast" [if north is up] side of the longer route are at 140 degrees, but those on the "southwest" side are at 320 degrees, but the Polylines they lie on all run in the same  direction [320].  Can you delineate a means whereby a routine could figure out which way to turn a given Block?

Kent Cooper, AIA
Message 3 of 18

Anonymous
Not applicable

@Kent1Cooper  It makes no difference, of preference 140 degrees - But if you stay always on the internal side of my pline it will be better!

0 Likes
Message 4 of 18

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... It makes no difference.....


 

Just to confirm:  Does that mean this is an acceptable outcome, with half of the Block "inside" the route and half of them "outside"?

NoDifference.PNG

Kent Cooper, AIA
Message 5 of 18

Anonymous
Not applicable

YES!!!

0 Likes
Message 6 of 18

Anonymous
Not applicable

Could not the blocks always stay inside?



 

Just to confirm:  Does that mean this is an acceptable outcome, with half of the Block "inside" the route and half of them "outside"?

NoDifference.PNG



This result is already very good!

0 Likes
Message 7 of 18

Kent1Cooper
Consultant
Consultant
Accepted solution

Try this:

(defun C:ABP (/ ss n blk ins pathss path); = Align Block(s) to Path(s)
  (if (setq ss (ssget '((0 . "INSERT"))))
    (repeat (setq n (sslength ss)); then
      (setq
        blk (vlax-ename->vla-object (ssname ss (setq n (1- n))))
        ins (vlax-get blk 'InsertionPoint)
      ); setq
      (if (setq pathss (ssget "_C" (polar ins 0 1) (polar ins pi 1) '((0 . "*LINE"))))
        (progn ; then
          (setq path (ssname pathss 0))
          (vla-put-Rotation blk
            (angle
              '(0 0 0)
              (vlax-curve-getFirstDeriv path
                (vlax-curve-getParamAtPoint path
                  (vlax-curve-getClosestPointTo path ins)
                ); ...getParam...
              ); ...FirstDeriv
            ); angle
          ); ...put...
        ); progn
      ); if
    ); repeat
  ); if
); defun

I don't really like the Crossing-window selection of the path, because depending on the scale of things, it could find more than one path.  But when I used simply the insertion point as the pick point, it worked on only one  Block in your sample drawing, and I couldn't figure out why.  It wasn't "seeing" the path for any Blocks but the one, even when I forced Block insertion points to ensure they were truly on  the path.  I tried several variant approaches without success.  And it's not like somehow doing the first one spoiled anything for subsequent ones, because the one it worked on isn't the first or last one in the selection.  I even wondered whether the fact that the Block has an Alignment parameter could be the reason, but if so, it shouldn't have worked for any of them.

 

In case anyone has any bright ideas as to what the problem could be, what I originally had in place of this:

    (if (setq pathss (ssget "_C" (polar ins 0 1) (polar ins pi 1) '((0 . "*LINE"))))

was this:

    (if (setq pathss (ssget ins '((0 . "*LINE"))))

which did the trick for one Block [so it must have some  kind of validity], but not for the rest.

 

I even tried adding the ":E" mode in, both before and after the 'ins', but got a too-many-arguments error.  And I tried that omitting the entity-type filter, intending to remove the Block from the resulting selection, but got a bad-point-argument error.  I guess I don't really get what the ":E" mode does, or how it relates to other arguments, and Help doesn't include any examples of its use.

 

By the way, for other kinds of path objects, you can replace that (ssget) filter list with:

    '((0 . "*LINE,CIRCLE,ARC,ELLIPSE,RAY"))

[and, if necessary, do some checking later to avoid MLINEs, which such a selection would accept but which can't be aligned with using (vlax-curve...) methods].

Kent Cooper, AIA
0 Likes
Message 8 of 18

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

.... But if you stay always on the internal side of my pline it will be better!


 

That's the challenging part.  There is no "internal side" of a Polyline that is not closed.  AutoLisp can find the Polyline that a Block's insertion point lies on, but it has no way of knowing that the Polyline has any relationship to any other Polyline in the drawing.  If, as I said before, you can spell out some way that a routine might be able to recognize which side of the Polyline is the "inside" of a "path" defined by that Polyline and another one, maybe an approach can be found to have the Block rotated so that it's on that "inside" of the path.

 

But one thing you could do, that's pretty quick:  Run the routine, and for the ones that come out on the "outside," they'll all be on the same  side of their Polyline.  Use REVERSE on those Polylines, and run the routine again [you can do it on all Blocks again, or on just those Blocks].

Kent Cooper, AIA
0 Likes
Message 9 of 18

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:

....  I guess I don't really get what the ":E" mode does, or how it relates to other arguments, and Help doesn't include any examples of its use. ....


>This< seems to confirm that, unfortunately, ":E" works only in User-pick operation, not feed-in-a-point-variable use.

Kent Cooper, AIA
0 Likes
Message 10 of 18

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:
....  There is no "internal side" of a Polyline that is not closed.  ....  If, as I said before, you can spell out some way that a routine might be able to recognize which side of the Polyline is the "inside" of a "path" defined by that Polyline and another one ....

 

And now, looking back at Message 1, I see there's the possibility of Arcs  as paths, so the expanded filter at the end of Message 7 should be incorporated.

 

But the "internal side" thing would require some additional consideration with a variety of possible path types.  An Arc does  definitely have an "internal side," and unlike a Polyline, its drawn direction is always the same way [unless there are complications such as a from-underneath  Coordinate System].  But if an Arc is one side of a "path" defined by two parallel/concentric Arcs, then the Blocks should go on the inside of one and the outside of the other.  The same question applies -- how is a routine to know whether a given Arc is the inner or the outer side of a path?

 

[My suggestion involving REVERSE on Polylines would also work if the path objects are Lines or Splines, but can't be used on Arcs or Ellipses -- I do have a routine to reverse their direction, but it involves changing Arcs into Polylines and Ellipses into Splines, if that would be acceptable.  But even that won't reverse the direction of Xlines, if those are a possibility.]

Kent Cooper, AIA
0 Likes
Message 11 of 18

Anonymous
Not applicable

@Kent1Cooper wrote:

Try this:

(defun C:ABP (/ ss n blk ins pathss path); = Align Block(s) to Path(s)
  (if (setq ss (ssget '((0 . "INSERT"))))
    (repeat (setq n (sslength ss)); then
      (setq
        blk (vlax-ename->vla-object (ssname ss (setq n (1- n))))
        ins (vlax-get blk 'InsertionPoint)
      ); setq
      (if (setq pathss (ssget "_C" (polar ins 0 1) (polar ins pi 1) '((0 . "*LINE"))))
        (progn ; then
          (setq path (ssname pathss 0))
          (vla-put-Rotation blk
            (angle
              '(0 0 0)
              (vlax-curve-getFirstDeriv path
                (vlax-curve-getParamAtPoint path
                  (vlax-curve-getClosestPointTo path ins)
                ); ...getParam...
              ); ...FirstDeriv
            ); angle
          ); ...put...
        ); progn
      ); if
    ); repeat
  ); if
); defun

@Kent1Cooper 
This is already perfect !!! I will mark as a solution because it will save me many hours of work.

0 Likes
Message 12 of 18

Anonymous
Not applicable

@Kent1Cooper  Most of my polylines are closed !!
So I can find the inner side?

 

If there is such a possibility, how to do this?

 

If the number of vertices of my polyline is equal to or less than 5 rotate "outside".

If it is greater than 5 to rotate "inside".

 

attached a .dwg with the example.

 

0 Likes
Message 13 of 18

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

@... Most of my polylines are closed !!  So I can find the inner side?

If there is such a possibility, how to do this?

 

If the number of vertices of my polyline is equal to or less than 5 rotate "outside".

If it is greater than 5 to rotate "inside".

....


 

Search this Forum for things like "polyline direction" and/or "clockwise vs. counterclockwise" and/or "inside or outside polyline" and the like -- there are many threads about the subject.

 

If one is drawn counterclockwise, Blocks defined as your example Block rotated to align in the drawn direction would be inside, and turned around in the opposite direction would be outside.  If one is drawn clockwise, the reverse.

Kent Cooper, AIA
Message 14 of 18

Anonymous
Not applicable

Thank you !!!! I'll search!

0 Likes
Message 15 of 18

ronjonp
Advisor
Advisor
Accepted solution

This is how I'd tackle it to be able to pick a side:

(defun c:foo (/ _aap b bl l p p2 r s x)
  ;; RJP » 2019-05-17
  ;; Rotate a blocks to nearest polyline
  (defun _aap (e p / pa cp)
    (if	(setq pa (vlax-curve-getparamatpoint e p))
      (angle '(0 0 0) (vlax-curve-getfirstderiv e pa))
    )
  )
  (if (and (setq s (ssget ":L" '((0 . "insert,lwpolyline"))))
	   (foreach x (vl-remove-if 'listp (mapcar 'cadr (ssnamex s)))
	     (if (= "INSERT" (cdr (assoc 0 (entget x))))
	       (setq b (cons (vlax-ename->vla-object x) b))
	       (setq l (cons x l))
	     )
	   )
	   b
	   l
      )
    (foreach lwp l
      (setq r nil)
      (foreach bl b
	(setq p (vlax-get bl 'insertionpoint))
	(cond ((equal 0 (distance p (setq p2 (vlax-curve-getclosestpointto lwp p))) 1e-3)
	       (setq r (cons bl r))
	       (vla-put-rotation bl (_aap lwp p2))
	       (vla-update bl)
	      )
	)
      )
      (cond (r
	     (redraw lwp 3)
	     (while (getpoint "\nPick a point to flip sides: ")
	       (foreach x r (vla-put-rotation x (+ pi (vla-get-rotation x))) (vla-update x))
	     )
	     (redraw lwp 4)
	    )
      )
    )
  )
  (princ)
)

2019-05-17_16-29-10.gif

Message 16 of 18

Anonymous
Not applicable

@ronjonp 
Thank you very much, this will be very useful!

but I'm still trying to do something like this, is it possible ?

-If the number of vertices of my polyline is equal to or less than 5 rotate "outside".

-If it is greater than 5 to rotate "inside".

0 Likes
Message 17 of 18

Kent1Cooper
Consultant
Consultant
Accepted solution

@Anonymous wrote:

 

...

I'm still trying to do something like this, is it possible ?

-If the number of vertices of my polyline is equal to or less than 5 rotate "outside".

-If it is greater than 5 to rotate "inside".


 

Try this [minimally  tested, but seems to work in your sample drawing]:

 

(defun C:ABP (/ ss n blk ins pathss path short CW); = Align Block(s) to Path(s)
  (if (setq ss (ssget '((0 . "INSERT"))))
    (repeat (setq n (sslength ss)); then
      (setq
        blk (vlax-ename->vla-object (ssname ss (setq n (1- n))))
        ins (vlax-get blk 'InsertionPoint)
      ); setq
      (if (setq pathss (ssget "_C" (polar ins 0 1) (polar ins pi 1) '((0 . "*LINE"))))
        (progn ; then
          (setq
            path (ssname pathss 0)
            short (<= (cdr (assoc 90 (entget path))) 5)
            CW ; Polyline is clockwise [T or nil]
              (LM:ListClockwise-p
                (mapcar 'cdr ; point list of vertices
                  (vl-remove-if-not
                    '(lambda ( x ) (= (car x) 10))
                    (entget path)
                  ); ...remove...
                ); mapcar
              ); ...Clockwise... & CW
          ); setq
          (vla-put-Rotation blk
            (+
              (angle
                '(0 0 0)
                (vlax-curve-getFirstDeriv path
                  (vlax-curve-getParamAtPoint path
                    (vlax-curve-getClosestPointTo path ins)
                  ); ...getParam...
                ); ...FirstDeriv
              ); angle
              (if (or (and short CW) (and (not short) (not CW)))
                0 ; then -- path's direction
                pi ; else -- reverse
              ); if
            ); +
          ); ...put...
        ); progn
      ); if
    ); repeat
  ); if
  (princ)
); defun

;; List Clockwise-p  -  Lee Mac
;; Returns T if the point list is clockwise oriented
(defun LM:ListClockwise-p (lst)
  (minusp
    (apply '+
      (mapcar
        (function
          (lambda ( a b )
            (- (* (car b) (cadr a)) (* (car a) (cadr b)))
          )
        )
        lst (cons (last lst) lst)
      )
    )
  )
)

It uses @Lee_Mac 's clockwise-ness test [one of the more concise of many such tests out there for the Searching], from >here<.

 

[I didn't change the command name from before, but you may want to, to suit these more limited circumstances.]

Kent Cooper, AIA
Message 18 of 18

Anonymous
Not applicable

@Kent1Cooper 
Thank you very very  much!! This works well!

0 Likes