Author Topic: Triangulation (re-visited)  (Read 247092 times)

0 Members and 1 Guest are viewing this topic.

rw2691

  • Newt
  • Posts: 125
Re: Triangulation (re-visited)
« Reply #690 on: July 17, 2016, 03:41:08 PM »
Ribarm,

Just a consideration...

Your resolution to average the z factor seems to be flawed in my my opinion. I know that it is the premise of the current Triang approach, but the fact that data can reflect a difference to a 2d resolution is a challenge to that theory. If 2d coordinates show a zero relationship, it should imply that an elevation difference is desired.

If the TIN is vertical it should not be assumed that it is wrong.

I have used a different program, EZYsurf, to build the TIN's and it succeeded. It took a very long time to create the contours, but it also succeeded. It is using a 3d resolution.

On a 2d evaluation it might appear that the contours cross, but they do not on a 3d evaluation.

I think it is an issue that needs to be examined. It is a tough one, but it is also the reality of contours.

The drawing that is submitted may be poor, and even contrived, yet it is also a situation that can be encountered. Why not attempt to resolve the issue without compromising the data?

Rick
« Last Edit: July 17, 2016, 05:09:33 PM by rw2691 »
Hippocrates (400BC), "Life is short, craft long, opportunity fleeting, experiment treacherous, judgment difficult."

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #691 on: July 18, 2016, 05:52:38 AM »
Are you sure EazySurf isn't compromising the data also... Are you aware that it may be very possible that similar algorithm is used and if collinearity comes into the triangulation process it's considered buggy, thus TIN (triangular IRREGULAR network)... As for my approach I don't see anything wrong in specifying some small fuzz factor to break down collinearity by rand position of points in 2D while preserving z coordinate relations... Z average is used though I really shouldn't - the triangulation process is 2D algorithm based and therefore while triangulating in WCS no vertical triangular 3DFACES should be produced... I know this is somewhat bad (averaging z coordinates, but then you can modify it to be used only lowest coordinate thus representing the ground elevation... To me those point data that have this info (double points with different Z) are bad data and from bad data you should get and bad results... If someone seriously want to perform triangulation, one should consider providing correct data point info in the very beginning and knowing that one is to built TIN, points shouldn't be positioned collinearly in 2D projection...
Hope it's now little more clear what I wanted to say and what my latest interventions were intended to do - this was just like I said child play in order to make TIN out from .... data...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

rw2691

  • Newt
  • Posts: 125
Re: Triangulation (re-visited)
« Reply #692 on: July 18, 2016, 08:13:52 AM »
Ribarm,

The difference in Z that I am considering is a bottom and top of curb, wall, or cliff. Instead of averaging them by Z, it would be better to shift the XY position.

Also, if the points are deliberate, appropriate breaklines will guide the algorithmic method. The code doesn't have to be aware of a vertical sheer or inversion, and the user expects the apparent crossovers.

Rick
Hippocrates (400BC), "Life is short, craft long, opportunity fleeting, experiment treacherous, judgment difficult."

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #693 on: July 18, 2016, 09:06:01 AM »
I agree that points should be shifted - but look in the picture here :
https://www.theswamp.org/index.php?topic=9042.msg567692#msg567692

What is the difference between 841.75 and 841.67 ? Isn't that pair of points at least confusing bad pair... In this situation average Z is good approach, but then again like I said - maybe the best is to take bottom one - ground level... As for shifting, what if we have 3 or more duplicates - to shift them to where - in surrounding of rand angle for rand distance between 0.0 and fuzz? Isn't this all producing what's so called bad terrain... I know that there may exist cliffs and mountains with almost vertical sides, but who would model that type of ground... What's more interesting there may exist cliffs with angle of slope greater than 90 degree assuming you watched films like cliffhanger, but I am considering this not for computational approach of modelling, it should be more like 3d environment scanning of mountain terrain... In such situations like Colorado canyons and so on, computer algorithms are useless and so is triangulation...
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

rw2691

  • Newt
  • Posts: 125
Re: Triangulation (re-visited)
« Reply #694 on: July 19, 2016, 03:49:14 PM »
Ribarm,

Yes, the drawing that we are looking at is poor practice.

Rick
Hippocrates (400BC), "Life is short, craft long, opportunity fleeting, experiment treacherous, judgment difficult."

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #695 on: July 22, 2016, 02:02:54 PM »
Hi, again me...

Recently I coded new version of triangulate-UCS, to try to overcome collinearity problem within triangulation process itself... I know ymg, Evgeniy and other gurus have no time for playing with this, but maybe some new fresh pair of eyes are capable to solve this issue... I confirm that you must use my first overkill-pts-average-z.lsp to make sure there are no duplicate points, but for collinearity I tried to step into and over breaking of ordinary triangulate-UCS.lsp I posted in archive... I'll highlight portions for which I think are important in this revision, so that you can understand what's going on... Sadly this code won't or shouldn't break, but triangulation is done with mistakes... Please retest irot's DWG - firstly apply c:overkill-pts-average-z and then this code - it should do it, but with triangulation mistakes... I am not able to find out why is this happening, so I am for now blind to this problem... If you have some spare time and you see it, please inform us or reply if you wish to help... Best regards, M.R.

Quote
(defun c:triangulate-UCS-new ( / LM:Rand mid 3D->2D MR:Collinear-p LM:Clockwise-p LM:ConvexHull triangulate ss i p pl ell tl z ppp lay d ti )

  ;; Rand  -  Lee Mac
  ;; PRNG implementing a linear congruential generator with
  ;; parameters derived from the book 'Numerical Recipes'

  (defun LM:rand ( / a c m )
      (setq m   4294967296.0
            a   1664525.0
            c   1013904223.0
            $xn (rem (+ c (* a (cond ($xn) ((getvar 'date))))) m)
      )
      (/ $xn m)
  )

  ;; Point between 2 points or middle list of values from 2 specified lists p1 and p2

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

  ;; 3D to 2D point  -  M.R.
  ;; Returns 2D point list from supplied 3D point list or returns supplied argument if it isn't 3D point list

  (defun 3D->2D ( p )
      (if (and (listp p) (vl-every '(lambda ( x ) (eq (type x) 'REAL)) p) (eq (length p) 3))
          (list (car p) (cadr p))
          p
      )
  )

  ;; Collinear-p  -  M.R.
  ;; Returns T if p1,p2,p3 are collinear

  (defun MR:Collinear-p ( p1 p2 p3 )
      (equal  (distance p1 p3)
              (+ (distance p1 p2) (distance p2 p3))
          1e-8
      )
  )

  ;; Clockwise-p  -  Lee Mac
  ;; Returns T if p1,p2,p3 are clockwise oriented or collinear

  (defun LM:Clockwise-p ( p1 p2 p3 )
      (<  (-  (* (- (car  p2) (car  p1)) (- (cadr p3) (cadr p1)))
              (* (- (cadr p2) (cadr p1)) (- (car  p3) (car  p1)))
          )
          1e-8
      )
  )

  ;; Convex Hull  -  Lee Mac
  ;; Implements the Graham Scan Algorithm to return the Convex Hull of a list of points.

  (defun LM:ConvexHull ( lst / ch p0 )
      (cond
          (   (< (length lst) 4) lst)
          (   (setq p0 (car lst))
              (foreach p1 (cdr lst)
                  (if (or (< (cadr p1) (cadr p0))
                          (and (equal (cadr p1) (cadr p0) 1e-8) (< (car p1) (car p0)))
                      )
                      (setq p0 p1)
                  )
              )
              (setq lst (vl-remove p0 lst))
              (setq lst (append (list p0) lst))
              (setq lst
                  (vl-sort lst
                      (function
                          (lambda ( a b / c d )
                              (if (equal (setq c (angle p0 a)) (setq d (angle p0 b)) 1e-8)
                                  (< (distance p0 a) (distance p0 b))
                                  (< (if (equal c (* 2.0 pi) 1e-8) 0.0 c) (if (equal d (* 2.0 pi) 1e-8) 0.0 d))
                              )
                          )
                      )
                  )
              )
              (setq ch (list (caddr lst) (cadr lst) (car lst)))
              (foreach pt (cdddr lst)
                  (setq ch (cons pt ch))
                  (while (and (caddr ch) (LM:Clockwise-p (caddr ch) (cadr ch) pt) (not (MR:Collinear-p (3D->2D (caddr ch)) (3D->2D (cadr ch)) (3D->2D pt))))
                      (setq ch (cons pt (cddr ch)))
                  )
              )
              (reverse ch)
          )
      )
  )

  ;; Triangulate - subfunction for drawing Delunay triangulation from specified list of points with provided factor for checking weather calcualted triangulation is convex hull boundary triangulation
  ;; Returns list of 2 elements - first element is list of triangles defined by 3 points forming triangle and second element is calculated factor for forming supertriangle for next call of triangulate function for gathering correct convex hull boundary of triangulation triangles

  (defun triangulate ( pl factor / tl pll getcircumcircle xmin xmax ymin ymax cs pmin pmax t1 t2 t3 al la p el tr l n m str och ich iche i all elll loop )

    (defun getcircumcircle ( p el / circumcircle cp cr rr )

      (defun circumcircle ( p1 p2 p3 / ang c r )
        (if
          (not
            (zerop
              (setq ang (- (angle p2 p3) (angle p2 p1)))
            )
          )
          (setq c (polar p3 (+ -1.570796326794896 (angle p3 p1) ang) (setq r (/ (distance p1 p3) (sin ang) 2.0)))
               r (abs r)
          )
        )
        (list c r)
      )

      (setq cp (car (setq cr (circumcircle (3D->2D p) (3D->2D (car el)) (3D->2D (cadr el))))) rr (cadr cr))
      (if (and cp rr)
        (list (+ (car cp) rr) cp rr (list p (car el) (cadr el))) ;;; Added X max of circumscribed triangle circle as first element of (getcircumcircle) output list ;;;
        (polar p (+ (angle (car el) p) (* 0.5 pi)) (* (LM:Rand) d))
      )
    )

    (setq pll pl)
    (setq xmin (caar (setq pl (vl-sort pl '(lambda ( a b ) (< (car a) (car b))))))) ;;; Sorted pl by X ;;;
    (setq xmax (caar (vl-sort pl '(lambda ( a b ) (> (car a) (car b))))))
    (setq ymin (cadar (vl-sort pl '(lambda ( a b ) (< (cadr a) (cadr b))))))
    (setq ymax (cadar (vl-sort pl '(lambda ( a b ) (> (cadr a) (cadr b))))))
    (setq cs (list (+ xmin (/ (- xmax xmin) 2.0)) (+ ymin (/ (- ymax ymin) 2.0))))
    (setq pmin (list xmin ymin) pmax (list xmax ymax))
    (setq t1 (polar cs 0.0 (if (setq n (atoi (substr (setq str (rtos (distance pmin cs) 1 0)) (- (strlen str) 2)))) (setq rs (expt factor (+ n 2)))))) ;;; Added 0.0 in polar for rotating supertriangle t1 is max X apex ;;;
    ;;(setq t1 (polar cs 0.0 (setq rs (* 2.0 factor (distance pmin cs)))))
    (setq t2 (polar cs (+ 0.0 (/ (* 2.0 pi) 3.0)) rs))
    (setq t3 (polar cs (+ 0.0 (/ (* 4.0 pi) 3.0)) rs))
    (setq al (list (list (car t1) cs rs (list t1 t2 t3))))
    (while pl
      (setq p (car pl))
      (setq pl (cdr pl))
      (setq el nil)
      (while al
        (setq tr (car al))
        (setq al (cdr al))
        (cond
          ( (< (car tr) (car p)) ;;; Comparison of X values ;;;
            (setq tl (cons (cadddr tr) tl))
          )
          ( (< (distance p (cadr tr)) (caddr tr))
            (setq el (append (list
                              (list (car (last tr)) (cadr (last tr)))
                              (list (cadr (last tr)) (caddr (last tr)))
                              (list (caddr (last tr)) (car (last tr)))
                            ) el
                    )
            )
          )
          ( t (setq l (cons tr l)) )
        )
      )
      (if l (setq al l l nil))
      (setq m -1 all al elll el loop t)
      (while loop
        (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
          (progn
            (while el ;;; el - edge list = ((a b) (b c) (c a) (d e) (e f) (f d) ... )
              (if (or (member (reverse (car el)) el)
                     (member (car el) (cdr el))
                  )
                  (setq el (vl-remove (reverse (car el)) el)
                        el (vl-remove (car el) el)
                  )
                  (setq al (cons (getcircumcircle p (car el)) al)
                        el (cdr el)
                  )
              )
            )
            (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
              (setq loop nil)
            )
          )
          (progn
            (while
              (and
                (setq la (vl-remove-if '(lambda ( x ) (= 4 (length x))) al))
                (nth (setq m (1+ m)) la)
                (equal p (setq p (nth m la)) 1e-8)
              )
            )
            (setq al all el elll)
            (while el ;;; el - edge list = ((a b) (b c) (c a) (d e) (e f) (f d) ... )
              (if (or (member (reverse (car el)) el)
                     (member (car el) (cdr el))
                  )
                  (setq el (vl-remove (reverse (car el)) el)
                        el (vl-remove (car el) el)
                  )
                  (setq al (cons (getcircumcircle p (car el)) al)
                        el (cdr el)
                  )
              )
            )
            (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
              (setq loop nil)
            )
          )
        )
      )

    )
    (foreach tr al (setq tl (cons (cadddr tr) tl)))
    (setq tl (vl-remove-if '(lambda ( x ) (or (member t1 x) (member t2 x) (member t3 x))) tl))
    (setq pl pll)
    ;; och - outside convex hull ring of points
    ;; ich - inside convex hull ring of points (convex hull obtained from rest of points when och was removed)
    (if (null ell)
      (progn
        (setq el (mapcar '(lambda ( a b ) (list a b)) (setq och (LM:ConvexHull pll)) (cdr (reverse (cons (car och) (reverse och))))))
        (mapcar '(lambda ( x ) (setq pll (vl-remove x pll))) och)
        (setq ich (LM:ConvexHull pll))
      )
    )
    (if ich
      (progn
        (setq ell t)
        (foreach e el
          (if (not (vl-some '(lambda ( x ) (and (member (car e) x) (member (cadr e) x))) tl))
            (progn
              (setq ich (vl-sort ich '(lambda ( a b ) (< (distance a (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance b (mid (3D->2D (car e)) (3D->2D (cadr e))))))))
              (setq iche (vl-remove-if '(lambda ( x ) (> (distance x (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance (car e) (mid (3D->2D (car e)) (3D->2D (cadr e)))))) ich))
              (foreach p iche
                (if (or
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (car e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (car e) x) (member p x))) (vl-remove tr tl))
                      )
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (cadr e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (cadr e) x) (member p x))) (vl-remove tr tl))
                      )
                    )
                    (setq iche (vl-remove p iche))
                )
              )
              (setq i (length iche))
              (setq iche (cons (car e) iche) iche (cons (cadr e) iche))
              (if (null z)
                (setq z 10.0)
              )
              (setq z
                (cond
                  ( (<= i (length (car (triangulate iche 10.0))))
                    (if (>= z 10.0)
                      z
                      (setq z 10.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 25.0))))
                    (if (>= z 25.0)
                      z
                      (setq z 25.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 50.0))))
                    (if (>= z 50.0)
                      z
                      (setq z 50.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 100.0))))
                    (if (>= z 100.0)
                      z
                      (setq z 100.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 250.0))))
                    (if (>= z 250.0)
                      z
                      (setq z 250.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 500.0))))
                    (if (>= z 500.0)
                      z
                      (setq z 500.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 1000.0))))
                    (if (>= z 1000.0)
                      z
                      (setq z 1000.0)
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
    (list tl (if (null z) factor z))
  ) ;;; end of triangulate

  (prompt "\nSelect points...")
  (setq ss (ssget '((0 . "POINT"))))
  (initget 6)
  (setq d (getdist "\nPick or specify fuzz distance for collinearity modifications <0.05> : "))
  (if (null d)
    (setq d 0.05)
  )
  (setq ti (car (_vl-times)))
  (repeat (setq i (sslength ss))
    (setq p (trans (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) 0 1))
    (setq pl (cons p pl))
  )
  (setq z (cadr (triangulate pl 10.0)))
  (foreach tr (car (triangulate pl z))
    (entmake
      (list (cons 0 "3DFACE")
        (cons 10 (trans (car tr) 1 0))
        (cons 11 (trans (car tr) 1 0))
        (cons 12 (trans (cadr tr) 1 0))
        (cons 13 (trans (caddr tr) 1 0))
      )
    )
    (setq ppp (cons (trans (car tr) 1 0) ppp) ppp (cons (trans (cadr tr) 1 0) ppp) ppp (cons (trans (caddr tr) 1 0) ppp))
  )
  (setq lay (cdr (assoc 8 (entget (ssname ss 0)))))
  (command "_.ERASE" ss "")
  (while (setq p (car ppp))
    (if (not (vl-position p (setq ppp (cdr ppp))))
      (entmake
        (list (cons 0 "POINT") (cons 10 p) (cons 8 lay))
      )
    )
  )
  (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
  (princ)
)

In attached archive, this code is placed independently of "Triangulate routines by MR.lsp" which is main and have explanations for what procedures are without problems and for me correct... Still I am looking forward to solve and this ("triangulate-UCS-new - overkill-pts-average-z prior.lsp") and this routine ("overkill-pts-average-z-rem-collinearity-not good-new.lsp") which are newly added to archive and are independent... This second is little slow processing, but based on the same principle I posted here in code tags, only with it I planned to use it and then for triangulation process, just ordinary "triangulate-UCS.lsp"... It also has some issues that needs to be solved, and for some unknown reasons it's unpredictable - sometime it breaks, and some time not, but then (c:triangulate-UCS) fails or if not which is really success it makes mistakes like above mentioned code posted in tags... So see what you can do with them, of course if you have some free time...

Sincerely, M.R.
« Last Edit: July 23, 2016, 02:44:18 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #696 on: July 23, 2016, 02:38:06 AM »
Now I've put whole main algorithm inside (while loop ... ), but no avail... The same issue again... I really don't know what is happening, but this irot's DWG is somewhat with black magic... Here is the code :

Quote
(defun c:triangulate-UCS-new ( / LM:Rand mid 3D->2D MR:Collinear-p LM:Clockwise-p LM:ConvexHull triangulate ss i p pl ell tl z ppp lay d ti )

  ;; Rand  -  Lee Mac
  ;; PRNG implementing a linear congruential generator with
  ;; parameters derived from the book 'Numerical Recipes'

  (defun LM:rand ( / a c m )
      (setq m   4294967296.0
            a   1664525.0
            c   1013904223.0
            $xn (rem (+ c (* a (cond ($xn) ((getvar 'date))))) m)
      )
      (/ $xn m)
  )

  ;; Point between 2 points or middle list of values from 2 specified lists p1 and p2

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

  ;; 3D to 2D point  -  M.R.
  ;; Returns 2D point list from supplied 3D point list or returns supplied argument if it isn't 3D point list

  (defun 3D->2D ( p )
      (if (and (listp p) (vl-every '(lambda ( x ) (eq (type x) 'REAL)) p) (eq (length p) 3))
          (list (car p) (cadr p))
          p
      )
  )

  ;; Collinear-p  -  M.R.
  ;; Returns T if p1,p2,p3 are collinear

  (defun MR:Collinear-p ( p1 p2 p3 )
      (equal  (distance p1 p3)
              (+ (distance p1 p2) (distance p2 p3))
          1e-8
      )
  )

  ;; Clockwise-p  -  Lee Mac
  ;; Returns T if p1,p2,p3 are clockwise oriented or collinear

  (defun LM:Clockwise-p ( p1 p2 p3 )
      (<  (-  (* (- (car  p2) (car  p1)) (- (cadr p3) (cadr p1)))
              (* (- (cadr p2) (cadr p1)) (- (car  p3) (car  p1)))
          )
          1e-8
      )
  )

  ;; Convex Hull  -  Lee Mac
  ;; Implements the Graham Scan Algorithm to return the Convex Hull of a list of points.

  (defun LM:ConvexHull ( lst / ch p0 )
      (cond
          (   (< (length lst) 4) lst)
          (   (setq p0 (car lst))
              (foreach p1 (cdr lst)
                  (if (or (< (cadr p1) (cadr p0))
                          (and (equal (cadr p1) (cadr p0) 1e-8) (< (car p1) (car p0)))
                      )
                      (setq p0 p1)
                  )
              )
              (setq lst (vl-remove p0 lst))
              (setq lst (append (list p0) lst))
              (setq lst
                  (vl-sort lst
                      (function
                          (lambda ( a b / c d )
                              (if (equal (setq c (angle p0 a)) (setq d (angle p0 b)) 1e-8)
                                  (< (distance p0 a) (distance p0 b))
                                  (< (if (equal c (* 2.0 pi) 1e-8) 0.0 c) (if (equal d (* 2.0 pi) 1e-8) 0.0 d))
                              )
                          )
                      )
                  )
              )
              (setq ch (list (caddr lst) (cadr lst) (car lst)))
              (foreach pt (cdddr lst)
                  (setq ch (cons pt ch))
                  (while (and (caddr ch) (LM:Clockwise-p (caddr ch) (cadr ch) pt) (not (MR:Collinear-p (3D->2D (caddr ch)) (3D->2D (cadr ch)) (3D->2D pt))))
                      (setq ch (cons pt (cddr ch)))
                  )
              )
              (reverse ch)
          )
      )
  )

  ;; Triangulate - subfunction for drawing Delunay triangulation from specified list of points with provided factor for checking weather calcualted triangulation is convex hull boundary triangulation
  ;; Returns list of 2 elements - first element is list of triangles defined by 3 points forming triangle and second element is calculated factor for forming supertriangle for next call of triangulate function for gathering correct convex hull boundary of triangulation triangles

  (defun triangulate ( pl factor / tl pll getcircumcircle xmin xmax ymin ymax cs pmin pmax t1 t2 t3 al la all p el tr l n m str och ich iche i tll loop )

    (defun getcircumcircle ( p el / circumcircle cp cr rr )

      (defun circumcircle ( p1 p2 p3 / ang c r )
        (if
          (not
            (zerop
              (setq ang (- (angle p2 p3) (angle p2 p1)))
            )
          )
          (setq c (polar p3 (+ -1.570796326794896 (angle p3 p1) ang) (setq r (/ (distance p1 p3) (sin ang) 2.0)))
               r (abs r)
          )
        )
        (list c r)
      )

      (setq cp (car (setq cr (circumcircle (3D->2D p) (3D->2D (car el)) (3D->2D (cadr el))))) rr (cadr cr))
      (if (and cp rr)
        (list (+ (car cp) rr) cp rr (list p (car el) (cadr el))) ;;; Added X max of circumscribed triangle circle as first element of (getcircumcircle) output list ;;;
        (polar p (+ (angle (car el) p) (* 0.5 pi)) (* (LM:Rand) d))
      )
    )

    (setq xmin (caar (setq pl (vl-sort pl '(lambda ( a b ) (< (car a) (car b))))))) ;;; Sorted pl by X ;;;
    (setq xmax (caar (vl-sort pl '(lambda ( a b ) (> (car a) (car b))))))
    (setq ymin (cadar (vl-sort pl '(lambda ( a b ) (< (cadr a) (cadr b))))))
    (setq ymax (cadar (vl-sort pl '(lambda ( a b ) (> (cadr a) (cadr b))))))
    (setq cs (list (+ xmin (/ (- xmax xmin) 2.0)) (+ ymin (/ (- ymax ymin) 2.0))))
    (setq pmin (list xmin ymin) pmax (list xmax ymax))
    (setq t1 (polar cs 0.0 (if (setq n (atoi (substr (setq str (rtos (distance pmin cs) 1 0)) (- (strlen str) 2)))) (setq rs (expt factor (+ n 2)))))) ;;; Added 0.0 in polar for rotating supertriangle t1 is max X apex ;;;
    ;;(setq t1 (polar cs 0.0 (setq rs (* 2.0 factor (distance pmin cs)))))
    (setq t2 (polar cs (+ 0.0 (/ (* 2.0 pi) 3.0)) rs))
    (setq t3 (polar cs (+ 0.0 (/ (* 4.0 pi) 3.0)) rs))
    (setq al (list (list (car t1) cs rs (list t1 t2 t3))))
    (while pl
      (setq p (car pl))
      (setq pl (cdr pl))
      (setq m -1 all al tll tl loop t)
      (while loop
        (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
          (progn
            (setq el nil)
            (while al
              (setq tr (car al))
              (setq al (cdr al))
              (cond
                ( (< (car tr) (car p)) ;;; Comparison of X values ;;;
                  (setq tl (cons (cadddr tr) tl))
                )
                ( (< (distance p (cadr tr)) (caddr tr))
                  (setq el (append (list
                                    (list (car (last tr)) (cadr (last tr)))
                                    (list (cadr (last tr)) (caddr (last tr)))
                                    (list (caddr (last tr)) (car (last tr)))
                                  ) el
                          )
                  )
                )
                ( t (setq l (cons tr l)) )
              )
            )
            (if l (setq al l l nil))
            (while el ;;; el - edge list = ((a b) (b c) (c a) (d e) (e f) (f d) ... )
              (if (or (member (reverse (car el)) el)
                     (member (car el) (cdr el))
                  )
                  (setq el (vl-remove (reverse (car el)) el)
                        el (vl-remove (car el) el)
                  )
                  (setq al (cons (getcircumcircle p (car el)) al)
                        el (cdr el)
                  )
              )
            )
            (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
              (setq loop nil)
            )
          )
          (progn
            (while
              (and
                (setq la (vl-remove-if '(lambda ( x ) (= 4 (length x))) al))
                (nth (setq m (1+ m)) la)
                (equal p (setq p (nth m la)) 1e-8)
              )
            )
            (setq el nil al all tl tll)
            (while al
              (setq tr (car al))
              (setq al (cdr al))
              (cond
                ( (< (car tr) (car p)) ;;; Comparison of X values ;;;
                  (setq tl (cons (cadddr tr) tl))
                )
                ( (< (distance p (cadr tr)) (caddr tr))
                  (setq el (append (list
                                    (list (car (last tr)) (cadr (last tr)))
                                    (list (cadr (last tr)) (caddr (last tr)))
                                    (list (caddr (last tr)) (car (last tr)))
                                  ) el
                          )
                  )
                )
                ( t (setq l (cons tr l)) )
              )
            )
            (if l (setq al l l nil))
            (while el ;;; el - edge list = ((a b) (b c) (c a) (d e) (e f) (f d) ... )
              (if (or (member (reverse (car el)) el)
                     (member (car el) (cdr el))
                  )
                  (setq el (vl-remove (reverse (car el)) el)
                        el (vl-remove (car el) el)
                  )
                  (setq al (cons (getcircumcircle p (car el)) al)
                        el (cdr el)
                  )
              )
            )
            (if (vl-every '(lambda ( x ) (= 4 (length x))) al)
              (setq loop nil)
            )
          )
        )
      )
      (setq pll (cons p pll))
    )
    (foreach tr al (setq tl (cons (cadddr tr) tl)))
    (setq tl (vl-remove-if '(lambda ( x ) (or (member t1 x) (member t2 x) (member t3 x))) tl))
    (setq pll (reverse pll) pl pll)
    ;; och - outside convex hull ring of points
    ;; ich - inside convex hull ring of points (convex hull obtained from rest of points when och was removed)
    (if (null ell)
      (progn
        (setq el (mapcar '(lambda ( a b ) (list a b)) (setq och (LM:ConvexHull pll)) (cdr (reverse (cons (car och) (reverse och))))))
        (mapcar '(lambda ( x ) (setq pll (vl-remove x pll))) och)
        (setq ich (LM:ConvexHull pll))
      )
    )
    (if ich
      (progn
        (setq ell t)
        (foreach e el
          (if (not (vl-some '(lambda ( x ) (and (member (car e) x) (member (cadr e) x))) tl))
            (progn
              (setq ich (vl-sort ich '(lambda ( a b ) (< (distance a (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance b (mid (3D->2D (car e)) (3D->2D (cadr e))))))))
              (setq iche (vl-remove-if '(lambda ( x ) (> (distance x (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance (car e) (mid (3D->2D (car e)) (3D->2D (cadr e)))))) ich))
              (foreach p iche
                (if (or
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (car e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (car e) x) (member p x))) (vl-remove tr tl))
                      )
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (cadr e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (cadr e) x) (member p x))) (vl-remove tr tl))
                      )
                    )
                    (setq iche (vl-remove p iche))
                )
              )
              (setq i (length iche))
              (setq iche (cons (car e) iche) iche (cons (cadr e) iche))
              (if (null z)
                (setq z 10.0)
              )
              (setq z
                (cond
                  ( (<= i (length (car (triangulate iche 10.0))))
                    (if (>= z 10.0)
                      z
                      (setq z 10.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 25.0))))
                    (if (>= z 25.0)
                      z
                      (setq z 25.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 50.0))))
                    (if (>= z 50.0)
                      z
                      (setq z 50.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 100.0))))
                    (if (>= z 100.0)
                      z
                      (setq z 100.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 250.0))))
                    (if (>= z 250.0)
                      z
                      (setq z 250.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 500.0))))
                    (if (>= z 500.0)
                      z
                      (setq z 500.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 1000.0))))
                    (if (>= z 1000.0)
                      z
                      (setq z 1000.0)
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
    (list tl (if (null z) factor z))
  ) ;;; end of triangulate

  (prompt "\nSelect points on ulocked layer(s)...")
  (setq ss (ssget "_:L" '((0 . "POINT"))))
  (initget 6)
  (setq d (getdist "\nPick or specify fuzz distance for collinearity modifications <0.05> : "))
  (if (null d)
    (setq d 0.05)
  )
  (setq ti (car (_vl-times)))
  (if ss
    (progn
      (repeat (setq i (sslength ss))
        (setq p (trans (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) 0 1))
        (setq pl (cons p pl))
      )
      (setq z (cadr (triangulate pl 10.0)))
      (foreach tr (car (triangulate pl z))
        (entmake
          (list (cons 0 "3DFACE")
            (cons 10 (trans (car tr) 1 0))
            (cons 11 (trans (car tr) 1 0))
            (cons 12 (trans (cadr tr) 1 0))
            (cons 13 (trans (caddr tr) 1 0))
          )
        )
        (setq ppp (cons (trans (car tr) 1 0) ppp) ppp (cons (trans (cadr tr) 1 0) ppp) ppp (cons (trans (caddr tr) 1 0) ppp))
      )
      (setq lay (cdr (assoc 8 (entget (ssname ss 0)))))
      (command "_.ERASE" ss "")
      (while (setq p (car ppp))
        (if (not (vl-position p (setq ppp (cdr ppp))))
          (entmake
            (list (cons 0 "POINT") (cons 10 p) (cons 8 lay))
          )
        )
      )
      (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
    )
  )
  (princ)
)
« Last Edit: July 24, 2016, 12:43:26 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

pedroantonio

  • Guest
Re: Triangulation (re-visited)
« Reply #697 on: July 28, 2016, 09:10:44 AM »
Hi ymg. Any new update ?

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #698 on: July 29, 2016, 08:25:43 AM »
Hi, me again... I decided to keep simplicity of main algorithm, but on irot's DWG it also gives bad results... Of course you must (c:overkill-pts-average-z) prior to applying this version... I don't know why on that particular DWG it makes mistakes, but there is always a hope... Maybe someone will solve it without moving and redefining points like I tried with this attempt, who knows... Anyway this version is also fast and for now it's my favorite...

ymg, is everything fine, you don't reply? Just tell us you're OK, nothing more...

Quote
(defun c:triangulate-UCS-new ( / mid 3D->2D MR:Collinear-p LM:Clockwise-p LM:ConvexHull triangulate ss i p pl ell tl z ti )

  ;; Point between 2 points or middle list of values from 2 specified lists p1 and p2

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

  ;; 3D to 2D point  -  M.R.
  ;; Returns 2D point list from supplied 3D point list or returns supplied argument if it isn't 3D point list

  (defun 3D->2D ( p )
      (if (and (listp p) (vl-every '(lambda ( x ) (eq (type x) 'REAL)) p) (eq (length p) 3))
          (list (car p) (cadr p))
          p
      )
  )

  ;; Collinear-p  -  M.R.
  ;; Returns T if p1,p2,p3 are collinear

  (defun MR:Collinear-p ( p1 p2 p3 )
      (equal  (distance p1 p3)
              (+ (distance p1 p2) (distance p2 p3))
          1e-8
      )
  )

  ;; Clockwise-p  -  Lee Mac
  ;; Returns T if p1,p2,p3 are clockwise oriented or collinear

  (defun LM:Clockwise-p ( p1 p2 p3 )
      (<  (-  (* (- (car  p2) (car  p1)) (- (cadr p3) (cadr p1)))
              (* (- (cadr p2) (cadr p1)) (- (car  p3) (car  p1)))
          )
          1e-8
      )
  )

  ;; Convex Hull  -  Lee Mac
  ;; Implements the Graham Scan Algorithm to return the Convex Hull of a list of points.

  (defun LM:ConvexHull ( lst / ch p0 )
      (cond
          (   (< (length lst) 4) lst)
          (   (setq p0 (car lst))
              (foreach p1 (cdr lst)
                  (if (or (< (cadr p1) (cadr p0))
                          (and (equal (cadr p1) (cadr p0) 1e-8) (< (car p1) (car p0)))
                      )
                      (setq p0 p1)
                  )
              )
              (setq lst (vl-remove p0 lst))
              (setq lst (append (list p0) lst))
              (setq lst
                  (vl-sort lst
                      (function
                          (lambda ( a b / c d )
                              (if (equal (setq c (angle p0 a)) (setq d (angle p0 b)) 1e-8)
                                  (< (distance p0 a) (distance p0 b))
                                  (< (if (equal c (* 2.0 pi) 1e-8) 0.0 c) (if (equal d (* 2.0 pi) 1e-8) 0.0 d))
                              )
                          )
                      )
                  )
              )
              (setq ch (list (caddr lst) (cadr lst) (car lst)))
              (foreach pt (cdddr lst)
                  (setq ch (cons pt ch))
                  (while (and (caddr ch) (LM:Clockwise-p (caddr ch) (cadr ch) pt) (not (MR:Collinear-p (3D->2D (caddr ch)) (3D->2D (cadr ch)) (3D->2D pt))))
                      (setq ch (cons pt (cddr ch)))
                  )
              )
              (reverse ch)
          )
      )
  )

  ;; Triangulate - subfunction for drawing Delunay triangulation from specified list of points with provided factor for checking weather calcualted triangulation is convex hull boundary triangulation
  ;; Returns list of 2 elements - first element is list of triangles defined by 3 points forming triangle and second element is calculated factor for forming supertriangle for next call of triangulate function for gathering correct convex hull boundary of triangulation triangles

  (defun triangulate ( pl factor / tl pll getcircumcircle xmin xmax ymin ymax cs pmin pmax t1 t2 t3 al p el tr l n str och ich iche i )

    (defun getcircumcircle ( p el / circumcircle cp cr rr )

      (defun circumcircle ( p1 p2 p3 / ang c r )
        (if
          (not
            (zerop
              (setq ang (- (angle p2 p3) (angle p2 p1)))
            )
          )
          (setq c (polar p3 (+ -1.570796326794896 (angle p3 p1) ang) (setq r (/ (distance p1 p3) (sin ang) 2.0)))
               r (abs r)
          )
        )
        (list c r)
      )

      (setq cp (car (setq cr (circumcircle (3D->2D p) (3D->2D (car el)) (3D->2D (cadr el))))) rr (cadr cr))
      (if (and cp rr)
        (list (+ (car cp) rr) cp rr (list p (car el) (cadr el))) ;;; Added X max of circumscribed triangle circle as first element of (getcircumcircle) output list ;;;
        (progn
          (cond
            ( (MR:Collinear-p (3D->2D p) (3D->2D (car el)) (3D->2D (cadr el)))
              (setq cp (list (/ (+ (car p) (car (cadr el))) 2.0) (/ (+ (cadr p) (cadr (cadr el))) 2.0)))
            )
            ( (MR:Collinear-p (3D->2D (car el)) (3D->2D p) (3D->2D (cadr el)))
              (setq cp (list (/ (+ (car (car el)) (car (cadr el))) 2.0) (/ (+ (cadr (car el)) (cadr (cadr el))) 2.0)))
            )
            ( (MR:Collinear-p (3D->2D (car el)) (3D->2D (cadr el)) (3D->2D p))
              (setq cp (list (/ (+ (car (car el)) (car p)) 2.0) (/ (+ (cadr (car el)) (cadr p)) 2.0)))
            )
          )
          (setq rr (max (distance (3D->2D p) cp) (distance (3D->2D (car el)) cp) (distance (3D->2D (cadr el)) cp)))
          (list (+ (car cp) rr) cp rr (list p (car el) (cadr el)))
        )

      )
    )

    (setq pll pl)
    (setq xmin (caar (setq pl (vl-sort pl '(lambda ( a b ) (< (car a) (car b))))))) ;;; Sorted pl by X ;;;
    (setq xmax (caar (vl-sort pl '(lambda ( a b ) (> (car a) (car b))))))
    (setq ymin (cadar (vl-sort pl '(lambda ( a b ) (< (cadr a) (cadr b))))))
    (setq ymax (cadar (vl-sort pl '(lambda ( a b ) (> (cadr a) (cadr b))))))
    (setq cs (list (+ xmin (/ (- xmax xmin) 2.0)) (+ ymin (/ (- ymax ymin) 2.0))))
    (setq pmin (list xmin ymin) pmax (list xmax ymax))
    (setq t1 (polar cs 0.0 (if (setq n (atoi (substr (setq str (rtos (distance pmin cs) 1 0)) (- (strlen str) 2)))) (setq rs (expt factor (+ n 2)))))) ;;; Added 0.0 in polar for rotating supertriangle t1 is max X apex ;;;
    ;;(setq t1 (polar cs 0.0 (setq rs (* 2.0 factor (distance pmin cs)))))
    (setq t2 (polar cs (+ 0.0 (/ (* 2.0 pi) 3.0)) rs))
    (setq t3 (polar cs (+ 0.0 (/ (* 4.0 pi) 3.0)) rs))
    (setq al (list (list (car t1) cs rs (list t1 t2 t3))))
    (while pl
      (setq p (car pl))
      (setq pl (cdr pl))
      (setq el nil)
      (while al
        (setq tr (car al))
        (setq al (cdr al))
        (cond
          ( (< (car tr) (car p)) ;;; Comparison of X values ;;;
            (setq tl (cons (cadddr tr) tl))
          )
          ( (< (distance p (cadr tr)) (caddr tr))
            (setq el (append (list
                              (list (car (last tr)) (cadr (last tr)))
                              (list (cadr (last tr)) (caddr (last tr)))
                              (list (caddr (last tr)) (car (last tr)))
                            ) el
                    )
            )
          )
          ( t (setq l (cons tr l)) )
        )
      )
      (if l (setq al l l nil))
      (while el ;;; el - edge list = ((a b) (b c) (c a) (d e) (e f) (f d) ... )
        (if (or (member (reverse (car el)) el)
               (member (car el) (cdr el))
            )
            (setq el (vl-remove (reverse (car el)) el)
                  el (vl-remove (car el) el)
            )
            (setq al (cons (getcircumcircle p (car el)) al)
                  el (cdr el)
            )
        )
      )
    )
    (foreach tr al (setq tl (cons (cadddr tr) tl)))
    (setq tl (vl-remove-if '(lambda ( x ) (or (member t1 x) (member t2 x) (member t3 x))) tl))
    (setq pl pll)
    ;; och - outside convex hull ring of points
    ;; ich - inside convex hull ring of points (convex hull obtained from rest of points when och was removed)
    (if (null ell)
      (progn
        (setq el (mapcar '(lambda ( a b ) (list a b)) (setq och (LM:ConvexHull pll)) (cdr (reverse (cons (car och) (reverse och))))))
        (mapcar '(lambda ( x ) (setq pll (vl-remove x pll))) och)
        (setq ich (LM:ConvexHull pll))
      )
    )
    (if ich
      (progn
        (setq ell t)
        (foreach e el
          (if (not (vl-some '(lambda ( x ) (and (member (car e) x) (member (cadr e) x))) tl))
            (progn
              (setq ich (vl-sort ich '(lambda ( a b ) (< (distance a (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance b (mid (3D->2D (car e)) (3D->2D (cadr e))))))))
              (setq iche (vl-remove-if '(lambda ( x ) (> (distance x (mid (3D->2D (car e)) (3D->2D (cadr e)))) (distance (car e) (mid (3D->2D (car e)) (3D->2D (cadr e)))))) ich))
              (foreach p iche
                (if (or
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (car e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (car e) x) (member p x))) (vl-remove tr tl))
                      )
                      (and
                        (vl-some '(lambda ( x ) (if (and (member (cadr e) x) (member p x)) (setq tr x))) tl)
                        (vl-some '(lambda ( x ) (and (member (cadr e) x) (member p x))) (vl-remove tr tl))
                      )
                    )
                    (setq iche (vl-remove p iche))
                )
              )
              (setq i (length iche))
              (setq iche (cons (car e) iche) iche (cons (cadr e) iche))
              (if (null z)
                (setq z 10.0)
              )
              (setq z
                (cond
                  ( (<= i (length (car (triangulate iche 10.0))))
                    (if (>= z 10.0)
                      z
                      (setq z 10.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 25.0))))
                    (if (>= z 25.0)
                      z
                      (setq z 25.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 50.0))))
                    (if (>= z 50.0)
                      z
                      (setq z 50.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 100.0))))
                    (if (>= z 100.0)
                      z
                      (setq z 100.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 250.0))))
                    (if (>= z 250.0)
                      z
                      (setq z 250.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 500.0))))
                    (if (>= z 500.0)
                      z
                      (setq z 500.0)
                    )
                  )
                  ( (<= i (length (car (triangulate iche 1000.0))))
                    (if (>= z 1000.0)
                      z
                      (setq z 1000.0)
                    )
                  )
                )
              )
            )
          )
        )
      )
    )
    (list tl (if (null z) factor z))
  ) ;;; end of triangulate

  (prompt "\nSelect points...")
  (setq ss (ssget '((0 . "POINT"))))
  (setq ti (car (_vl-times)))
  (if ss
    (progn
      (repeat (setq i (sslength ss))
        (setq p (trans (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) 0 1))
        (setq pl (cons p pl))
      )
      (setq z (cadr (triangulate pl 10.0)))
      (foreach tr (car (triangulate pl z))
        (entmake
          (list (cons 0 "3DFACE")
            (cons 10 (trans (car tr) 1 0))
            (cons 11 (trans (car tr) 1 0))
            (cons 12 (trans (cadr tr) 1 0))
            (cons 13 (trans (caddr tr) 1 0))
          )
        )
      )
      (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
    )
  )
  (princ)
)

P.S. For those that downloaded archive, just add this one too, I don't want to reattach it...
Regards, M.R.
« Last Edit: July 29, 2016, 10:09:40 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

AARYAN

  • Newt
  • Posts: 72
Re: Triangulation (re-visited)
« Reply #699 on: August 10, 2016, 03:00:39 AM »
@YMG
Hi. Any new update ?
Eagerly waiting for you to sort the Contour bug out.

@Ribarm
Thanks for all your efforts. Highly appreciated.


Thanks
« Last Edit: August 10, 2016, 03:06:27 AM by AARYAN »

lamensterms

  • Mosquito
  • Posts: 1
Re: Triangulation (re-visited)
« Reply #700 on: September 06, 2016, 05:38:08 AM »
Awesome routine YMG.

Just wondering if someone could please link to the post containing the latest version?

I tested V0.5.5, and seems to work great.

Thanks.

pedroantonio

  • Guest
Re: Triangulation (re-visited)
« Reply #701 on: September 26, 2016, 10:02:18 AM »
Hi ymg. Where are you ? Are you ok ?
Any new update ?

ribarm

  • Gator
  • Posts: 2784
  • Marko Ribar, architect
Re: Triangulation (re-visited)
« Reply #702 on: September 26, 2016, 02:44:27 PM »
Hi ymg. Where are you ? Are you ok ?
Any new update ?

I can only guess like all others, but apparently something isn't ok with ymg...
 :reallysad:
(I don't want to put the very next emoticon in smileys dialog box...)
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

pedroantonio

  • Guest
Re: Triangulation (re-visited)
« Reply #703 on: November 17, 2016, 02:07:06 PM »
any updates?

ymg

  • Swamp Rat
  • Posts: 725
Re: Triangulation (re-visited)
« Reply #704 on: November 21, 2016, 01:11:01 PM »
Marko,

Everything is fine with me, just been away from CAD for the past 5 or 6 months.

Still doing renovation.

Sorry about the lack of progress.

ymg