### Author Topic: (Challenge) To draw the shortest lwpolyline  (Read 108637 times)

0 Members and 2 Guests are viewing this topic. ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #90 on: October 23, 2018, 03:09:36 AM »
Something's still wrong... If you set break point at line (setq dmin 1e+308), just when ll is evaluated and you picked 5 points, you can test list ll by :
Code: [Select]
`(vl-some '(lambda ( x ) (vl-position (reverse x) ll)) ll)`
If everyting's fine this should return nil showing that there are no reversed sub lists, but it returns 59, so 1 good sub list wasn't calculated and instead there is one reversed (nth 59 ll) - (nth 1 ll) are reverses... I am very sorry, but I think I can't track this thing, simply either order of creation of sub lists are wrong, or my estimation that there should be 60 sub lists out of 120 that are reverses is wrong for which I doubt... Simple tests for 3 and 4 points return always half (6/2 = 3) and (24/2 = 12)... So next one would be (120/2 = 60)...

And in my comment there is reverse pair (nth 11 ll) - (nth 1 ll) - look closer they are reverses - read one of them reverse and it should be exactly the same as other one... Wait there are more : (nth 2 ll) and (nth 9 ll) - check it out... And even more (nth 5 ll) and (nth 6 ll)...

When I look closer in my comment, I think that here is an error too there should be (n!/(n - 1)), so (6/2 = 3); (24/3 = 9); so next one is (120/4 = 30), and so on...
« Last Edit: October 23, 2018, 03:36:05 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)  ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #91 on: October 23, 2018, 06:14:09 AM »
I've tried it again, still no good, there are reverse sub lists - you can see it from comment - now it's little different, but not good...

Code - Auto/Visual Lisp: [Select]
1. (defun c:TSP-bruteforce-3dpoints ( / unique factorial permutate-exclude-reverses ss i pl n k l ti ll dmin x d rtn )
2.
3.   (defun unique ( l )
4.     (if l (cons (car l) (unique (vl-remove-if '(lambda ( x ) (equal x (car l) 1e-6)) l))))
5.   )
6.
7. ;|
8.   (defun factorial ( k )
9.     (if (> k 1) (setq k (* k (factorial (1- k)))) k)
10.   )
11. |;
12.
13.   (defun factorial ( k / kk r )
14.     (while (> k 0)
15.       (setq k (1- k))
16.       (if (null kk)
17.         (setq kk 1)
18.         (setq kk (1+ kk))
19.       )
20.       (if (null r)
21.         (setq r 1)
22.         (setq r (* kk r))
23.       )
24.     )
25.     r
26.   )
27.
28.   ;;;--------------------------------------------------------------------------
29.   ;;; Permutate a single list.
30.   ;;; Recursive solution by Reini Urban
31.   ;;; (permutate '(0 1 2 3)) => ((0 1 2 3) (0 1 3 2) (0 2 3 1) (0 2 1 3) (0 3 1 2) (0 3 2 1) (1 2 3 0) (1 2 0 3) (1 3 0 2) (1 3 2 0) (1 0 2 3) (1 0 3 2) (2 3 0 1) (2 3 1 0) (2 0 1 3) (2 0 3 1) (2 1 3 0) (2 1 0 3) (3 0 1 2) (3 0 2 1) (3 1 2 0) (3 1 0 2) (3 2 0 1) (3 2 1 0))
32.   ;;; Modified version for exclude reverses sublists by M.R.
33.   ;;; (permutate-exclude-reverses '(0 1 2 3)) => ((0 1 2 3) (0 1 3 2) (0 2 3 1) (0 2 1 3) (0 3 1 2) (0 3 2 1) (1 2 3 0) (1 2 0 3) (1 3 2 0) (1 0 2 3) (2 3 0 1) (2 3 1 0))
34.   ;;;--------------------------------------------------------------------------
35.   (defun permutate-exclude-reverses ( l / x1 z k kk q qq qqq lll )
36.     (cond
37.       ( (null l) l )
38.       ( (= (length l) 2) (list l (reverse l)) )
39.       ( t
40.         (if (= (length l) n)
41.             (setq z 0)
42.             (setq qqq (1- n))
43.             (repeat (1- n)
44.               (if (not (zerop (rem (setq qqq (1+ qqq)) (1- n))))
45.                 (setq lll (cons t lll))
46.                 (setq lll (cons nil lll))
47.               )
48.             )
49.             (setq lll (reverse lll))
50.           )
51.         )
52.         (repeat (length l)
53.           (foreach x (permutate-exclude-reverses (cdr l)) ;; loop1 = (foreach x '((1 2) (2 1)) [(permutate (cdr '(0 1 2))) = (permutate '(1 2)) = '((1 2) (2 1))] ; loop2 = (foreach x '((2 0) (0 2)) ; loop3 = (foreach x '((0 1) (1 0))
54.             (if (= (length l) n) ;; n - lexical global from routine processing previous steps ;; final recursion - check for reversers and (cons) only unique lists
55.                 (if (null k)
56.                   (setq k 1)
57.                   (setq k (1+ k))
58.                 )
59.                 (if (null kk)
60.                   (setq kk 1)
61.                 )
62.                 (if (= (factorial (1- n)) (1- kk))
63.                   (setq z (1+ z) kk 1 qq nil)
64.                 )
65.                 (setq q (- (factorial (1- n)) (* (factorial (1- (1- n))) z)))
66.                 (if (> z 0)
67.                   (if (and (nth (rem (1- k) (1- n)) lll) (< (length qq) q))
68.                     (setq x1 (cons (cons (car l) x) x1) qq (cons t qq))
69.                   )
70.                   (setq x1 (cons (cons (car l) x) x1))
71.                 )
72.                 (setq kk (1+ kk))
73.               )
74.               (setq x1 (cons (cons (car l) x) x1)) ;; all inner recursions ;; loop1 = x1 = '((0 2 1) (0 1 2)) ; loop2 = x1 = '((1 0 2) (1 2 0) (0 2 1) (0 1 2)) ; loop3 = x1 = '((2 1 0) (2 0 1) (1 0 2) (1 2 0) (0 2 1) (0 1 2))
75.             )
76.           )
77.           (setq l (append (cdr l) (list (car l)))) ;; l = '(0 1 2) - loop1; l = '(1 2 0) - loop2; l = '(2 0 1) - loop3
78.         )
79.         (reverse x1)
80.       )
81.     )
82.   )
83.
84.   (setq ss (ssget '((0 . "POINT"))))
85.   (repeat (setq i (sslength ss))
86.     (setq pl (cons (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) pl))
87.   )
88.   (setq pl (unique pl))
89.   (setq n (length pl))
90.   (setq k n)
91.   (repeat n
92.     (setq l (cons (setq k (1- k)) l))
93.   )
94.   (setq ti (car (_vl-times)))
95.   (setq ll (permutate-exclude-reverses l))
96.   (setq dmin 1e+308)
97.   (foreach x ll
98.     (setq x (mapcar '(lambda ( a ) (nth a pl)) x))
99.     (setq d (apply '+ (mapcar '(lambda ( a b ) (distance a b)) x (append (cdr x) (list (car x))))))
100.     (if (> dmin d)
101.       (setq dmin d rtn x)
102.     )
103.   )
104.   (vl-cmdf "_.3DPOLY")
105.   (foreach p rtn
106.     (vl-cmdf "_non" (trans p 0 1))
107.   )
108.   (vl-cmdf "_C")
109.   (prompt "\nDistance : ") (princ (rtos dmin 2 50))
110.   (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
111.   (princ)
112. )
113.
« Last Edit: October 24, 2018, 10:41:21 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)  ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #92 on: October 23, 2018, 10:09:54 AM »
I achieved what I wanted... This is good version, there are no reverse sub lists... The code is little shorter, and it was in front of my eyes all the time, just had to think more over it...

Code - Auto/Visual Lisp: [Select]
1. (defun c:TSP-bruteforce-3dpoints ( / unique factorial permutate-exclude-reverses ss i pl n k l ti ll dmin x d rtn )
2.
3.   (defun unique ( l )
4.     (if l (cons (car l) (unique (vl-remove-if (function (lambda ( x ) (equal x (car l) 1e-6))) l))))
5.   )
6.
7. ;|
8.   (defun factorial ( k )
9.     (if (> k 1) (setq k (* k (factorial (1- k)))) k)
10.   )
11. |;
12.
13.   (defun factorial ( k / kk r )
14.     (while (> k 0)
15.       (setq k (1- k))
16.       (if (null kk)
17.         (setq kk 1)
18.         (setq kk (1+ kk))
19.       )
20.       (if (null r)
21.         (setq r 1)
22.         (setq r (* kk r))
23.       )
24.     )
25.     r
26.   )
27.
28.   ;;;--------------------------------------------------------------------------
29.   ;;; Permutate a single list.
30.   ;;; Recursive solution by Reini Urban
31.   ;;; (permutate '(0 1 2 3)) => ((0 1 2 3) (0 1 3 2) (0 2 3 1) (0 2 1 3) (0 3 1 2) (0 3 2 1) (1 2 3 0) (1 2 0 3) (1 3 0 2) (1 3 2 0) (1 0 2 3) (1 0 3 2) (2 3 0 1) (2 3 1 0) (2 0 1 3) (2 0 3 1) (2 1 3 0) (2 1 0 3) (3 0 1 2) (3 0 2 1) (3 1 2 0) (3 1 0 2) (3 2 0 1) (3 2 1 0))
32.   ;;; Modified version for exclude reverses sublists by M.R.
33.   ;;; (permutate-exclude-reverses '(0 1 2 3)) => ((0 1 2 3) (0 1 3 2) (0 2 3 1) (0 2 1 3) (0 3 1 2) (0 3 2 1) (1 2 0 3) (1 3 0 2) (1 0 2 3) (1 0 3 2) (2 0 1 3) (2 1 0 3))
34.   ;;;--------------------------------------------------------------------------
35.   (defun permutate-exclude-reverses ( l / x1 z zz zp kk q qq g gg )
36.     (cond
37.       ( (null l) l )
38.       ( (= (length l) 2) (list l (reverse l)) )
39.       ( t
40.         (if (= (length l) n)
41.           (setq z 0)
42.         )
43.         (repeat (length l)
44.           (foreach x (permutate-exclude-reverses (cdr l)) ;; loop1 = (foreach x '((1 2) (2 1)) [(permutate (cdr '(0 1 2))) = (permutate '(1 2)) = '((1 2) (2 1))] ; loop2 = (foreach x '((2 0) (0 2)) ; loop3 = (foreach x '((0 1) (1 0))
45.             (if (= (length l) n) ;; n - lexical global from routine processing previous steps ;; final recursion - check for reversers and (cons) only unique lists
46.                 (if (null kk)
47.                   (setq kk 1)
48.                 )
49.                 (if (null g)
50.                   (setq g (factorial (1- n)))
51.                 )
52.                 (if (null gg)
53.                   (setq gg (/ g (1- n)))
54.                 )
55.                 (setq zp zz)
56.                 (if (= g (1- kk))
57.                   (setq z (1+ z) kk 1 qq nil zz (cons (1- z) zz))
58.                 )
59.                 (if (/= (length zp) (length zz))
60.                   (setq q (- g (* gg z)))
61.                 )
62.                 (if (> z 0)
63.                   (if (and (< (length qq) q) (not (vl-position (last x) zz)))
64.                     (setq x1 (cons (cons (car l) x) x1) qq (cons t qq))
65.                   )
66.                   (setq x1 (cons (cons (car l) x) x1))
67.                 )
68.                 (setq kk (1+ kk))
69.               )
70.               (setq x1 (cons (cons (car l) x) x1)) ;; all inner recursions ;; loop1 = x1 = '((0 2 1) (0 1 2)) ; loop2 = x1 = '((1 0 2) (1 2 0) (0 2 1) (0 1 2)) ; loop3 = x1 = '((2 1 0) (2 0 1) (1 0 2) (1 2 0) (0 2 1) (0 1 2))
71.             )
72.           )
73.           (setq l (append (cdr l) (list (car l)))) ;; l = '(0 1 2) - loop1; l = '(1 2 0) - loop2; l = '(2 0 1) - loop3
74.         )
75.         (reverse x1)
76.       )
77.     )
78.   )
79.
80.   (setq ss (ssget '((0 . "POINT"))))
81.   (repeat (setq i (sslength ss))
82.     (setq pl (cons (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) pl))
83.   )
84.   (setq pl (unique pl))
85.   (setq n (length pl))
86.   (setq k n)
87.   (repeat n
88.     (setq l (cons (setq k (1- k)) l))
89.   )
90.   (setq ti (car (_vl-times)))
91.   (setq ll (permutate-exclude-reverses l))
92.   (setq dmin 1e+308)
93.   (foreach x ll
94.     (setq x (mapcar (function (lambda ( a ) (nth a pl))) x))
95.     (setq d (apply (function +) (mapcar (function (lambda ( a b ) (distance a b))) x (append (cdr x) (list (car x))))))
96.     (if (> dmin d)
97.       (setq dmin d rtn x)
98.     )
99.   )
100.   (vl-cmdf "_.3DPOLY")
101.   (foreach p rtn
102.     (vl-cmdf "_non" (trans p 0 1))
103.   )
104.   (vl-cmdf "_C")
105.   (prompt "\nDistance : ") (princ (rtos dmin 2 50))
106.   (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
107.   (princ)
108. )
109.

P.S. 10 points are still too much for PC, so still up to 9 pts...
Regards, M.R.
« Last Edit: October 24, 2018, 09:23:23 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)  ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #93 on: October 24, 2018, 09:26:34 AM »
Still though I am boggling with this issue : Why is my firstly posted code faster than last one? IMHO it should be opposite... Who can explain it?
Marko Ribar, d.i.a. (graduated engineer of architecture) #### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #94 on: October 26, 2018, 11:02:05 PM »
Straight up Approximate Nearest Neighbor (ANN) algorithm, using nanoflann.
In some cases using Manhattan worked better than Euclidian…
red=first
yellow = last
Retired ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #95 on: October 27, 2018, 01:50:31 AM »
Daniel, chlh_jd's code is more accurate, and BTW. real TSP is considered as 3D problem too with 3D points in 3D space...
Marko Ribar, d.i.a. (graduated engineer of architecture) #### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #96 on: October 27, 2018, 05:04:43 AM »
Daniel, chlh_jd's code is more accurate
Doh! crushed

real TSP is considered as 3D problem too with 3D points in 3D space...
Retired

#### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #97 on: October 27, 2018, 05:07:36 AM »
New 3d datasets, used
std::random_device
std::mt19937
std::uniform_real_distribution

10,100,1000 and 10000 points

edit, rand 100000 seems way to big, attached 10000
« Last Edit: October 27, 2018, 10:42:16 PM by nullptr »
Retired

#### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #98 on: October 27, 2018, 05:15:59 AM »
just sort by distance (greedy)? rand10 = 44.252606
rand100 = 2049.632063
rand1000 = 84593.961921
rand10000 = 3731327.006039
« Last Edit: October 28, 2018, 11:01:10 AM by nullptr »
Retired ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #99 on: October 27, 2018, 08:05:32 AM »
1. find center point of complete point cloud
2. take closest point to center point as start
3. find path from start point to outer points using shortest distance between 2, 3, 4, 5 points cloud in one direction from inner to outer point of point cloud
4. append path 3. to main path - store last point as start for next loop
5. find next direction for next point cloud from start point (last from previous step) to center point - step 1.
6. loop 3-4 until all points are processed and calculate final path and its length

3rd step is the most important...
This is my vision and its not foolprof, but I think it may give desired in quickest time processed...
Marko Ribar, d.i.a. (graduated engineer of architecture)  ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #100 on: October 27, 2018, 02:27:19 PM »
At least it works, but it's terribly wrong in difference of my previous codes that are good but useless for 10 and more points...

Code - Auto/Visual Lisp: [Select]
1. (defun c:TSP-3dpoints-MR ( / unique ptonline unit v^v rayincone car-sort nextpt ss i pl pll c p cpcloud cpcloudr dist ti )
2.
3.   (defun unique ( l )
4.     (if l (cons (car l) (unique (vl-remove-if (function (lambda ( x ) (equal x (car l) 1e-6))) l))))
5.   )
6. ;|
7.   (defun ptonline ( p p1 p2 )
8.     (equal (distance p1 p2) (+ (distance p1 p) (distance p p2)) 1e-8)
9.   )
10. |;
11.   (defun unit ( v / d )
12.     (if (not (equal (setq d (distance '(0.0 0.0 0.0) v)) 0.0 1e-8))
13.       (mapcar (function (lambda ( x ) (/ x d))) v)
14.     )
15.   )
16.
17.   (defun v^v ( u v )
18.     (list
20.       (- (* (caddr u) (car v)) (* (car u) (caddr v)))
21.       (- (* (car u) (cadr v)) (* (cadr u) (car v)))
22.     )
23.   )
24.
25.   (defun rayincone ( apex paxis ang pray / d h p nv pv p1 p2 )
26.     (setq d 10.0)
27.     (setq h (* d (/ (sin ang) (cos ang))))
28.     (setq p (mapcar (function *) (unit (mapcar (function -) paxis apex)) (list d d d)))
29.     (setq nv (v^v (mapcar (function -) paxis apex) (mapcar (function -) pray apex)))
30.     (setq pv (v^v nv (mapcar (function -) paxis apex)))
31.     (setq p1 (mapcar (function +) p (mapcar (function *) (unit pv) (list h h h))))
32.     (setq p2 (mapcar (function +) p (mapcar (function *) (unit pv) (list (- h) (- h) (- h)))))
33.     (if (inters p1 p2 apex (mapcar (function +) apex (mapcar (function *) (unit (mapcar (function -) pray apex)) (list 100.0 100.0 100.0))))
34.       t
35.     )
36.   )
37.
38.   ;;; (car-sort '(2 4 1 3 5 1) '<) => nil
39.   ;;; (car-sort '(2 4 1 3 5 1) '<=) => 1
40.   (defun car-sort ( l f / removenth r k )
41.
42.     (defun removenth ( l n / k )
43.       (setq k -1)
44.       (vl-remove-if (function (lambda ( x ) (= (setq k (1+ k)) n))) l)
45.     )
46.
47.     (setq k -1)
48.     (vl-some (function (lambda ( a ) (setq k (1+ k)) (if (vl-every (function (lambda ( x ) (apply f (list a x)))) (removenth l k)) (setq r a)))) l)
49.     r
50.   )
51.
52.   (defun nextpt ( p ptlst )
53.     (car-sort (vl-remove p ptlst) (function (lambda ( a b ) (<= (distance p a) (distance p b)))))
54.   )
55.
56.   (setq ss (ssget '((0 . "POINT"))))
57.   (setq ti (car (_vl-times)))
58.   (if ss
59.     (repeat (setq i (sslength ss))
60.       (setq pl (cons (cdr (assoc 10 (entget (ssname ss (setq i (1- i)))))) pl))
61.     )
62.   )
63.   (setq pl (unique pl))
64.   (setq c (mapcar (function (lambda ( x ) (/ x (length pl)))) (apply (function mapcar) (cons (function +) pl))))
65.   (setq pl (vl-sort pl (function (lambda ( a b ) (< (distance c a) (distance c b))))))
66.   (while pl
67.     (while (and pl (null cpcloud))
68.       (setq p (car pl))
69.       (setq cpcloud (vl-sort (vl-remove-if-not (function (lambda ( x ) (rayincone c p (/ pi 6.0) x))) (vl-remove p pl)) (function (lambda ( a b ) (< (distance p a) (distance p b))))))
70.       (setq pll (cons p pll))
71.       (setq pl (cdr pl))
72.     )
73.     (if (and pl cpcloud)
74.         (setq pp (last cpcloud))
75.         (while (and (setq p (nextpt p (setq cpcloud (vl-remove p cpcloud)))) (not (equal p pp 1e-6)))
76.           (setq pll (cons p pll))
77.           (setq pl (vl-remove p pl))
78.         )
79.         (setq cpcloud nil)
80.       )
81.     )
82.     (if (and pl p (equal p pp 1e-6))
83.         (setq pll (cons p pll))
84.         (setq pl (vl-remove p pl))
85.         (while (and pl (null cpcloudr))
86.           (setq cpcloudr (vl-sort (vl-remove-if-not (function (lambda ( x ) (rayincone p c (/ pi 6.0) x))) (vl-remove p pl)) (function (lambda ( a b ) (< (distance p a) (distance p b))))))
87.           (setq p (car-sort pl (function (lambda ( a b ) (<= (distance p a) (distance p b))))))
88.           (setq pll (cons p pll))
89.           (setq pl (vl-remove p pl))
90.         )
91.       )
92.     )
93.     (if (and pl cpcloudr)
94.         (setq pp (car-sort cpcloudr (function (lambda ( a b ) (<= (distance c a) (distance c b))))))
95.         (while (and (setq p (nextpt p (setq cpcloudr (vl-remove p cpcloudr)))) (not (equal p pp 1e-6)))
96.           (setq pll (cons p pll))
97.           (setq pl (vl-remove p pl))
98.         )
99.       )
100.     )
101.     (setq cpcloudr nil)
102.     (if (and pl p (equal p pp 1e-6))
103.         (setq pll (cons p pll))
104.         (setq pl (vl-remove p pl))
105.       )
106.     )
107.   )
108.   (setq dist (apply (function +) (mapcar (function (lambda ( a b ) (distance a b))) pll (append (cdr pll) (list (car pll))))))
109.   (vl-cmdf "_.3DPOLY")
110.   (foreach p pll
111.     (vl-cmdf "_non" (trans p 0 1))
112.   )
113.   (vl-cmdf "_C")
114.   (prompt "\nDistance : ") (princ (rtos dist 2 50))
115.   (prompt "\nElapsed time : ") (princ (rtos (/ (- (car (_vl-times)) ti) 1000.0) 2 50)) (prompt " seconds.")
116.   (princ)
117. )
118.
Marko Ribar, d.i.a. (graduated engineer of architecture) #### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #101 on: October 27, 2018, 10:38:15 PM »
At least it works, but it's terribly wrong in difference of my previous codes that are good but useless for 10 and more points...

what is your result for rand10? I tried to run it, but select , copy paste gives me line numbers... lol
Retired ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #102 on: October 28, 2018, 06:07:52 AM »
RAND10 :
Distance : 62.71290278984382
Elapsed time : 0.04699999999999999 seconds.

RAND100 :
Distance : 6679.527823958952
Elapsed time : 0.7189999999999999 seconds.

RAND1000 :
Distance : 631481.0073386774
Elapsed time : 68.10999999999999 seconds.

RAND10000 :
I need about 10 hours of running... But I'll be back with info as soon as it finishes...
Marko Ribar, d.i.a. (graduated engineer of architecture) #### beck's bolero ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #103 on: October 28, 2018, 06:45:41 AM »
I need about 10 hours of running... But I'll be back with info as soon as it finishes...

LOL! I tried adding 2-opt to mine, had to kill the process , Im going to skip the bigger sets until I have a better algorithm
Retired ##### Re: (Challenge) To draw the shortest lwpolyline
« Reply #104 on: October 28, 2018, 07:01:22 AM »
LOL!...

But I am pretty sure that my Salesman haven't traveled neither shortest nor longest... So he enjoyed travel the most... LOL!
Marko Ribar, d.i.a. (graduated engineer of architecture) 