Jump to content

Sum Numbers in Mtext Fields to Mtext Field


muurr

Recommended Posts

Hello everybody,

This is my first post on CADTutor. I've been reading alot here even before I became a member, but it is time for me to join the community with a question since I cannot find the exact answer to mine.

Question:

Is it possible to sum numbers in Mtext fields created with lisps?

AT.LSP

OT.LSP

I edited them to suit my needs with prefix and suffix and decimal precision (they are in the core the same, originally made by JTB), one is displaying area of selected polyline (AT.lsp) and the other perimeter/length (OT.lsp). I would like to preserve possibility of field updating so when polyline/area is changed I just enter regenall. I copied Mtext fields maually to "oldstyletable" made from lines and mtext, mtext fields. See attached dwg for example.

I've seen this thread:

http://www.cadtutor.net/forum/showthread.php?43699-Sum-Text-Strings-to-Text-Field...

I tried all the lisps but none are applicable to my problem. I get only #### even after regen (I think it's maybe because of prefix and suffix, but don't know). I've managed to work only with text and then my updating Mtext fields are, for sure, gone.

Please advise.

TEST1.dwg

Link to comment
Share on other sites

Try this:

(vl-load-com)

;;; -------------------------------------------------------------------------------------
;;; Get a text object's field references
;;; -------------------------------------------------------------------------------------
(defun Text:GetTextFields (obj / lst xdic fdic fo fd GF:RecurseFields)
 (if (and (= (vla-get-HasExtensionDictionary obj) :vlax-true)
          (setq xdic (vla-GetExtensionDictionary obj))
          (not (vl-catch-all-error-p (setq fdic (vl-catch-all-apply 'vla-Item (list xdic "ACAD_FIELD")))))
          (not (vl-catch-all-error-p (setq fo (vl-catch-all-apply 'vla-Item (list fdic "TEXT")))))
          (setq fd (entget (vlax-vla-object->ename fo)))
     )
   (progn
     (defun GF:RecurseFields (fd / lst1 lst)
       (setq lst1 (member (assoc 2 fd) fd))
       (mapcar
         '(lambda (item)
            (cond
              ((= (car item) 360)
               (setq lst (cons (GF:RecurseFields (entget (cdr item))) lst))
              )
              ((= (car item) 331)
               (setq lst (cons (vla-get-ObjectID (vlax-ename->vla-object (cdr item))) lst))
              )
            )
          )
         (cdr lst1)
       )
       (cons (cdar lst1) (reverse lst))
     )
     (setq lst (GF:RecurseFields fd))
   )
 )
 lst
)

(setq *Text:FieldNumTypes* "*).Area*,*).Length*")
;;; Get all the numerical fields from a text object
(defun Text:GetNumberFields (obj /)
 (vl-remove-if-not
   (function
     (lambda (e)
       (wcmatch (car e) *Text:FieldNumTypes*)
     )
   )
   (cdr (Text:GetTextFields obj))
 )
)

;; Sum all numerical fields in selected text objects
(defun c:SumTextFields (/ ss obj fLst target)
 (or *ActiveDoc* (setq *ActiveDoc* (vla-get-activedocument (vlax-get-acad-object))))
 (princ "Select text entities: ")
 (if (and (setq ss (ssget "_:L" '((0 . "TEXT,MTEXT"))))
          (setq target (entsel "Pick target text: "))
          (wcmatch (cdr (assoc 0 (entget (car target)))) "TEXT,MTEXT")
          (setq target (vlax-ename->vla-object (car target)))
          (setq ss (vla-get-ActiveSelectionSet *ActiveDoc*))
     )
   (progn
     (vlax-for obj (setq ss (vla-get-ActiveSelectionSet *ActiveDoc*))
       (setq fLst (vl-remove-if-not (function (lambda (e) e)) (append fLst (Text:GetNumberFields obj))))
     )
     (vla-delete ss)
     (setq ss "%<\\AcExpr (")
     (foreach obj fLst
       (setq ss (strcat ss "%<\\AcObjProp Object(%<\\_ObjId " (itoa (last obj)) ">%)."
                        (cond
                          ((wcmatch (car obj) "*).Area*") "Area")
                          ((wcmatch (car obj) "*).Length*") "Length")
                        )
             ">%+"))
     )
     (setq ss (strcat (vl-string-right-trim "+" ss) [color=red]") \\f \"%lu2%pr2%ps[bF=,m2]%ct8[0.0001]>%"[/color]))
     (vla-put-TextString target ss)
   )
 )
 (princ)
)

The command is SumTextFields. I haven't tried formatting on this, since the format would differ between Area and Length. But you could edit the field afterwards, then see what its field codes do and add it to the last ")>%") in the code above. Perhaps make one version for areas and one for lengths.

 

It does the opposite of what you'd expect. Rather than trying to extract the values from the selected text, it searches through the text finding all fields. Then recreates fields pointing to the original objects' properties and combines them into a Formula field which just adds them all together.

 

Edit: I just realized that it becomes difficult to format the Formula field after the fact. So I changed the ending to match your Area format (marker in red). For your length format do the same thing thus:

) \\f \"%lu2%pr2%ps[uF=,m]%ct8[0.01]\">%

Link to comment
Share on other sites

On second though, here's a much better way:

(vl-load-com)

;;; -------------------------------------------------------------------------------------
;;; Get a text object's field references
;;; -------------------------------------------------------------------------------------
(defun Text:GetTextFields (obj / lst xdic fdic fo fd GF:RecurseFields)
 (if (and (= (vla-get-HasExtensionDictionary obj) :vlax-true)
          (setq xdic (vla-GetExtensionDictionary obj))
          (not (vl-catch-all-error-p (setq fdic (vl-catch-all-apply 'vla-Item (list xdic "ACAD_FIELD")))))
          (not (vl-catch-all-error-p (setq fo (vl-catch-all-apply 'vla-Item (list fdic "TEXT")))))
          (setq fd (entget (vlax-vla-object->ename fo)))
     )
   (progn
     (defun GF:RecurseFields (fd / lst1 lst)
       (setq lst1 (member (assoc 2 fd) fd))
       (mapcar
         '(lambda (item)
            (cond
              ((= (car item) 360)
               (setq lst (cons (GF:RecurseFields (entget (cdr item))) lst))
              )
              ((= (car item) 331)
               (setq lst (cons (vla-get-ObjectID (vlax-ename->vla-object (cdr item))) lst))
              )
            )
          )
         (cdr lst1)
       )
       (cons (cdar lst1) (reverse lst))
     )
     (setq lst (GF:RecurseFields fd))
   )
 )
 lst
)

(setq *Text:FieldNumTypes* "*).Area*,*).Length*")
;;; Get all the numerical fields from a text object
(defun Text:GetNumberFields (obj /)
 (vl-remove-if-not
   (function
     (lambda (e)
       (wcmatch (car e) *Text:FieldNumTypes*)
     )
   )
   (cdr (Text:GetTextFields obj))
 )
)

;; Sum all numerical fields in selected text objects
(defun c:SumTextFields (/ ss obj fLst target FieldType)
 (or *ActiveDoc* (setq *ActiveDoc* (vla-get-activedocument (vlax-get-acad-object))))
 (princ "Select text entities: ")
 (if (and (setq ss (ssget "_:L" '((0 . "TEXT,MTEXT"))))
          (setq target (entsel "Pick target text: "))
          (wcmatch (cdr (assoc 0 (entget (car target)))) "TEXT,MTEXT")
          (setq target (vlax-ename->vla-object (car target)))
          (progn
            (initget "Area Length")
            (setq FieldType (cond ((getkword "Select [Area/Lengh] <Area>: "))
                                  ("Area")
                            )
            )
          )
          (setq ss (vla-get-ActiveSelectionSet *ActiveDoc*))
     )
   (progn
     (setq *Text:FieldNumTypes*
            (cond ((eq FieldType "Area") "*).Area*")
                  ((eq FieldType "Length") "*).Length*")
            )
     )
     (vlax-for obj (setq ss (vla-get-ActiveSelectionSet *ActiveDoc*))
       (setq fLst (vl-remove-if-not (function (lambda (e) e)) (append fLst (Text:GetNumberFields obj))))
     )
     (vla-delete ss)
     (setq ss "%<\\AcExpr (")
     (foreach obj fLst
       (setq ss (strcat ss "%<\\AcObjProp Object(%<\\_ObjId " (itoa (last obj)) ">%)." FieldType ">%+"))
     )
     (setq ss (strcat (vl-string-right-trim "+" ss)
                      (cond
                        ((eq FieldType "Area") ") \\f \"%lu2%pr2%ps[bF=,m2]%ct8[0.0001]>%")
                        ((eq FieldType "Length") ") \\f \"%lu2%pr2%ps[uF=,m]%ct8[0.01]\">%")
                      )
              )
     )
     (vla-put-TextString target ss)
   )
 )
 (princ)
)

It asks if you want Area or Length and extracts only the selected fields. Thus you could even go and select across mixed texts, it will only extract the area fields if you selected area (same for length). And then also it formats according to your format requirements.

Link to comment
Share on other sites

Thank you, irneb!

I've been comparing the two lisps side by side for last hour or so :) checking what exactly have you done, and exploring what exactly can they do. I must say for the second one - It does the job whole in one!

It's an interesting way of extracting numbers from fields going to their root objects and then formatting them in resulting field.

Although I didn't expect that when I "pick target text:" it will overwrite that text rather then it uses its formatting and then asks me where to put the resulting mtext field.

I was just wandering if there is a possibility to do that; To extract format from fields (although fields can have different format) or from a target text (better) and then put text field to a specific point. Using this lisp I need first to copy some text (any text with any format that I wish to be in resulting field) to resulting tab and then use your lisp. If I forget to do that or there is no text to overwrite than I need to start the command again.

But besides that lisp is doing it's job. The greatest thing is that you have put all in one lisp with possibility to decide, and this can grow with needs.

 

Also I found that when I edit mtext it has all fields in expression like this:

cExpr (Field1+Field2+Field3+etc...) - Field1,2,3 is just a representation of values extracted from objects that are in not shown here, but I think you already know that. :)

 

(sdrow eht nrael) ;)

Link to comment
Share on other sites

You're welcome.

 

To answer your last question first :whistle:: That's because I've used the formula field ... it has that hiccup. A work-around is to include the prefix as normal text instead of the field's formatting prefix. This so the whole text is not a formula and won't show up as a formula when edited. For this you need to change (setq ss "%

 

As for the query about drilling down to the original objects, that's the only way to get at the true values through fields. If a text contains something else than numbers a field trying to calculate from that text will fail. So my code goes and de-constructs the field - finding the original object.

 

It is certainly possible to extract the formatting from one of the source fields and re-use that same format. I'll look into that for you at a later stage.

 

As for allowing a new text instead of an existing to overwrite, that's also quite possible. Would you want the option for both scenarios? Or would you prefer just making a new text?

Link to comment
Share on other sites

Yes, I think to create new is enough. But IT IS interesting to have possibility to replace existing if there are some changes. hmmmm..

If it's no problem another cond for New/Replace - would be great. You have the routine for Replace now and I don't know how difficult is to do the one for new.

You need to know that I'm not so familiar with lisp routines programing, so I can help only with requests (for now) and just trying to understand something vaguely if I can. I edited some lisps before but on most basic level (as you saw). I used your lisp to finishing some of my tables in few drawings that had empty space for sum - but not any more - and that's to thank you for that. :)

I am no longer in a hurry to edit this drawings, it's easier now. But in a future it would be good to have a polished routine. So when you have time and if you have time for that I will be here watching and trying out with. This BF=/UF= is editable it can be anything or nothing at all, and measures also.. somehow I figured those things before. :) and this can be usefull for somebody else also, hopefully.

And maybe I'm writing too much. :D

Link to comment
Share on other sites

  • 2 years later...

Hi guys,

Taking advantage of this great opportunity.

 

I'd like to get a lisp that make a specific formula and insert the result as a field.

I'm doing this manually, but it take a lot of time. Maybe a lisp could be faster.

 

I've attached a little example of my request.

I'll be really happy if someone could help me out.:D

 

Thank in advance

FIELD-FORMULA.dwg

Link to comment
Share on other sites

Can't you make a spreadsheet and import the information on that sheet into AutoCAD? If your set on a LISP routine look through some of these. Lee should have something in there like what you need.

Link to comment
Share on other sites

Hi Turns,

Thanks for replay

 

I'm a big fan of Lee Mac, his routines is just amazing! :thumbsup:

 

But I couldn't find any program doing as my request.

I always use Text Calculator from Lee Mac. Unfortunately didn't work for Field.

 

I'll be wait patiently for some help!

 

Thank you , guys.

:D

Link to comment
Share on other sites

Then in the meantime while someone more versed in LISP than I, try making a spread sheet and importing it into AutoCAD. Here is a guide in case you didn't already know how to do that.

Link to comment
Share on other sites

I really appreciate your kindness trying to help me out.

 

Import Excel Spreadsheets into AutoCAD is not what I'm looking for, to be honest.

 

Thanks Anyway.

:thumbsup:

Link to comment
Share on other sites

  • 3 years later...
Hi guys,

Taking advantage of this great opportunity.

 

I'd like to get a lisp that make a specific formula and insert the result as a field.

I'm doing this manually, but it take a lot of time. Maybe a lisp could be faster.

 

I've attached a little example of my request.

I'll be really happy if someone could help me out.:D

 

Thank in advance

 

Thank you very much Lee Mac!! :D

http://lee-mac.com/fieldmath.html

You're amazing!! :notworthy:

 

Guys, How I can mention Lee Mac in my post?

I've thought it using @Lee Mac.

 

Fabricio

Link to comment
Share on other sites

You're welcome! I'm glad you find the program useful!

 

I don't think there is a way to 'mention' members on this forum in a post in such as way that they will be notified.

Link to comment
Share on other sites

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