Author Topic: Code to auto-update blocks. . . help?  (Read 10318 times)

0 Members and 1 Guest are viewing this topic.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« on: July 05, 2005, 11:18:18 AM »
I would like to write a LISP and would really appreciate some help (to be honest – this will be the first time I’ve really attempted to write one – I have always been able to find one already written before).

PSEUDOCODE:
Program ‘annotatep’
1.   User chooses polyline as an object (ensure object is polyline)

Program ‘annotate’
1.   Let user choose point on polyline (ensure point is on polyline)
2.   Insert block ‘anno’ at point
  a.   Predefined block has text in it including an integer (ex. “Air Release Valve Sta. 200")
  b.   Value of integer should be the distance from the beginning of the pline to the insertion point of the block on the pline
3.   If block is moved along pline, update integer field (only if insertion point of block is on polyline)


MY FIRST ATTEMPT (OK, so I have a LONG way to go):
Code: [Select]

(vl-load-com)

; Program loops until user selects a polyline
(defun c:annotatep ( \ obj pline)
  (while type( = pline ???)
    (setq obj (car (entsel “\n Select polyline: “)))
    (setq anno_pline (vlax-ename->vlax-object obj))
  )
)


; Determines if point ‘pt’ is on the polyline
(defun c:pointOnLineCheck (pt)

)


(defun c:annotate (userPt)
  (if anno_pline ; check to see that pline has been selected
   (progn

    ;; loop until user picks point on polyline
    (while (= -1 pointOnLineCheck(userPt))
      (setq userPt (getpoint “\n Pick a point on the polyline: “))
    ) ; end while

    ;; insert block ‘anno’ at point ‘userPt’
    (command insert ? ? ? ) ; bad to use 'command' with VLISP I think


    ; determine distance along pline to selected point
    (vlax-curve-getdist distOnPline ? ? ?)


    ;update block to reflect distance along curve ? ? ?
    ; use field/rtext/reactor?


   )
  princ “A polyline has not been selected with ANNOTATEP”)
)




OK, well anyone care to throw a bone? (with some meat on it)?  I plan on writing this code until it works, even if it takes me all month of working on it here and there and learning the language.  I told my boss how I wanted to automate some of the work we do and he just laughed at me like “Yeah, that’s nice and after you’re done dreaming just finish it OK?”

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #1 on: July 05, 2005, 12:37:55 PM »
First, ask yourself, what's TYPE going to return? Check the help files for this. You won't see that it returns a PLINE or any specific object type. To get a specific object type, use (ssget ":S" '((0 . "*POLYLINE"))). You can use entsel or nentsel, but it takes more work to get the filter working.

What is the point going to represent on the pline? Take note that a point is a set of coordinates in space, not on an object. If you have overlaps, you could inadvertently pick a different object if you intend to use these coords for selecting objects.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #2 on: July 05, 2005, 01:20:31 PM »
OK, thanks for the help on the TYPE function.

Quote
What is the point going to represent on the pline?

I would snap the insertion point of the block to a point on the polyline.  This point would be referenced as a coordinate.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Code to auto-update blocks. . . help?
« Reply #3 on: July 05, 2005, 01:38:57 PM »
A quick problem you might run into is determining where on the pline the point lies ... at least programmatically it is difficult.

If you are using 2d polylines (lwpolyline), you might need to extract the entire list of points and attempt to determine (likely with a fuzz factor) if your selected point falls between two points of the polyline. In 3d space it gets decidedly more difficult too.

A quick primer follows:
Code: [Select]

(defun ispointbetween (BeginPoint EndPoint TestPoint FuzzFactor / ang1 ang2 RetVal)(setq ang1(angle BeginPoint EndPoint)
        ang2(angle BeginPoint TestPoint))
(If (equal ang1 ang2 FuzzFactor)
  (setq RetVal T)
  (setq RetVal nil)
)
RetVal
)


Now you will have to do a whole lot more math to determine if the point is on an arc of a polyline, but the abovce should get you pointed in the right direction for actually getting this part done.

You need to loop through the entire polyline until you get a T returned or reach the end of the polyline. You might find it easier to extract the distance between the points as you go ... once T is returned you can calculate the distance between the last beginpoint and your testpoint.

One more caveat .... seldom does comparing points and/or angles relating to points that the user selects return a T value since the test is to a limited number of decimal points that the user can see, which is why you need to have a fuzz factor. To see what I mean, draw a line and use this:
Code: [Select]

(ISPOINTBETWEEN (GETPOINT) (GETPOINT) (GETPOINT) 0.0)


Now try this one selecting the same points
Code: [Select]

(ISPOINTBETWEEN (GETPOINT) (GETPOINT) (GETPOINT) 0.01)


You also need to add to the code above something to make sure the point is actually BETWEEN the two points and not just along the same line
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #4 on: July 05, 2005, 02:10:58 PM »
Well here is lisp I started, perhaps too much for a start.
It gives you the outline & error function with sys var routines.
You will need them eventually.
I got you to the pick a point on a lwpolyline & the distance.
I did not complete the subroutines so you may want to make some
choices there.
I'll leave it with you to play with.

anno.lsp
This is a rather ambitious routine for your first time out. :)

The final piece of the pie will require a reactor.
I'm sorry I can not participate anymore but I will be busy for the rest of this week.
Looks like you are in good hands though.
Lot's of em around here.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #5 on: July 05, 2005, 02:14:25 PM »
Wow Keith, I see this part alone could take some work.

I want the user to tell CAD where to put the insertion point of a block.  So what if I just turned osnap on, checked to see if the user clicked on the polyline, and then found the coords of the insertion point of the block. . . that way I wouldn't have to find any coords on the pline at all.

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #6 on: July 05, 2005, 02:22:51 PM »
Don't forget to look into vlax-curve-parameters. These beauties are a treat when dealing with polylines.

As far as placing a block on a "LINE", I'm soon going to get to work on a procedure that will have the user select a line and a point at which to insert the block, then have it figure out the angle of the line and the coordinates where to place it based on what was originally selected. I'll see how generic I can make it, so it'll hopefully work with more than just line objects.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #7 on: July 05, 2005, 05:01:04 PM »
Hey thanks CAB!  I'll have a look later on - kinda busy today and prolly tomorrow.  I hope you didn't do ALL of it for me :)

I hope to learn as I piece some of it together.

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #8 on: July 07, 2005, 10:15:09 AM »
tcdan, for this:
Code: [Select]
; Program loops until user selects a polyline
(defun c:annotatep ( \ obj pline)
  (while type( = pline ???)
    (setq obj (car (entsel “\n Select polyline: “)))
    (setq anno_pline (vlax-ename->vlax-object obj))
  )
)

take note of  >this<.
Stig does an excellent job at making sure you get the desired object.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #9 on: July 18, 2005, 07:20:51 PM »
OK - I finally have a few minutes to look at this code again. . . progress at a turtle's pace, but still moving.


CAB - still haven't looked at your code, but I will soon.  I need to take a good chunk of time to read through all that you wrote and learn what the functions do.  I really appreciate your help though.


Daron -
I used CAD's help menus trying to get a handle on the difference between SSGET and NENTSEL to understand why I wouldn't always just use SSGET to pick the object I want. . . All that I'm coming up with right now is that NENTSEL works with attributes and subentities (both of which I'm not concerned with in picking a polyline).

So I don't know why I wouldn't use (ssget ":S" '((0 . "*POLYLINE"))) as you suggested at first.

However, I DID look at Stig's code for awhile, via your link.  I don't know the scope of the applications of the code, getSubent, but it seems quite versatile and reusable since you can pass it whatever user prompt and entity type for filtering that you desire.  I can see it being more useful than ssget due to its ability to select subentities.  Thanks for the learning - I discovered nentsel, member, and the variable ERRNO (although I don't know why the variable 'parent' was declared in the function...)

edited: EERNO --> ERRNO

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #10 on: July 18, 2005, 07:39:23 PM »
Maybe I should say progress at a newt's pace :)

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #11 on: July 18, 2005, 11:24:32 PM »
To add to the stress. Think about this: At the moment, you have no need for a nested object selection and you may never. Anyhow, all of a sudden you have a need for a selection of an object or a user other than yourself gets ahold of your code and starts using it. If he selects a nested object, the code could very well be set and ready to go. However, if you don't have the ability to grab a nested object, your user is most likely going to come up to you one day complaining about how that "Killer" app you asked him to use isn't working. You want to tell him that it's probably because he selected an object that he shouldn't be selecting, except Mark can tell you all about how you should never blame your users for selecting objects they shouldn't. If you expect that someone else might use your code, you should have checks and balances built into it, so that if your users pick something they shouldn't they are either told they need to select a different object or allow them the option to exit out safely. The nentsel and *(ssget ":SN" '((0 . "*POLYLINE"))) will ensure that nested selected items can still get processed or their lists can still be collected. It's just nice to have failsafes for such occasions. I know there are times when you really just don't need to care, but you never know.

*Not sure if I got the ":SN" in there correctly. That can be a tricky filter at times. S=single object selection mode and N=nested object selection. If I remember correctly, you can combine them as I've shown and you should be able to only select one nested object as long as you select an object.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #13 on: July 19, 2005, 11:27:04 AM »
Well, I thought you should be able to group those together. Either way, S for single selection and N for nested selection.

whdjr

  • Guest
Code to auto-update blocks. . . help?
« Reply #14 on: July 19, 2005, 11:49:06 AM »
You can group those togethor Daron:

Code: [Select]
(ssget ":S:N")

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #15 on: July 19, 2005, 01:07:11 PM »
Daron
If I understand ssget correctly, it allows you to click on subentities but it actually only adds the main entity (i.e. block reference...) to the selection set.  I'm sure you knew this, but I don't see how it is useful in selecting a single polyline as I am trying to do.

Edit - I'm referring to ssget with the :N argument

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #16 on: July 19, 2005, 03:16:40 PM »
CAB-
OK, I've looked at some of your code.  So far I understand how Save_Sys, Restore_Sys, and anno (error function and routine exit) work.    (I wish that meant I could write them off the top of my head!).

I'm looking at get_poly_pt:
Code: [Select]
;;  function to get a point along a polyline
;;  returns a list of (ent_name, point)
(defun get_poly_pt (/ loop ent)
  (setq loop t)
  (while loop
    (setq ent (entsel "\nPick a point on the pline to tag distance."))
    (if (and ent
             (= (cdr (assoc 0 (entget (car ent)))) "POLYLINE")
             ;;  may want to restrict to a specific layer name
        )
        (setq ent (list (car ent)
                        (vlax-curve-getClosestPointTo (car ent) (cadr ent)))
              loop nil) ; exit loop
        ;;  else nothing valid selected
        (setq loop nil) ; exit loop
   
    )
  )
  ent
)


This is how I'm reading the loop:
- display message and let user pick point (store object selected as ENT)
- IF an object was selected and it is a polyline
THEN
-->   store the entity name and user-clicked point in ENT
-->   exit loop
- ELSE selection is invalid --> exit loop
- return ENT

I would rather keep looping until the user selected a polyline by replacing
Code: [Select]
(setq loop nil) ; exit loop
with
Code: [Select]
(prompt "  Selection is not a polyline.")

The prompt could even display what the object-type selected was (would help if they were clicking on a block, spline etc.)  Am I looking at this accurately?

daron

  • Guest
Code to auto-update blocks. . . help?
« Reply #17 on: July 19, 2005, 03:22:11 PM »
Thanks Will. I knew it could be done. I just forgot how. tcdan, if you use the ":N" feature it will allow you to select a polyline within a block, if you or another user should feel so inclined. It's also not a bad safeguard for that future use if there is no need for one now. Also, if you use it how Will has correctly shown, it will allow you to feel like you're using nentsel, yet will allow you to select multiple object if you should hit non-graphical areas.

Just looking at the help file and it might HELP to add this:
(ssnamex (ssget ":N")) Read up on ssnamex.That's what will return the nested objects.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #18 on: July 19, 2005, 03:52:04 PM »
OK, just looked at the get_dist subroutine and changed it a little:

Code: [Select]
(defun get_dist (lst / obj)
  (setq obj (vlax-ename->vla-object (car lst)))
  (vlax-curve-getdistatpoint obj (cadr lst))
)


I think this:
Code: [Select]
(vlax-curve-getdistatparam obj (vlax-curve-getendparam obj))
)

will always give you the total length of the object since vlax-curve-getdistatparam gives the length of the object from the start parameter to whatever parameter you give it (in this case the end parameter).

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #19 on: July 19, 2005, 05:51:07 PM »
Try this one
Code: [Select]
;;  function to get a point along a polyline
;;  returns a list of (ent_name, point) or
;;  nil if user pressed ENTER
(defun get_poly_pt (/ loop ent)
  (setvar "errno" 0) ; must pre set the errno to 0
  (setq loop t)
  (while loop
    (cond
      ((and (null
              (setq ent (entsel "\nPick a point on the pline to tag distance."))
            )
            (= (getvar "errno") 7) ; missed
       )
       (prompt "\nMissed, Try again.")

      )

      ((= (getvar "errno") 52) ; exit if user pressed ENTER
       (setq loop nil) ; exit with nil
      )
      ((null ent)
       (prompt "\nUnknown error, select ahgain.")
      )
      ((= (cdr (assoc 0 (entget (car ent)))) "LWPOLYLINE")
       (setq loop nil) ; exit with ent
      )
      (T
       (prompt
         (strcat "\nWrong object type: " (cdr (assoc 0 (entget (car ent)))))
       )
      )
    )
  )
  ent
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #20 on: July 19, 2005, 06:15:46 PM »
Dan I had to rework that function. That is because entsel does not return a point that is exactly on the entity.
Try this.
Code: [Select]
;;  function to return the distance of point from START
;;  
(defun get_dist (lst / obj)
  (setq obj (vlax-ename->vla-object (car lst)))
  (vlax-curve-getdistatparam obj
    (vlax-curve-getParamAtPoint obj
      (vlax-curve-getClosestPointTo obj (cadr lst))))
)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Code to auto-update blocks. . . help?
« Reply #21 on: July 19, 2005, 06:22:13 PM »
Quote from: tcdan
Daron
If I understand ssget correctly, it allows you to click on subentities but it actually only adds the main entity (i.e. block reference...) to the selection set.  I'm sure you knew this, but I don't see how it is useful in selecting a single polyline as I am trying to do.

Edit - I'm referring to ssget with the :N argument

You need to use the (ssnamex) function to get the nested selected object.

Here I select a circle that is in a block, that itself is in an xref:
Code: [Select]

_$ (setq ss (ssget ":S:N"))
<Selection set: 6e>

_$ (entget (ssname ss 0))
((-1 . <Entity name: 400bf588>) (0 . "INSERT") (330 . <Entity name: 400cacb8>) (5 . "11249") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "XRef") (100 . "AcDbBlockReference") (2 . "Sodut") (10 7.72704 -51.2706 0.0) (41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 2.85639e-005) (70 . 0) (71 . 0) (44 . 0.0) (45 . 0.0) (210 0.0 0.0 1.0))

_$ (setq ent (ssnamex ss 0))
((1 <Entity name: 40fb1e50> 0 (0 (1.7913e+006 269284.0 0.0)) (-0.00114256 40.0 0.0) (-40.0 -0.00114256 0.0) (0.0 0.0 40.0) (1.79129e+006 269283.0 0.0) <Entity name: 40fb1ed0> <Entity name: 400bf588>))
_$
_$ (entget (cadr (car ent))) ;;the actual circle
((-1 . <Entity name: 40fb1e50>) (0 . "CIRCLE") (330 . <Entity name: 40fb1e40>) (5 . "D1FA8D4E5DB16DA2") (100 . "AcDbEntity") (67 . 0) (8 . "0") (100 . "AcDbCircle") (10 0.0 0.0 0.0) (40 . 0.0625) (210 0.0 0.0 1.0))
_$
_$ (entget (last (car ent))) ;; the xref object
((-1 . <Entity name: 400bf588>) (0 . "INSERT") (330 . <Entity name: 400cacb8>) (5 . "11249") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "XRef") (100 . "AcDbBlockReference") (2 . "Sodut") (10 7.72704 -51.2706 0.0) (41 . 1.0) (42 . 1.0) (43 . 1.0) (50 . 2.85639e-005) (70 . 0) (71 . 0) (44 . 0.0) (45 . 0.0) (210 0.0 0.0 1.0))

_$ (entget (car (cdr (reverse (car ent))))) ;;the block reference
((-1 . <Entity name: 40fb1ed0>) (0 . "INSERT") (330 . <Entity name: 40fc6e08>) (5 . "D1FA8D4E5DB16DB2") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "Sodut|SS") (100 . "AcDbBlockReference") (2 . "Sodut|SSMH1") (10 1.79129e+006 269283.0 0.0) (41 . 40.0) (42 . 40.0) (43 . 40.0) (50 . 1.5708) (70 . 0) (71 . 0) (44 . 0.0) (45 . 0.0) (210 0.0 0.0 1.0))

Soyou see, you can get the complete structure of that object from a single pick.

HTH,
Jeff

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Code to auto-update blocks. . . help?
« Reply #22 on: July 19, 2005, 06:26:43 PM »
CAB, why not just get the distance at the point, rather than get the param then the dist?
Code: [Select]

(defun get_dist (lst / obj)
  (setq obj (vlax-ename->vla-object (car lst)))
  (vlax-curve-getdistatpoint obj
    (vlax-curve-getClosestPointTo obj (cadr lst)))
)

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #23 on: July 19, 2005, 06:48:30 PM »
Yes that would be the best way. Too many choices & I get confused :)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #24 on: July 21, 2005, 12:56:38 PM »
Well, I've looked at reactors a bit - and they just plain intimidate me.  You have to not just attach one but multiple reactors to deal with the user starting and then finishing a command which modifies the block, you have to make sure having multiple blocks with reactors attached behave correctly (the reactors don't affect each other), and then you have to unload the reactor after you close CAD unless it is persistent (which I want it to be).  But it looks like reactors can easily crash your drawing, and, if I have say a couple hundred of these blocks all with reactors, I'm wondering if CAD's performance will suffer too.

So I think I'm going to skip the reactor portion and settle for a block that will set itself when you place it.  You have 2 options if you need to move the block:
1. Delete it and reinsert another one.
2. Manuualy run another routine which updates the block - perhaps a special 'move' routine or a routine which you can run once the block has been moved.

Thanks for your guys help thus far - it has been tremendous!  Helping me learn how to write code effectively and how different functions work. . . I find I learn much better from others as opposed to reading 'the book'.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #25 on: July 29, 2005, 10:35:00 PM »
OK, I worked on the routine today and I think I've got code that's close to being finished (fingers crossed).  CAB I just rearranged your code a little so that it made sense to me and added the portion that updates the block attribute. . . I wasn't quite sure why you pute the error-handling and exit routine at the beginning of the entire function, so I moved it out of the main function.  I'd like to know if that was a bad idea.

Of course the code doesn't work. . . not sure why yet.  Well, here it is:

Code: [Select]
;;;  =================================================================
;;;---------------------------------------------------------------------;
;;; Anno.lsp      
;;;              
;;; Description: This function will input a block on a polyline.  This block
;;; has a text field which will display the distance along the polyline from
;;; the start of the polyline.  If the block is moved and placed on the polyline
;;; elsewhere, the text field will be automatically updated.

;;;        
;;; Arguments: (none)
;;;              

;;;          
;;; Usage Anno
;;;
;;;---------------------------------------------------------------------;

(defun c:anno ()
  (vl-load-com)
  (Save_Sys '("CMDECHO" "OSMODE" ))
  (setvar "cmdecho" 0)
  (setvar "osmode" 547) ;; turn on end, int, mid, nea
 
  ;; ****************************************
  ;;       Code starts here            
  ;; ****************************************
  (while (setq pt_ent (an:get_poly_pt))
    (setq dist (an:get_dist pt_ent))
    (command "insert" "ARV" (CADR pt_ent) "" "" "") ;; insert block ARV (no scaling/rotation)
    (an:attribute dist)  ;; update attribute NUM with dist
    ;;  next line is a test ;; ??????????
    ;; (command "point" "non" (cadr pt_ent)) ;; ???NOT SURE WHY PUTTING POINT THERE???

  ;; End of main routine and exit
  (*error* "") ;;(*error* "") ; call error routine to reset vars
  (princ)  ; exit quietly
  )  ; end while
)  ; end defun
;;;  =================================================================

 

;;;  =================================================================
;;  function to get a point along a polyline
;;  returns a list of (ent_name, point) or
;;  nil if user pressed ENTER
(defun an:get_poly_pt (/ loop ent)
  (setvar "errno" 0) ; must pre set the errno to 0
  (setq loop t)
  (while loop

    (cond
      ((and (null
              (setq ent (entsel "\nPick a point on the pline to tag distance."))
            )
            (= (getvar "errno") 7) ; missed
       )
       (prompt "\nMissed, Try again.")
      ) ; end cond 1

      ((= (getvar "errno") 52) ; exit if user pressed ENTER
       (setq loop nil) ; exit with nil
      ) ; end cond 2
      ((null ent)
       (prompt "\nUnknown error, select again.")
      ) ; end cond 3
      ((= (cdr (assoc 0 (entget (car ent)))) "LWPOLYLINE")
       (setq loop nil) ; exit with ent
      ) ; end cond 4
      ((= (cdr (assoc 0 (entget (car ent)))) "POLYLINE")
       (setq loop nil) ; exit with ent
      ) ; end cond 5
      (T
       (prompt
         (strcat "\nWrong object type: " (cdr (assoc 0 (entget (car ent)))))
       )
      ) ; end cond 6
    ) ; end cond
  ) ; end while
  ent ; return this
) ; end defun
;;;  =================================================================

 

;;;  =================================================================
;;  function to return the distance of point from START.
;;  
(defun an:get_dist (lst / obj)
  (setq obj (vlax-ename->vla-object (car lst)))
  (vlax-curve-getdistatpoint obj
    (vlax-curve-getClosestPointTo obj (cadr lst)))
) ; end defun
;;;  =================================================================



;;;  =================================================================
;;  function to update attribute NUM with distance along polyline
;;  
(defun an:attribute (dist / prefix suffix station dist_round dist_len ename elist)
  (setq prefix (an:round (fix (* dist 0.01)) )
  suffix (progn
  (setq dist_round (an:round dist)
dist_len (strlen dist_round)
  )  ;; end setq

  (if (> dist_len 2) (substr dist_round (- dist_len 1) dist_len)  dist_round)
      ) ; end progn
station (strcat prefix "+" suffix)  ;; create attribute text
  ) ; end setq

  (setq ename (entnext (entlast))
   elist (entget ename))

    ;; search for attribute with tag = "NUM"
  (while (and (= (cdr (assoc 0 elist))
         "ATTRIB")
         (/= (cdr (assoc 2 elist))
        "NUM")
    )
   
    (setq ename (entnext ename)  ;; try next attribute
     elist (entget ename)
    )

    ;; replace value with contents of variable 'dist'
    (if (= (cdr (assoc 2 elist)) "NUM")
      (progn
    (entmod
       (subst (cons 1 station) (assoc 1 elist) elist)   ;; (new data, old data, list to use)
        )
        (entupd ename)   ;; force regen of entity
;;station  ;; DEBUG return text of attribute
      )
      ;; else
      (*error* "Attribute NUM not found in inserted block.")
    ) ; end if
     
  ) ; end while
   
) ; end defun
;;;  =================================================================



;;;  =================================================================
;;  function to return real number as an integer string
;;  
(defun an:round (num)
  (rtos num 2 0)
) ; end defun
;;;  =================================================================



;;;  *****************************************************************
;;   UTILITY FUNCTIONS
;;;  *****************************************************************

;;;  =================================================================
;;   error function & Routine Exit
;;
  (defun *error* (msg)
    (if
      (not
        (member
            msg
           '("console break" "Function cancelled" "quit / exit abort" "")
        )
      )
       (princ (strcat "\nError: " msg))
    ) ; endif

    ;;reset all variables here
    (Restore_Sys)
  ) ;end error function
;;;  =================================================================

 

;;;  =================================================================
;;  Function to save system variables
;;  call to function
;;    (Save_Sys '("CMDECHO" "BLIPMODE" "CLAYER" "OSMODE" "CELTYPE" "CECOLOR"))
;;
(defun Save_Sys (sysvar)
  (setq *SysVar* '()) ; global var list of saved values
  (repeat (length sysvar)
    (setq *SysVar* (append *SysVar* (list (list (car sysvar) (getvar (car sysvar))))))
    (setq sysvar (cdr sysvar))
  )
)
;;;  =================================================================



;;;  =================================================================
;; Function to reset system variables
;;
(defun Restore_Sys ()
  (and (listp *SysVar*)
    (repeat (length *SysVar*)
      (setvar (caar *SysVar*) (cadar *SysVar*)) ;set 1st item (system variable) as 2nd item in first list
      (setq *SysVar* (cdr *SysVar*)) ; remove first list
    )
  )
)
;;;  =================================================================


updates:
- changed \= to /=
- allow user to select POLYLINE as well as LWPOLYLINE
- (command "insert" "ARV" pt_ent "" "" "") changed to (command "insert" "ARV" (CADR pt_ent) "" "" "")
- took out modifications to correct alleged "rounding error"
- fixed error when clicking on polyline smaller shorter than 10 units

Jürg Menzi

  • Swamp Rat
  • Posts: 599
  • Oberegg, Switzerland
Code to auto-update blocks. . . help?
« Reply #26 on: July 30, 2005, 05:19:26 AM »
Quote from: tcdan
(...)But it looks like reactors can easily crash your drawing, and, if I have say a couple hundred of these blocks all with reactors,...
Not with a clean programming. We are working with dwgs they contain thousands of reactors (object-, command-, drawing-) and have no probs with them.
Quote from: tcdan
I'm wondering if CAD's performance will suffer too.(...)
Yes, there is a minor slow down (especially with object reactors) but only if you apply them on thousands of objects.

Cheers
A computer's human touch is its unscrupulousness!
MENZI ENGINEERING GmbH
Current A2k16... A2k24 - Start R2.18

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Code to auto-update blocks. . . help?
« Reply #27 on: July 30, 2005, 02:06:28 PM »
Quote from: tcdan
. . . I wasn't quite sure why you pute the error-handling and exit routine at the beginning of the entire function, so I moved it out of the main function.  I'd like to know if that was a bad idea.
The reason for the (*error*) function being at the beginning of the routine is to make it a local error handler, and anything local must be (defun'ed prior to calling it.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #28 on: July 30, 2005, 11:01:24 PM »
Quote
The reason for the (*error*) function being at the beginning of the routine is to make it a local error handler, and anything local must be (defun'ed prior to calling it.


So what does it mean to be 'local'?  I guess it just means you can only call the function from the function that it is defined within.

And does the code skip any locally defined functions (blocks of code surrounded by a (defun) statement)?

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #29 on: July 30, 2005, 11:32:13 PM »
And is it OK for me to make it global. . . or is it better to keep it local?  What does it matter?

Anyways, I was thinking it would be better to make it global cuz I would prolly use this with other functions.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #31 on: July 31, 2005, 01:16:49 AM »
ERRORS RIGHT NOW

1.  If the user presses escape during execution - an error occurs.  Not sure what to do about that one.


I attached the block which the program inputs here.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #32 on: July 31, 2005, 01:21:58 AM »
Quote
read these
http://www.theswamp.org/phpBB2/search.php?mode=results

Was that a joke CAB or just trying to tell me to do my own search? . . . you just attached the search dialog.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #33 on: July 31, 2005, 04:38:55 AM »
OK - everything seems to work now!!!!
WOOHOO!

I included a setup file so the user can input what block name and attribute tag will be modified.  It also asks you to set the scale of the block and an optional offset.

There are 2 things I would like to add to the program another time:

1.  Allow the user to press escape to exit command (instead of clicking point or inputting data).

2.  Rotate the block so that it is perpendicular to the polyline.  This would just require me to determine the angle of the polyline at the insertion point of the block. . . I'm not quite sure how to do that though.  I could go about it by drawing a line snapped perpendicular to the polyline at that point and subtracting 90 degrees from the angle of the line. . . but that seems like the long way around doesn't it?  There must be a way to get to the segment in question, perhaps using (entnext), and then determing the angle of the segment.  hmmmm

Any ideas?  I'll check into this at a better hour :)

Program here if interested

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Code to auto-update blocks. . . help?
« Reply #35 on: July 31, 2005, 02:53:55 PM »
Quote from: tcdan

There are 2 things I would like to add to the program another time:

1.  Allow the user to press escape to exit command (instead of clicking point or inputting data).
This is where your error handler comes in to play. If it is setup correctly, it will take care of the ESC key. Just make sure to reset your variables that you would normally reste when exiting, and you may need to place a (command) or two to terminate any active command call.
Quote from: tcdan

2.  Rotate the block so that it is perpendicular to the polyline.  This would just require me to determine the angle of the polyline at the insertion point of the block. . . I'm not quite sure how to do that though.  I could go about it by drawing a line snapped perpendicular to the polyline at that point and subtracting 90 degrees from the angle of the line. . . but that seems like the long way around doesn't it?  There must be a way to get to the segment in question, perhaps using (entnext), and then determing the angle of the segment.  hmmmm
See the 7th post in THIS thread A bit more work would be needed if the pline has arcs in it, but it could be done.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #36 on: July 31, 2005, 06:46:36 PM »
direct to 7th post
Right Click on the Paper icon next to the word Posted to get the direct link.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Jeff_M

  • King Gator
  • Posts: 4096
  • C3D user & customizer
Code to auto-update blocks. . . help?
« Reply #37 on: July 31, 2005, 07:56:27 PM »
I thought it would benefit tcdan to read the entire thread.......;)

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Code to auto-update blocks. . . help?
« Reply #38 on: July 31, 2005, 09:12:33 PM »
Sorry, that one went right by me. :oops:
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

tcdan

  • Guest
Code to auto-update blocks. . . help?
« Reply #39 on: August 01, 2005, 01:01:39 AM »
Alright Jeff - now I have the block inserting perpendicularly to the line and rotating to make the text readable!  Great!  

Quote
This is where your error handler comes in to play. If it is setup correctly, it will take care of the ESC key. Just make sure to reset your variables that you would normally reste when exiting, and you may need to place a (command) or two to terminate any active command call.


Well, I'm not sure how to catch ESC in an error handler. . . don't write this one for me - maybe just point me a little. :)

ALso, is there a way to make global variables persist between sessions?. . . like maybe writing some information into a dictionary (whatever that is)?

CAB - read a bit of your links, yeah a lot of reading if I want to get it all :)  Thanks.