Author Topic: Contour - perimeter polyline from 3d faces  (Read 2687 times)

0 Members and 1 Guest are viewing this topic.

nekonihonjin

  • Newt
  • Posts: 103
Contour - perimeter polyline from 3d faces
« on: November 04, 2015, 06:08:48 PM »
Hello everyone,
I have some files exported to dxf from minesght, representing a 3D shape of a mine tunnel, I would like to get the top view of this tunnel but only the contour, since the files exported is a sort of 3d faces, I need a polyline of only the outside but can't figure out a way of achieving this, I placed the topic in Autolisp because I have to do this a lot and it would be great to have a routine that would do the job, but if you tell me the steps to do it mannually it's very good as well.

The attachment is an example of how I get the file exported from minesight, I tried flattening the faces and joining the lines but didn't worked out.

I hope you can help me.
(Sorry the bad english).
« Last Edit: November 04, 2015, 06:19:22 PM by nekonihonjin »

Dave M

  • Newt
  • Posts: 196
Re: Contour - perimeter polyline from 3d faces
« Reply #1 on: November 04, 2015, 07:25:42 PM »
There's probably a better way, but here is what I did. It was relatively fast and easy.
1. Flatten all the 3-D faces
2. Convert the faces to regions.
3. Use the Union command and select all the regions.
 
Civil 3D 2018 - Microstation SS4 - Windows 10 - Dropbox

nekonihonjin

  • Newt
  • Posts: 103
Re: Contour - perimeter polyline from 3d faces
« Reply #2 on: November 05, 2015, 09:26:35 AM »
There's probably a better way, but here is what I did. It was relatively fast and easy.
1. Flatten all the 3-D faces
2. Convert the faces to regions.
3. Use the Union command and select all the regions.

With the faces flattened, selected all of them and the region command did the trick
didn't even had to use the union command.
And a lisp with these steps it's a peace of cake.

Thanks a lot.

ymg

  • Guest
Re: Contour - perimeter polyline from 3d faces
« Reply #3 on: November 05, 2015, 06:55:35 PM »
nekonihonjin,

Here a feeble attempt at automating some of it, method is essentially
what Dave proposed except that I use lwpoly and boundary instead
of region and union.

You select the 3DFaces, from it a selection set of
LWPolyline is created at elevation 0.

Command "_MOVE" is initiated with the set of lwpoly selected awaiting
that you drag it to a new position, thus preserving your original 3dfaces.

Once you've selected a new position, a bounding box just a tad bigger than the set is drawn to
completely contains the set of LWPolyline.

Command "_BOUNDARY" is initiated and pause awaiting that you select
internal point(s) to define the boundaries.

Program completes.

Upon completion you have to select the right boundaries manually and move it
to final position.

I tried to round the coordinates of the lwpoly to limit the number of boundaries
being created, but it did not help.

Code: [Select]
(defun c:test (/ bb en ent i p1 p2 pol ss ss1)
   (prompt "\n Select 3dFaces: ")
   (setq ss (ssget '((0 . "3DFACE"))))
   (setq ss1 (ssadd))
   (repeat (setq i (sslength ss))
      (setq en  (ssname ss (setq i (1- i)))
    ent (entget en)
    pol (distinctfuzz (list (cdr (assoc 10 ent)) (cdr (assoc 11 ent)) (cdr (assoc 12 ent)) (cdr (assoc 13 ent))) 0.003)
      )
      (if (= (length pol) 3)
         (ssadd (mk_lwp pol) ss1)
      )
   ) 
   (command "_MOVE" ss1 "" (cadr (grread nil 13 0)) pause)
   (setq bb (ssboundingbox ss1)
p1 (car bb)
p2 (cadr bb)
   )     
   (command "_RECTANGLE" p1 p2)
   (command "_SCALE" (entlast) "" (midpoint p1 p2) 1.05)
   (ssadd (entlast) ss1)
   (command "_ZOOM" "_O" (entlast) "")  
   (command "_BOUNDARY" "_A" "_B" "_N" ss1 "" "_I" "YES" "_O" "POLYLINE" "")
)


;; distinctfuzz       by Gile Chanteau                                        ;
;; Suprime tous les doublons d'une liste                                      ;
;;                                                                            ;
;; Argument                                                                   ;
;; l : une liste                                                              ;
;; f : fuzz value for comparison                                              ;
;;                                                                            ;

(defun distinctfuzz (l f)   
   (if l   
      (cons (car l) (distinctfuzz (vl-remove-if '(lambda (a) (equal a (car l) f)) (cdr l)) f))
   )
)

(defun midpoint (p1 p2)
  (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2)


;;                                                                            ;
;; mk_lwp    by Alan J Thompson     (Modified by ymg for closed poly)         ;
;;                                                                            ;
;; Argument: pl, A list of points (2d or 3d)                                  ;
;; Create an LWPolyline at Elevation 0, on Current Layer.                     ;
;; Return: Entity Name                                                        ;
;;                                                                            ;

(defun mk_lwp (pl / isclosed)
   (setq isclosed 0)
   (if (equal (car pl) (last pl) 0.001)
      (setq isclosed 1  pl (cdr pl))
   ) 
   
      (entmakex
         (append (list '(0 . "LWPOLYLINE")
                       '(100 . "AcDbEntity")
                       '(100 . "AcDbPolyline")
                        (cons 90 (length pl))
                        (cons 70 isclosed)
                 )
                 (mapcar '(lambda (p) (cons 10 (trans (list (car p) (cadr p)) 1 0))) pl)
         )
      )
)

;; Selection Set Bounding Box  -  Lee Mac                                     ;
;; Returns a list of the lower-left and upper-right WCS coordinates of a      ;
;; rectangular frame bounding all objects in a supplied selection set.        ;
;; s - [sel] Selection set for which to return bounding box                   ;

(defun ssboundingbox ( s / a b i m n o )
    (repeat (setq i (sslength s))
        (if
            (and
                (setq o (vlax-ename->vla-object (ssname s (setq i (1- i)))))
                (vlax-method-applicable-p o 'getboundingbox)
                (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list o 'a 'b))))
            )
            (setq m (cons (vlax-safearray->list a) m)
                  n (cons (vlax-safearray->list b) n)
            )
        )
    )
    (if (and m n)
        (mapcar '(lambda ( a b ) (apply 'mapcar (cons a b))) '(min max) (list m n))
    )
)

« Last Edit: November 06, 2015, 12:54:26 PM by ymg »

ymg

  • Guest
Re: Contour - perimeter polyline from 3d faces
« Reply #4 on: November 07, 2015, 04:42:34 PM »
nekonihonjin,

Here, maybe a little better. 

As previously the 3dfaces are flattened and transformed into LWpoly.
If an LWpoly ends up close to colinear, it is rejected.

Command move is used to place the LWpoly in an empty space
in order to preserve your original set of 3DFaces.

A rectangle slightly bigger than this set is drawn to enclose it.

Command boundary is started with the set of LWPoly and the Rectangle
selected.  Island detection is set to yes, and Object type to polyline.
At this point, the command awaits that you select points to define the external
and internal contours of your set.

The resulting boundaries created are kept.

We erase the set of flattened LWpoly, to make it easier to select
the correct boundaries.

You are prompted to select the boundaries to retain;
The rest of boundaries are erased.

This is close to the method used by VVA in program ECO
Except that I could not get ECO to keep the right boundaries,
also only the external one would be created.

Code - Auto/Visual Lisp: [Select]
  1. (defun c:test (/ bb en ent i p p1 p2 pol rec ss ss1 w)
  2.    (prompt "\n Select 3dFaces: ")
  3.    (setq ss (ssget '((0 . "3DFACE"))))
  4.    (setq ss1 (ssadd))
  5.    (repeat (setq i (sslength ss))
  6.       (setq en  (ssname ss (setq i (1- i)))
  7.             ent (entget en)
  8.             pol (list (butlast (cdr (assoc 10 ent))) (butlast (cdr (assoc 11 ent))) (butlast (cdr (assoc 12 ent))))
  9.       )
  10.       (if  (not (colinear_p  (cadr pol) (car pol) (caddr pol)))
  11.          (ssadd (mk_lwp (cons (last pol) pol)) ss1)
  12.       )
  13.    )  
  14.    (command "_MOVE" ss1 "" (cadr (grread nil 13 0)) pause)
  15.    (setq bb (ssboundingbox ss1)
  16.          p1 (car bb)
  17.          p2 (cadr bb)
  18.    )      
  19.    (command "_RECTANGLE" p1 p2)
  20.    (command "_SCALE" (entlast) "" (midpoint p1 p2) 1.05)
  21.    (setq rec  (entlast))
  22.    (setq w (ssboundingbox (ssadd rec)))
  23.    (command "_ZOOM" "_O" rec "")
  24.    (setq ss1 (ssget "_C" p1 p2))
  25.    
  26.    (command "_BOUNDARY" "_A" "_B" "_N" ss1 rec "" "_I" "YES" "_O" "POLYLINE" "" )
  27.       (while (setq p (getpoint "\nPick Internal Point: ")) (command p))
  28.    (command "")
  29.  
  30.    (command "_ERASE" ss1 "")
  31.    (setq ss1 (ssget "_C" (car w) (cadr w)))
  32.    (while (setq en (car (entsel "\nSelect Boundary to Retain: ")))
  33.       (ssdel en ss1)
  34.    )  
  35.    (command "_ERASE" ss1 "")
  36. )
  37.  
  38.  
  39.  
  40. ;; colinear_p                                                                 ;
  41. ;; Return true if point is within 20 seconds of vector v1->v2                 ;
  42. ;;                                                                            ;
  43.  
  44. (defun colinear_p (p v1 v2 / xp yp)
  45.    (setq  xp (car  p) yp (cadr  p))
  46.    (< (abs (- (* (- (cadr v1) yp) (- (car v2) xp)) (* (- (car v1) xp) (- (cadr v2) yp)))) 1e-4)
  47. )
  48.  
  49.  
  50.  
  51. ;; butlast, Returns the list with last item removed.                          ;
  52. (defun butlast (l) (reverse (cdr (reverse l))))
  53.  
  54. ;; Returns midpoint between two points                                        ;
  55.  
  56. (defun midpoint (p1 p2)
  57.   (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2)
  58. )  
  59.  
  60. ;;                                                                            ;
  61. ;; mk_lwp    by Alan J Thompson     (Modified by ymg for closed poly)         ;
  62. ;;                                                                            ;
  63. ;; Argument: pl, A list of points (2d or 3d)                                  ;
  64. ;; Create an LWPolyline at Elevation 0, on Current Layer.                     ;
  65. ;; Return: Entity Name                                                        ;
  66. ;;                                                                            ;
  67.  
  68. (defun mk_lwp (pl / isclosed)
  69.    (setq isclosed 0)
  70.    (if (equal (car pl) (last pl) 0.001)
  71.       (setq isclosed 1  pl (cdr pl))
  72.    )  
  73.    
  74.       (entmakex
  75.          (append (list '(0 . "LWPOLYLINE")
  76.                        '(100 . "AcDbEntity")
  77.                        '(100 . "AcDbPolyline")
  78.                         (cons 90 (length pl))
  79.                         (cons 70 isclosed)
  80.                  )
  81.                  (mapcar '(lambda (p) (cons 10 (trans (list (car p) (cadr p)) 1 0))) pl)
  82.          )
  83.       )
  84. )
  85.  
  86. ;;                                                                            ;
  87. ;; Selection Set Bounding Box  -  Lee Mac                                     ;
  88. ;; Returns a list of the lower-left and upper-right WCS coordinates of a      ;
  89. ;; rectangular frame bounding all objects in a supplied selection set.        ;
  90. ;; s - [sel] Selection set for which to return bounding box                   ;
  91. ;;                                                                            ;
  92.  
  93. (defun ssboundingbox ( ss / a b i m n o )
  94.     (repeat (setq i (sslength ss))
  95.         (if (and (setq o (vlax-ename->vla-object (ssname ss (setq i (1- i)))))
  96.                  (vlax-method-applicable-p o 'getboundingbox)
  97.                  (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list o 'a 'b))))
  98.             )
  99.            (setq m (cons (vlax-safearray->list a) m)
  100.                  n (cons (vlax-safearray->list b) n)
  101.            )
  102.         )
  103.     )
  104.     (if (and m n)
  105.         (mapcar '(lambda ( a b ) (apply 'mapcar (cons a b))) '(min max) (list m n))
  106.     )
  107. )
  108.  
  109.  
« Last Edit: November 07, 2015, 10:55:23 PM by ymg »

nekonihonjin

  • Newt
  • Posts: 103
Re: Contour - perimeter polyline from 3d faces
« Reply #5 on: November 17, 2015, 12:08:42 PM »
nekonihonjin,

Here, maybe a little better. 

As previously the 3dfaces are flattened and transformed into LWpoly.
If an LWpoly ends up close to colinear, it is rejected.

Command move is used to place the LWpoly in an empty space
in order to preserve your original set of 3DFaces.

A rectangle slightly bigger than this set is drawn to enclose it.

Command boundary is started with the set of LWPoly and the Rectangle
selected.  Island detection is set to yes, and Object type to polyline.
At this point, the command awaits that you select points to define the external
and internal contours of your set.

The resulting boundaries created are kept.

We erase the set of flattened LWpoly, to make it easier to select
the correct boundaries.

You are prompted to select the boundaries to retain;
The rest of boundaries are erased.

This is close to the method used by VVA in program ECO
Except that I could not get ECO to keep the right boundaries,
also only the external one would be created.

Code - Auto/Visual Lisp: [Select]
  1. (defun c:test (/ bb en ent i p p1 p2 pol rec ss ss1 w)
  2.    (prompt "\n Select 3dFaces: ")
  3.    (setq ss (ssget '((0 . "3DFACE"))))
  4.    (setq ss1 (ssadd))
  5.    (repeat (setq i (sslength ss))
  6.       (setq en  (ssname ss (setq i (1- i)))
  7.             ent (entget en)
  8.             pol (list (butlast (cdr (assoc 10 ent))) (butlast (cdr (assoc 11 ent))) (butlast (cdr (assoc 12 ent))))
  9.       )
  10.       (if  (not (colinear_p  (cadr pol) (car pol) (caddr pol)))
  11.          (ssadd (mk_lwp (cons (last pol) pol)) ss1)
  12.       )
  13.    )  
  14.    (command "_MOVE" ss1 "" (cadr (grread nil 13 0)) pause)
  15.    (setq bb (ssboundingbox ss1)
  16.          p1 (car bb)
  17.          p2 (cadr bb)
  18.    )      
  19.    (command "_RECTANGLE" p1 p2)
  20.    (command "_SCALE" (entlast) "" (midpoint p1 p2) 1.05)
  21.    (setq rec  (entlast))
  22.    (setq w (ssboundingbox (ssadd rec)))
  23.    (command "_ZOOM" "_O" rec "")
  24.    (setq ss1 (ssget "_C" p1 p2))
  25.    
  26.    (command "_BOUNDARY" "_A" "_B" "_N" ss1 rec "" "_I" "YES" "_O" "POLYLINE" "" )
  27.       (while (setq p (getpoint "\nPick Internal Point: ")) (command p))
  28.    (command "")
  29.  
  30.    (command "_ERASE" ss1 "")
  31.    (setq ss1 (ssget "_C" (car w) (cadr w)))
  32.    (while (setq en (car (entsel "\nSelect Boundary to Retain: ")))
  33.       (ssdel en ss1)
  34.    )  
  35.    (command "_ERASE" ss1 "")
  36. )
  37.  
  38.  
  39.  
  40. ;; colinear_p                                                                 ;
  41. ;; Return true if point is within 20 seconds of vector v1->v2                 ;
  42. ;;                                                                            ;
  43.  
  44. (defun colinear_p (p v1 v2 / xp yp)
  45.    (setq  xp (car  p) yp (cadr  p))
  46.    (< (abs (- (* (- (cadr v1) yp) (- (car v2) xp)) (* (- (car v1) xp) (- (cadr v2) yp)))) 1e-4)
  47. )
  48.  
  49.  
  50.  
  51. ;; butlast, Returns the list with last item removed.                          ;
  52. (defun butlast (l) (reverse (cdr (reverse l))))
  53.  
  54. ;; Returns midpoint between two points                                        ;
  55.  
  56. (defun midpoint (p1 p2)
  57.   (mapcar '(lambda (a b) (/ (+ a b) 2.0)) p1 p2)
  58. )  
  59.  
  60. ;;                                                                            ;
  61. ;; mk_lwp    by Alan J Thompson     (Modified by ymg for closed poly)         ;
  62. ;;                                                                            ;
  63. ;; Argument: pl, A list of points (2d or 3d)                                  ;
  64. ;; Create an LWPolyline at Elevation 0, on Current Layer.                     ;
  65. ;; Return: Entity Name                                                        ;
  66. ;;                                                                            ;
  67.  
  68. (defun mk_lwp (pl / isclosed)
  69.    (setq isclosed 0)
  70.    (if (equal (car pl) (last pl) 0.001)
  71.       (setq isclosed 1  pl (cdr pl))
  72.    )  
  73.    
  74.       (entmakex
  75.          (append (list '(0 . "LWPOLYLINE")
  76.                        '(100 . "AcDbEntity")
  77.                        '(100 . "AcDbPolyline")
  78.                         (cons 90 (length pl))
  79.                         (cons 70 isclosed)
  80.                  )
  81.                  (mapcar '(lambda (p) (cons 10 (trans (list (car p) (cadr p)) 1 0))) pl)
  82.          )
  83.       )
  84. )
  85.  
  86. ;;                                                                            ;
  87. ;; Selection Set Bounding Box  -  Lee Mac                                     ;
  88. ;; Returns a list of the lower-left and upper-right WCS coordinates of a      ;
  89. ;; rectangular frame bounding all objects in a supplied selection set.        ;
  90. ;; s - [sel] Selection set for which to return bounding box                   ;
  91. ;;                                                                            ;
  92.  
  93. (defun ssboundingbox ( ss / a b i m n o )
  94.     (repeat (setq i (sslength ss))
  95.         (if (and (setq o (vlax-ename->vla-object (ssname ss (setq i (1- i)))))
  96.                  (vlax-method-applicable-p o 'getboundingbox)
  97.                  (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list o 'a 'b))))
  98.             )
  99.            (setq m (cons (vlax-safearray->list a) m)
  100.                  n (cons (vlax-safearray->list b) n)
  101.            )
  102.         )
  103.     )
  104.     (if (and m n)
  105.         (mapcar '(lambda ( a b ) (apply 'mapcar (cons a b))) '(min max) (list m n))
  106.     )
  107. )
  108.  
  109.  

ymg,

I was on vacation, just got to the office.
the first lisp works fine, just some random sharp edges but it's still usefull.
The second one is better yet, you'll save me lots of work with this.

Thanks a lot.

ymg

  • Guest
Re: Contour - perimeter polyline from 3d faces
« Reply #6 on: November 18, 2015, 10:56:36 AM »
nekonihonjin,

You are most Welcome!

Glad! I could help.

ymg