Author Topic: How to get area?  (Read 5644 times)

0 Members and 2 Guests are viewing this topic.

litss

  • Guest
How to get area?
« on: October 18, 2011, 05:16:37 AM »
I have got a list of line ends, like ((pt1 pt2) (pt3 pt4) (pt5 pt6) ...). And these lines form a closed area (only one), but some of them connect by ends and others cross each other, which means it could be rectangle or "#".

How could I get the area of the closed area? I've tried: draw the lines->pick a point manually within the closed area->genrate a region->get the area. But here, a manual point is required.

If "regen" is the only way, how can I omit the "pick point" step? Or, there is another better way to solve the problem?

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: How to get area?
« Reply #1 on: October 18, 2011, 05:59:54 AM »
Depending on how complex the shape defined is, and if you're only using lines: Then you could use the inters function to find those intersections, generate a LWPolyline from those points and get it's area property.

Of course you'd need to find the correct order for these intersections though, otherwise you could end up with a self-intersecting polyline. Thus your area would be smaller than it should.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: How to get area?
« Reply #2 on: October 18, 2011, 09:16:10 AM »
Depending on how complex the shape defined is, and if you're only using lines: Then you could use the inters function to find those intersections, generate a LWPolyline from those points and get it's area property.

If you have a set of points describing a simple (non-intersecting) polygon, you can use the equation from here to calculate the enclosed area, e.g.:

Code: [Select]
(defun PointArea ( lst )
    (/
        (abs
            (apply '+
                (mapcar
                    (function
                        (lambda ( a b ) (- (* (car a) (cadr b)) (* (car b) (cadr a))))
                    )
                    lst (append (cdr lst) (list (car lst)))
                )
            )
        )
        2.0
    )
)

litss

  • Guest
Re: How to get area?
« Reply #3 on: October 18, 2011, 09:17:13 PM »
Thanks U guys!

To irneb: :( I have tried to collect points before. But I have no idea how to arrange them in the right order. So I finally gave up that thought.

To Lee: Does ur routine require a arranged points-lst? I haven't tried it. If not, the same problem.


pBe

  • Bull Frog
  • Posts: 402
Re: How to get area?
« Reply #4 on: October 18, 2011, 11:45:39 PM »
USe something like this in conjunction with Lee's code

Code: [Select]
(defun c:test (/ sort_ ss i ent pts_ ll)
(defun sort_ (lst / a  mList intr)
    (while (setq a (car lst))
  (foreach itm (setq lst (vl-remove a lst))
  (if (setq intr (inters (car a)(cadr a)
                       (car itm)(cadr itm) ))
     (setq mList (cons intr mList))))
  )
  mList
    ) 
  (setq ss (ssget '((0 . "LINE"))))
  (repeat (setq i (SSLENGTH ss))
  (setq ent (entget (ssname ss (setq i (1- i))))
      )
  (setq pts_ (cons (list (cdr (assoc 10 ent))
  (cdr (assoc 11 ent))) pts_)))
(if (= (length  (setq ll (sort_ pts_))) 4)
    (princ (strcat "\nArea: "(rtos (pointarea (list (cadr ll)
(car ll)
(caddr ll)
(last ll)
   )
) 2 4)))
   )(princ)
  )

Hope this helps

litss

  • Guest
Re: How to get area?
« Reply #5 on: October 19, 2011, 09:24:19 PM »
Thx pBe!

I will try ur code soon. It must be helpful.

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: How to get area?
« Reply #6 on: October 20, 2011, 07:53:32 AM »
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

litss

  • Guest
Re: How to get area?
« Reply #7 on: October 20, 2011, 11:40:43 AM »
To pBe: I've tried ur code. It works well with closed area with 4 lines. But failed with more than 4. I am not quite sure why.

To Lee: Ur code works. But it did require an arranged pts. Otherwise, returns unexpected value.

To alanjt: Thank you. Ur code is amzing. Though it is not perfectly meet my situation. I can't point out he vertex one by one to get the area. There are too many.

Thx again for all of u. I'll try to arrange the intersections. Then I will use Lee's code.


Lee Mac

  • Seagull
  • Posts: 12915
  • London, England
Re: How to get area?
« Reply #8 on: October 20, 2011, 11:57:14 AM »
To Lee: Ur code works. But it did require an arranged pts. Otherwise, returns unexpected value.

Yes, the points must outline the area, since the equation will only apply to simple (non-self-intersecting) polygons.

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: How to get area?
« Reply #9 on: October 20, 2011, 12:58:30 PM »
Why not use BPoly and pick a point within your intersecting lines and get the area from the created polyline?
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

litss

  • Guest
Re: How to get area?
« Reply #10 on: October 20, 2011, 09:37:19 PM »
alanjt:  Well, to manually pick a point within the area is my current way. The difference is I generate a "region", not a pline. I just wanna improve and make it more automaticly.  Maybe I can try to find out a point within the area automaticly. That will do too.  Thx!

pBe

  • Bull Frog
  • Posts: 402
Re: How to get area?
« Reply #11 on: October 21, 2011, 12:56:12 AM »
To pBe: I've tried ur code. It works well with closed area with 4 lines. But failed with more than 4. I am not quite sure why.

Of course, its written that way to do as such  :)

Thx again for all of u. I'll try to arrange the intersections. Then I will use Lee's code.

Might as well :)

Tell you what, post an image or a dwg sample.




litss

  • Guest
Re: How to get area?
« Reply #12 on: October 21, 2011, 02:08:02 AM »
Here are the samples. I am wishing to get the areas of all shadowed automaticly while I "ssget" the lines at one time. It might be too difficult for me. So I am planning to "ssget" one by one :), without picking a point within it.

pBe

  • Bull Frog
  • Posts: 402
Re: How to get area?
« Reply #13 on: October 21, 2011, 03:02:26 AM »
Here are the samples. I am wishing to get the areas of all shadowed automaticly while I "ssget" the lines at one time. It might be too difficult for me. So I am planning to "ssget" one by one :), without picking a point within it.

Tell me this, if you're going to select the lines one by one anyway, you might as well pick a point rather than select the lines:
8 lines , 8 input
8 points, 8 input

Alanjt's posted link will take care of the area once you have the points in order, which is very likely so as you are picking the points in order


or why not?
Quote
Why not use BPoly and pick a point within your intersecting lines and get the area from the created polyline?

The plines generated by BPoly can be easily converted to a region and just one pick point.

we can play around with codes to suit your needs, but there are other options to consider first.

So give us an outline
How:<-------- sequence that is

What:<--- the result  (besides the area value of course)

 :-)



« Last Edit: October 21, 2011, 03:09:00 AM by pBe »

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: How to get area?
« Reply #14 on: October 21, 2011, 03:08:54 AM »
I can think of a way using polar to figure out the direction around the shape for most of those. The problem one would be that Z shape.

As a test I tried figuring out if a hatch would work, though then you get all sorts of strange artifacts. So bang goes that idea. It seems your best bet is to use the boundary though trying to figure out the "internal" point would be very similar to trying to figure out the order of the intersections.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

litss

  • Guest
Re: How to get area?
« Reply #15 on: October 21, 2011, 05:06:02 AM »
Quote
if you're going to select the lines one by one anyway, you might as well pick a point rather than select the lines:

Well, reasons:
1) the drawings are not as neat as this sample. Other lines, texts, dims, ect..will cross the figure. If pick points to "region", I need to "layer-off" those unrelavant layers, after that, "layer-on". Not that convenient as "ssget" with filters.
2) there might be some small gaps between lines' intersections. I can use the (inters ... nil) to negelect those gaps by allowing some distance errors. While the "region" will fails.
3) Actually, by apply the (command "pedit" ...), I now can achive the area. But I am still curious about the way without "command", like the Lee's Pointarea. That would be nice:)

Hope this can help ur undersanding.

I am trying a method to rearrange the intersections that collected by ur code :
Quote
(setq pts_ (cons (list (cdr (assoc 10 ent))
                     (cdr (assoc 11 ent))) pts_)))
That is:
select an arbitrary line -> (setq ptlst (list p0 p1)) -> use p0 to search for the next line (p0, p2) -> (cons p2 ptlst) -> use p2 to search for next (p2,p3).......
Maybe it would work

Thank you!

litss

  • Guest
Re: How to get area?
« Reply #16 on: October 21, 2011, 05:12:13 AM »
To irneb : Thanks :)   Hatch is somewhat like region. Both might be fragile to gaps.
               

hare14

  • Guest
Re: How to get area?
« Reply #17 on: October 21, 2011, 05:50:44 AM »
Hi

Get Volume and area from solid!

I used this code in MDT8 which worked fine.
Now on Win7 and MDT9(64bit) only the dvb-version works, this Lisp code gives an error ...access violation!

Any ideas?

Code: [Select]
(defun c:t1 (/)
  (vl-load-com)

;;;  dvb working in MDT9

;;;    Dim tmpObj As AcadObject
;;;    Dim objEntity
;;;    Set objEntity = pickObj("select 3D Solid")  ' an acad Solid Object
;;;   
;;;    Dim mcad As McadApplication
;;;    Set mcad = ThisDrawing.Application.GetInterfaceObject("Mcad.Application")
;;;    Dim mcC As IMcadBody
;;;   
;;;    Set mcC = mcad.ActiveDocument.Utility.GetObjectFromID(objEntity.ObjectID, mcSolid) ' mcC ist das mcad Solid ( mcSolid = 24 )
;;;   
;;;    Dim dArea As Double
;;;    Dim dVolume As Double
;;;
;;;   mcC.BRepEntity.Body.GetVolume dVolume ' getVolume ist eine Methode und liefert in dVolume den Wert zurück
;;;   mcC.BRepEntity.Body.GetSurfaceArea dArea


  (setq aobj (vlax-get-acad-object))
  (setq aAcDoc (vla-get-activedocument aobj))

  (setq aUtil (vla-get-utility aAcDoc))
 
  (setq mobj (vla-getinterfaceobject aobj "Mcad.Application"))
  (setq activeDoc (vla-get-activedocument mobj))
  (setq util (vla-get-utility activedoc))

  (setq Solid3d (entsel "\nSelect object "))
;;; Solid3d is an autocad-object!
 
(setq mc_solid nil)
(setq objS (vlax-ename->vla-object ( car Solid3d)))
 
(setq objId (vlax-get-property objS  'ObjectId))

(setq mc_solid (vlax-invoke-method util 'GetObjectFromid (vlax-get-property objS  'ObjectId) 0 nil nil nil nil))
 ;;;  GetObjectFromID(Id As LONG_PTR, Type As McadObjectType, [Infer As Boolean = True], [SubentType], [SubentIndex], [Point]) As IMcadObject
 ;;;                                  pars : McadObjectType = 0 , optional

 ;;; now mc_solid is an MCad-object!
   
(setq b_rep    ( vlax-get-property mc_solid 'BrepEntity ))
(setq b_body   ( vlax-get-property b_rep 'body))
(setq vol (vlax-make-variant 0 vlax-vbDouble )) 
(setq area (vlax-make-variant 0 vlax-vbDouble ))
(setq edge (vlax-make-variant 0 vlax-vbDouble ))

;;; needs a suitable tolerance !!!!
(setq tol (vlax-make-variant 0.01 vlax-vbDouble )) 

( vlax-invoke-method b_body 'getVolume 'vol tol)
( vlax-invoke-method b_body 'getSurfaceArea 'area tol)
( vlax-invoke-method b_body 'getPerimeterLength 'edge tol)

;;;  if many calls -> best practice: realease them
 (vlax-release-object b_body)
 (vlax-release-object b_rep)
 (vlax-release-object mc_solid)

 ( princ  vol )
(  princ  "  " )
(  princ  area )
(  princ  "  " )
(  princ  edge )
(  princ  "\n" ) 
)

Thanks

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: How to get area?
« Reply #18 on: October 21, 2011, 05:51:28 AM »
Actually the hatch may help with lines not intersecting properly (note the Gap Tolerance). Although the artifacts I was referring to is when selecting the lines (instead of pick-point) then you get strange pieces of the hatch going outside the area, see the attached.

Have you perhaps thought of using a lisp routine which asks for the pick-point, then turn off the layers or using LayIso then issuing the Boundary command and sending that point, then turning the layers back on (or LayUnIso)? That might work if the layers are always the same ones for your boundary lines.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: How to get area?
« Reply #19 on: October 21, 2011, 06:30:03 AM »
What about this?
Code: [Select]
(vl-load-com)

(defun c:MyBoundary (/ pt elast layers hpgap layers-off layers-on)
  (setq hpgap (getvar 'HPGAPTOL))
  (setvar 'HPGAPTOL 50.0) ;Change to your preference
  (setq layers (cons (strcat (getvar 'CLayer)) '("0" "DIMS"))) ;Change to suit your situation, keep upper case
  (or *vla-AcadObject* (setq *vla-AcadObject* (vlax-get-acad-object)))
  (or *vla-ActiveDocument* (setq *vla-ActiveDocument* (vla-get-ActiveDocument *vla-AcadObject*)))
  (or *vla-LayersCollection* (setq *vla-LayersCollection* (vla-get-Layers *vla-ActiveDocument*)))
  (if (setq pt (getpoint "\nPick internal point of boundary: "))
    (progn
      (vlax-for layer *vla-LayersCollection*
        (if (= (vla-get-LayerOn layer) :vlax-true)
          (setq layers-on (cons layer layers-on))
          (setq layers-off (cons layer layers-off))
        )
        (vla-put-LayerOn
          layer
          (if (member (strcase (vla-get-Name layer)) layers)
            :vlax-true
            :vlax-false
          )
        )
      )
      (setq elast (entlast))
      (command "._-HATCH" "_Properties" "Solid" "_None" pt "")
      (if (eq elast (entlast))
        (princ "\nThe boundary couldn't be created.")
        (progn
          (setq elast (entlast))
          (command "._HATCHEDIT" elast "_Boundary" "_Region" "_Yes")
          (setq *boundary* nil)
          (if (eq elast (entlast))
            (princ "\nThe boundary couldn't be created.")
            (progn
              (setq *boundary* (entlast))
              (princ "\nThe boundary is created.")
            )
          )
          (entdel elast)
        )
      )
      (foreach layer layers-on
        (vla-put-LayerOn layer :vlax-true)
      )
      (foreach layer layers-off
        (vla-put-LayerOn layer :vlax-false)
      )
    )
  )
  (setvar 'HPGAPTOL hpgap)
  (princ)
)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

pBe

  • Bull Frog
  • Posts: 402
Re: How to get area?
« Reply #20 on: October 22, 2011, 01:54:41 AM »

Well, reasons:
1) the drawings are not as neat as this sample. Other lines, texts, dims, ect..will cross the figure. If pick points to "region", I need to "layer-off" those unrelavant layers, after that, "layer-on". Not that convenient as "ssget" with filters.
2) there might be some small gaps between lines' intersections. I can use the (inters ... nil) to negelect those gaps by allowing some distance errors. While the "region" will fails.
3) Actually, by apply the (command "pedit" ...), I now can achive the area. But I am still curious about the way without "command", like the Lee's Pointarea. That would be nice:)


If I understand it right, you cant do a "point" method because there are too many lines intersecting inside the target area.
and you would rather select lines one by one sans layer?

try this:

Code: [Select]
(defun c:Test2 ( / ss entV pts x1 x2 y1 y2 Pt2Pt PeriM Area str)
(vl-load-com)
(foreach nm '("entV" "Pt2Pt" "PeriM")
  (if (not (eval (read nm)))
    (set (setq ss (read nm)) nil)
  )
)
 (if (setq ss (ssget '((0 . "LINE"))))
  (progn
(repeat (sslength ss)
(setq entV (cons (vlax-ename->vla-object (ssname ss 0)) entV) )
(ssdel (ssname ss 0) ss)
  )
(setq pts
       (mapcar '(lambda (o k)
  (vlax-invoke o 'Intersectwith k acExtendNone)
)
       entv
       (cdr (append entv (list (car entv))))
       )
      pts (cons (last pts) pts)
)
(repeat (length entV)
                         (setq x1 (car (car pts))
                               x2 (cadr (car pts))
                               y1 (car (cadr pts))
                               y2 (cadr (cadr pts))
                               )
                         (setq Pt2Pt
                                    (cons (- (* x1 y2) (* x2 y1))
                                          Pt2Pt))
                         (setq PeriM (cons (distance (car pts)(cadr pts)) PeriM))
                         (setq pts (cdr pts))
                         )
                   (setq Area (abs (/ (apply '+ Pt2pt) 2))
                         str
                              (if (or (= (getvar "lunits") 3)
                                      (= (getvar "lunits") 4))
                                    (strcat
                                          (rtos (/ area 144) 2)
                                          " sq. ft.")
                                    (strcat (rtos Area 2) " m²")
                                    )
                         )(print Str)
  )
  )
(print)                   
  )

the code is messy right now, but we can do a cleanup later on,
You need to selct lines one by one in order <clockwise or cclockwise> as long as its the same direction
« Last Edit: October 22, 2011, 01:59:35 AM by pBe »

litss

  • Guest
Re: How to get area?
« Reply #21 on: October 25, 2011, 12:15:58 AM »
irneb, pBe, thank you!

Quite busy these days. I'll try ur codes and finish mine after that.