Hi,
I'd like to be able to make a rectangular selection of a point cloud in the xy plane and extract the z-value of the point cloud node with the lowest z-value within that selection.
This would be very useful when adding ground levels to a drawing where there might be foliage/twigs/debris etc above or on the ground.
I already have a Lisp routine for picking a point cloud node and drawing a cross with the level value but this just picks the node nearest the picker, which might not be the lowest point within the selected area.
Any help much appreciated.
Thanks.
Here is a Dropbox link to a small point cloud sample that has uneven ground with some small trees, clumps of foliage, and some debris on the ground.
My present workflow is to chop clouds up into small areas then clip them as near to ground as possible. I then enable the previously mentioned Lisp routine for adding a cross with level (with 3D object snap node enabled) and move the picker around while keeping an eye on the running z-value until I decide it's a good point and then click.
https://www.dropbox.com/sh/3nzf3qwuxq3g6kp/AABM8J0BpRp8Bdpntu4FmA0Ma?dl=0
The above point cloud is a recap pro file which can be attached directly to an Autocad drawing. It will attach at the co-ordinates in the 500,500,25 range that it has been controlled to.
Try this
(defun c:pc_pt_with_min_z (/ pco)
(setq pco (vlax-ename->vla-object (car (entsel "\nSelect point cloud :"))))
(and (= "AcDbPointCloudEx" (vla-get-objectname pco))(vla-getboundingbox pco 'minpt 'maxpt))
(setq p1 (vlax-safearray->list minpt))
)
Point with min z stored in global variable p1. Z value should be minimal Z in pointcloud. This is not actual point with min z.
Miljenko Hatlak
Is it possible to obtain a good quality lidar aerial survey record of a mountainous area covered with deciduous forest
and remove forest layer to retain only ground levels to create terrain model? Have you got any experience with this kind of work?
Miljenko Hatlak
That sounds like an expensive undertaking and I'm afraid that kind of stuff is out of my league. I'm using a Leica BLK360 in combination with a Theodolite to survey small/medium Topo and buildings.
There are various software packages such as Leica Cloudworx, Virtual Surveyor etc. that can do this with a combination of lowest point of a selection (Smart Pick in Cloudworx) and interpolating between visible low points.
These software packages cost 1000s though and I'm running on a minimal budget with regards to point clouds using Register360, Recap Pro, and Autocad.
Any special survey drawing functions I use are achieved using Lisp routines.
Thanks for the code. I'm currently trying to figure out how to combine it with the code I use to pick a point and add a cross and level text. I'll let you know how I get on...
If points from a part of a pointcloud can be extracted to some kind of txt file then working with them analyzing data could be done easy and autolisp can be used for it.
I have been testing with UK survey .asc files from https://environment.data.gov.uk/DefraDataDownload/?Mode=survey Here in attachment is my code to to load .asc files to autocad , maybe you can find some use for it.
Works well with sets up to 300 000 points.
Thanks for info about lidar. It was one of ideas to present it to my client about terrain survey for future aggregate exploitation.
Miljenko Hatlak
You need to have a block called "CROSS" defined. I have a layer called "LTEXT" for all level text and a layer called "LX" for level crosses.
(defun C:LP (/ lyr txtSize osm3D pt ptXY ptXY2 zStr)
;;initial prep
;
(setvar "cmdecho" 0)
(setq lyr (getvar 'CLAYER))
(setq txtSize (getvar "textsize"))
;
;;user select point
;
(setq osm3D (getvar '3DOSMODE))
(setvar '3DOSMODE 128)
(initget 1) (setq pt (getpoint "\nSelect Point: "))
(setvar '3DOSMODE osm3D)
;
;;prep for work
;
(setq ptXY (list (car pt) (cadr pt)))
(setq ptXY2 (list (car pt) (- (cadr pt) (* 2 txtSize))))
(setq zStr (rtos (caddr pt) 2 2))
;
;;block/text creation
;
(command "-LAYER" "M" "LX" "")
(command "-INSERT" "CROSS" "non" ptXY txtSize "" 0.0)
(command "-LAYER" "M" "LTEXT" "")
(command "TEXT" "non" ptXY2 "" 0.0 zStr)
;
;;finish up
;
(setvar 'CLAYER lyr)
(setvar 'CMDECHO 1)
(princ)
);defun
Your code seems to let me pick an entire point cloud, not a selection of that point cloud. It then returns the z-value corresponding to the lowest point of the bounding box, not the z-value of the lowest point within in the cloud.
I incorporated it into my code and the above seems to be the result I get.
PS I don't really know what I'm doing...
(defun c:LOW (/ pco p1 pt ptXY ptXY2 zStr)
;
(setvar "cmdecho" 0)
(setq lyr (getvar 'CLAYER))
(setq txtSize (getvar "textsize"))
;
(setq pco (vlax-ename->vla-object (car (entsel "\nSelect point cloud :"))))
(and (= "AcDbPointCloudEx" (vla-get-objectname pco))(vla-getboundingbox pco 'minpt 'maxpt))
(setq p1 (vlax-safearray->list minpt))
;
(setq pt(getpoint "Whereabouts...?"))
;
(setq ptXY (list (car pt) (cadr pt)))
(setq ptXY2 (list (car pt) (- (cadr pt) (* 2 txtSize))))
(setq zStr (rtos (caddr p1) 2 2))
;
(command "-LAYER" "M" "LX" "")
(command "-INSERT" "CROSS" "non" ptXY txtSize "" 0.0)
(command "-LAYER" "M" "LTEXT" "")
(command "TEXT" "non" ptXY2 "" 0.0 zStr)
;
(setvar 'CLAYER lyr)
(setvar 'CMDECHO 1)
(princ)
);defun
This is definitively not a solution. I don't use Recap, but if you can extract part of a pointcloud you are working on it can be done with easy. Actually data can be filtered out from txt file without even loading PC in acad. Unfortunately there is no much options. Instead of picking points you would have to extract part of a cloud to txt file, and process with lisp. Sorting points for min Z can be done during reading file and there is not need to create any object on the screen. That's the way I would tackle this problem. Sorry, I don't have much experience working with pointclouds.
Miljenko Hatlak
OK thanks for your help. You've given me some ideas for further research.