Jump to content

Recommended Posts

Posted

Hello,

 

I've been having trouble lately making an autolisp program that allows me to return the names of buildings that are included (totally or not) in a hatched area.
In my case, the colour of the hatched area is important but I'm not going to linger on the colour because if the code works for one colour there shouldn't be any problems for the others.

 

Here's the considered approach:
- select the hatches that might contain buildings
- analyse each hatch and check whether buildings are actually contained within it
- create a list of the buildings' names contained in the hatches and write the names in an Excel file

 

The hatches in question can be of any shape (rectangular, circular, etc.)

 

An example of an autocad file is attached:
- a layer "polylines" containing the polylines representing the outlines of the buildings
- a layer "numero" containing the names of the buildings (inside the outlines)
- a final layer "hatch" containing the hatches

Test AUTOCAD.dwg

 

This is the basis of my code:

 

   (setq names (ssadd))
   (setq Build (ssadd))	

  ; selecting the hatches and get their outlines
  
   (if (setq ss (ssget "x" (list '(0 . "HATCH") '(62 . 4)))) ; blue hactches
     (repeat (setq i (sslength ss))
       (setq Contours (mapcar 'cdr (vl-remove-if-not '(lambda (p) (= (car p) 10)) (entget (ssname ss (setq i (1- i)))))))
       (setq Contours (cdr Contours)) ; "Contours" = building outlines
       (setq Contours (reverse (cdr (reverse Contours))))

  ;get a selection of the polylines inside the hatches
       
       (if Contours
	 	(progn
	   		(setq ss_bat (ssget "_CP" Contours '((0 . "LWPOLYLINE") (8 . "polylignes"))))

			[...]; get the list of each building to get the names after (see lines below) -> fill "Build" 

			)
		(princ "no contours")
		)
       )
     )


; get the list of names of the buildings
  
  (repeat (setq j (sslength sel))
           (if 
               (setq sel (ssget "_CP" 
                   (mapcar 'cdr 
                       (vl-remove-if-not
                          '(lambda (p) (= (car p) 10)) 
                           (entget (ssname Build (setq j (1- j))))
                       )
                   )
		  '((0 . "TEXT,MTEXT") (8 . "numero")))
               )
	     (progn
	       (setq text (cdr (assoc 1 (entget (ssname sel 0)))))
	       (setq names (cons text names))
	       )
	     )
    )

 

I have 2 problems at the moment:
- if the hatches are in the shape of a circle, I don't have enough points when I want to retrieve the outline to accurately determine whether a building is in the hatched area or not.
- I don't know how to get a list of each individual polyline from the building selection (see the [...] inside the code above)

 

If you could give me any hints or help, I'd be very grateful.

 

Thanks

 

Posted (edited)

Yes
Getting the list of hatch points is one of the biggest difficulties in your program, especially if it is circular hatching or similar.
You cannot get a coherent perimeter from the entity list.

I tried a couple of times but had to resign myself to doing it with 'hatchedit'.

Is it possible that there is someone who can prove otherwise?

Edited by GLAVCVS
Posted

I used HatchB.lsp and yes got a pline as the defining shape, it appears to have two vertices so could check for that and make a series of points that would be the pline as facets.

 

; may be able to use (setq ent (entlast)) if a pline has been made with 2 points.
(setq ent (car (entsel "\nPick hatch boundary ")))
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget ent))))
(setq mp (mapcar '* (mapcar '+ (car co-ord) (cadr co-ord)) '(0.5 0.5)))
(setq rad (distance mp (car co-ord)))
(setq inc (/ (* pi 2) 20)) ; may want more than 20
(setq pts '())
(setq ang 0.0)
(repeat 21
(setq pt (polar mp ang rad))
(setq pts (cons pt pts))
(setq ang (+ ang inc))
)

 

 

Posted
9 hours ago, BIGAL said:

Utilicé HatchB.lsp y sí, obtuve una pline como forma definitoria, parece tener dos vértices, así que pude verificarlo y hacer una serie de puntos que serían la pline como facetas.

 

 

 

 

It's interesting
But, at least for me, it doesn't work correctly.
I've drawn a polyline with the points that the function calculates when selecting the yellow circle and this is what I get:

 

Img2-1.png

Posted

And if the hatch has several arcs to compose an irregular shape, it doesn't work well either.
In the following image you can see the perimeter returned by the function when the cyan hatch is selected.

It is interesting to note that all the perimeters returned by the function seem to want to pass through the point 0,0

 

 

Img3.png

Posted

Furthermore, the function in no case returns the inner perimeter

Posted

This should be helpful when you trying something to select inside the CIRCLE (like from attached example file).

 

(setq ent_circle (car (entsel "\nSelect the CIRCLE:"))
      num 50 ;; number of times to repeat inside "repeat" function. Can be changeable, depends of density between the points.
      ang 0.0 ;; default angle
      tot (+ pi pi)
      inc (/ tot (float num))
      cen (cdr (assoc 10 (entget ent_circle))) ;; CIRCLE base point
      rad (cdr (assoc 40 (entget ent_circle))) ;; radius of the CIRCLE
      )
(repeat num
  (setq lst (cons (polar cen ang rad) lst)) ;; creating a LIST with "points" on the CIRCLE
  (setq ang (+ ang inc))
  )
(setq entSelection (ssget "CP" lst '((0 . "LWPOLYLINE")))) ;; make a selection set from previous list of points (lst). SSGET filter can be changed

 

After executing the code, you will get this (picture 1). I changed the color into to the orange, just to make it easier to see all polylines.

 

image.png.d5007e6a477bf1efa71db4b75ba6f6a0.png

 

Maybe the second approach can be also helpful.

 

(setq entOne (car (entsel "\nSelect the first HATCHED area:"))
      objOne (vlax-ename->vla-object entOne)
      )

(vla-getboundingbox objOne 'minPtOne 'maxPtOne) ;; get the boundingbox from hatch

(setq ptMinOne (vlax-safeArray->list minPtOne) ;; get the lower left point
      ptMaxOne (vlax-safeArray->list maxPtOne) ;; get the upper right point
      )

(if (not (tblsearch "LAYER" "TEST_BOUNDARY")) ;; this is just for testing
    (progn
      (command "-layer" "m" "TEST_BOUNDARY" "c" 1 "" "s" "TEST_BOUNDARY" "")
      )
    (progn
      (command "clayer" "TEST_BOUNDARY")
      )
    )

(command-s "_RECTANG" ptMinOne ptMaxOne) ;; make a rectangle to wrap everything around the hatch
(setq entlastOne (entlast)
      objRectangOne (vlax-ename->vla-object entlastOne))

(setq coordsOne (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget entlastOne)))) ;; get the coordinates from previous maded rectangle
(setq ssOutside (ssget "WP" coordsOne '((0 . "LWPOLYLINE")))) ;; make a selection set from previous list of points (coordsOne). SSGET filter can changed

 

After executing the code, you will get this (picture 2). I changed the color into to the orange, just to make it easier to see all polylines and you will se a red rectangle which I get from boundingbox.

 

image.png.a13757f8f14005fbc6263404defd2907.png

 

But if you have this next situation, you can think about changing the "hatch pattern" (something about "ANSI 31"). When you change the "hatch pattern" you can explode it and you will get a bunch o lines. Then, you can create a selection set with filter and then iterate through the loop, and make a new selection set only from lines which are croosing through the "buildings" (picture 3, just an example). You can see how the line will intersect the buildings (red circles), and after the loop was finished, undo everything to get previous "hatch pattern", you will get a new selection set list with buildings who belongs to the hatched area, and than you can iterate through the new selection set to get the data (names) of the buildings.

 

image.thumb.png.a0937d5998e7dcb80f6f6c35f0bc08cb.png

 

I hope it will be helpful, or make a starting point to think about the solution.

Also, tried the Bigals code, but something weird happening, like GLAVCVS say.

 

Best regards.

Posted

Thank you guys for your help.

 

Several comments:

 

Indeed @GLAVCVS, when you get the points of the hatch outline, it always (at least every time I checked) takes the (0 0) points, that's why I remove the first point in "Contours" in my basis code, I do not know why..

 

@Saxlle, thank you for your help, the tip to use ANSI type hatches and explode it is quite intersting!

 

Having the outline points independently of the hatch shape seems very complicated. Even if I make several cases for circles, rectangles et, I can still have hatches like the blue one GLAVCVS told about earlier...

 

11 hours ago, GLAVCVS said:

 

Img3.png

 

I'll try to work on it in the next few days

Posted

You're welcome @Lucay. Than, if you are going to have irregular shapes, than I would think about the 3rd solution which I described, that is going to help you. Maybe something unexpectedly can happend, but let us know if it's happen.

 

Best regards.

Posted (edited)

The problem with the pline being multi objects ars & lines etc. This seemed to work, to get points. Point them on a dummy layer then use ssget, after got points erase the selection set. Yes used HatchB.lsp to make outline.

 

(setvar 'osmode 0)
(setvar 'pdmode 34)

(setq obj (vlax-ename->vla-object (car (entsel "\nPick hatch object "))))

(setq len (vlax-get obj 'length))
(setq inc ( / len 40))
(setq ch 0.0)
(repeat 40 
(setq pt (vlax-curve-getpointatdist obj ch))
(command "point" pt)
(setq ch (+ ch inc))
)

 

Need some real shapes to check properly.

image.png.9b15514fe3facdf5c9b3c64cd7f1d09d.png

Edited by BIGAL
Posted

If you try to run:

 

(vl-cmdf "_hatchedit" (car (entsel "\nSelect HATCH... ")) "_boundary" "_polyline" "_no")


you will generate a perimeter polyline of the selected hatch. It will create polylines for both the outer perimeter and the inner ones, if there are any.
From these polylines, which have arcs, you need to get the list of points

 

 

 

Posted

If you store in a variable the name of the last drawing entity returned by '(entlast)', (before running 'hatchedit'), after running 'hatchedit' the last drawing entities will be the ones created by 'hatchedit'. This will allow us to create a loop with 'entlast' in which we will get the list of each entity created by 'hatchedit' and store it in a variable before deleting it. In this way, the next call to 'entlast' will return the drawing entity before the one deleted.
As long as 'entlast' does not return the entity before running 'hatchedit', we will repeat this cycle.
This, in code, could look like this:

 

(setq entPre (entlast))
(vl-cmdf 'hatchedit' entHatch...)
(while (not (equal (setq ent (entlast)) entPre))
  (setq lstpts (getListPoints (entget ent)))
  .....
  (entdel (entlast)) 
  .....

 

Posted

Of course: the 'getListPoints' function will have to be the function that converts the entity list into a list of points.

Posted

I just came up with another approach, which I think is better.
You can use 'vla-intersectwith' directly to determine if any geometry is inside or outside the contour obtained with 'hatchedit'.
You could apply @Saxlle's idea of creating a selection set from 'vla-getboundingbox' to make a first filter. And apply 'vla-intersectwith' to all the segments of the selected lines to check if they are inside.
I'll leave the idea there.
Try to understand it and advance in it on your own. It's the way to progress and improve your skills.

If you get to a point where you need help, ask again.

  • Agree 1
Posted

Thank you all for your ideas and help, I've got plenty to do :)

Posted

Like @GLAVCVS said, you can also use the "vla-IntersectWith" method and you will get a list of points where the intersecting are happend as variant (array of doubles) or "nil" which depends of which ExtendOption will be in use.

 

You're welcome @Lucay.

Posted (edited)

In case I have not made myself clear, I will briefly explain how my approach would be:
-Make a selection set of the hatches that may contain buildings
-For each hatch:
1) obtain its outline with 'hatchedit' and identify it with 'entlast' (as I explained above)
2) make a selection set of the buildings contained in the window returned by 'getboundingbox'.
3) analyze with 'vla-intersectwith' each building selected in the previous step and identify the buildings included and/or intersected by the outline(s).
4) save the results in a file (excel, txt... etc)

Edited by GLAVCVS
  • Agree 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...