Menessis Posted June 9, 2023 Posted June 9, 2023 I am a novice when it comes to scrips. A buddy of mine asked if I can draw up a plan for pavers for his driveway. So there are 4 basic sizes 8" x 8", 16" x 8", 16" x 16" and 24" x 16". I can make myself crazy trying to put this together in some sort of random form that all fits into a given space (a multiple of 8" of course). Or maybe some sort of script? Given the dimensions of the driveway which in the case is just a rectangle that I could select the corners and let AutoCad fill it. Sounds easy but I bet it's not! Thanks Menessis Quote
Emmanuel Delay Posted June 12, 2023 Posted June 12, 2023 Could you draw a small sample of the result you're going for? I think yes, it's doable. Quite a challenge though 1 Quote
CANDOWE Posted June 12, 2023 Posted June 12, 2023 I Have seen someone realized that function using C++ language. Quote
Steven P Posted June 12, 2023 Posted June 12, 2023 Similar to above, quite a challenge to to make up a LISP for this, probably for a single job it would be quicker to do it manually than write, verify, test and then use a LISP. Generally LISP saves time if you are going go to repeat the task a few times, but a single time usually quicker without it. There might be something out there already though. If it was me I would fill the drive with 8x8 rectangles - just an array and then replace then with the larger ones to get the random pattern Quote
phjlc Posted June 12, 2023 Posted June 12, 2023 I suggest that you draw the pattern and make a custom hatch of that pattern Quote
Steven P Posted June 12, 2023 Posted June 12, 2023 (edited) EDIT: This will draw random pavers at the top and bottom of the drive: Assuming the drive is rectangular and aligned to the X-Y (not rotated). Just need to fill in the centre part. Quick thing to note, I haven't added anything in here in the case that the random selection goes over the width of the drive - there could be an overlap, is this important to avoid or can they cut pavers too? Noting here though that the cut edge will currently be the same edge at both ends. As a quick LISP for a one off design this might be enough to make up a a random pattern? (defun c:testthis ( / rects rectdim BlockList MyDist MyRiot MyBlock) ;;;;Change this to user specified details;;;; (setq rects (list '(8 8) '(16 8) '(16 16) '(24 16))) ;; block Dimensions (setq basept1 (getpoint "Select LOWER LEFT corner: ")) (setq basept2 (getpoint "Select TOP RIGHT corner: ")) (setq basept (list (car (vl-sort (list (car basept1) (car basept2) ) '<)) (car (vl-sort (list (cadr basept1) (cadr basept2) ) '<)) )) (setq rectdim (list (abs (- (car basept1) (car basept2) ) ) (abs (- (cadr basept1) (cadr basept2) ) ) )) ;;Draw rectangle (command "rectang" basept1 basept2) ;;;;End user specified details;;;; (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) ) (defun LM:randrange ( a b ) (+ (min a b) (fix (* (LM:rand) (1+ (abs (- a b)))))) ) (defun getsquares ( rectdim rects / MyDist MyRot MyBlock BlockList) (setq BlockList (list)) (setq MyDist 0) (while (< MyDist (nth 0 rectdim)) (setq MyRot (LM:randrange 1 2) ) ; rotation 1 or 2 (setq MyBlock (nth (LM:randrange 0 (- (length rects) 1)) rects )) ; selected block (if (= MyRot 2)(setq MyBlock (reverse MyBlock)) ) rotate block (setq BlockList (append Blocklist (list MyBlock))) (setq MyDist (+ MyDist (car MyBlock))) ) ; end while BlockList ) (setq base basept) (setq BlockListBase (getsquares rectdim rects) ) ;;Draw recrangles, base of drive (foreach x BlockListBase (command "rectang" base (mapcar '+ base x)) (setq base (mapcar '+ base (list (car x) 0))) ) ; end foreach (setq base (list (car basept) (+ (cadr basept)(cadr rectdim)))) (setq BlockListTop (getsquares rectdim rects) ) ;;Draw recrangles, top of drive (foreach x BlockListTop (command "rectang" base (mapcar '+ base x)) (command "mirror" (entlast) "" base (mapcar '+ base (list 100 0 0)) "Y") (setq base (mapcar '+ base (list (car x) 0))) ) ; end foreach ) Noting also that there might be a different way to do this, not by 'row' but randomly placing blocks in a scatter way largest first and filling in the spaces with smaller and smaller blocks Edited June 12, 2023 by Steven P Quote
marko_ribar Posted June 12, 2023 Posted June 12, 2023 You could try with random drawing of rectangles desired width and length, but to fit, so that runnings from left to right and from bottom to top match... Here is my code, but you'll have to draw samples manually... And in fact everything should be orthogonal... https://www.theswamp.org/index.php?topic=53697.0 (you have to be logged at theswamp.org to access...) 2 Quote
eldon Posted June 12, 2023 Posted June 12, 2023 On 6/9/2023 at 7:14 PM, Menessis said: I am a novice when it comes to scrips. A buddy of mine asked if I can draw up a plan for pavers for his driveway. So there are 4 basic sizes 8" x 8", 16" x 8", 16" x 16" and 24" x 16". I can make myself crazy trying to put this together in some sort of random form that all fits into a given space (a multiple of 8" of course). Or maybe some sort of script? Given the dimensions of the driveway which in the case is just a rectangle that I could select the corners and let AutoCad fill it. Sounds easy but I bet it's not! Thanks Menessis Has your buddy tried searching the web? The paving companies either have a good programme, or someone who has spent years figuring it out! Here is a picture I took off the web - I wonder what programme drew it! Quote
marko_ribar Posted June 12, 2023 Posted June 12, 2023 Picture attached is very interesting... The trick in solving big rectangle is that every piece is Euclidian : dxd - smallest rectangle/square : D=1D - square , C=2D , B=4D, A=6D... BIG RECTANGLE = 15 D x 11 D Quote
Tsuky Posted June 12, 2023 Posted June 12, 2023 I made my living room in natural stone with the Roman opus model. There are several possible models. I made a drawing to help me with the pose, I attach the DXF for example opus romain.dxf 1 Quote
BIGAL Posted June 12, 2023 Posted June 12, 2023 (edited) This is a bit like a game I play on my phone, I can only think start at a corner and use a code like A B C D for shape but auto insert in some way so they align correctly even if wrong corner is picked. Like the Opus Romain but that is a repeating pattern not directly obvious. Laid a timber floor recently and did the same tried to jigsaw it to reduce cut offs. All timber lengths were different 600-3000+ so just laid on floor a few at a time and moved them around. Just suggesting may be the way to go with the contractor. Edited June 12, 2023 by BIGAL Quote
SLW210 Posted June 13, 2023 Posted June 13, 2023 Like eldon stated, most paver companies have programs for this. You might search around for nesting LISP/Programs and see if those could work. Quote
Menessis Posted June 13, 2023 Author Posted June 13, 2023 Thanks for all the tips guys. What I wound up doing is taking a pattern from the manufacturer which is an "L" shape. Made that a block. Then just manually copied that into place. Now when I get the dimensions of the driveway I will just lay that over and line it up. Its a mind bender just to dream up the logic in order to make a script! Menessis Quote
ronjonp Posted June 13, 2023 Posted June 13, 2023 2 minutes ago, Menessis said: Thanks for all the tips guys. What I wound up doing is taking a pattern from the manufacturer which is an "L" shape. Made that a block. Then just manually copied that into place. Now when I get the dimensions of the driveway I will just lay that over and line it up. Its a mind bender just to dream up the logic in order to make a script! Menessis Kinda sounds like Tetris! Set your SNAPANG correctly then rotate the block in 90 degree increments ? Quote
Emmanuel Delay Posted June 14, 2023 Posted June 14, 2023 (edited) I made something. A few remarks: - For my ease I made it 1 unit = 1 smallest paver. So I ignored the 8" size. You can always scale the result by 8 at the end. - The driveway starts at 0,0 . Then you pick a second point (both X and Y must be positive). Start small. (x=10, y=25 for example) - The algorithm will pick a random point, then a random pavers size (we skip the smallest paver), and a random orientation (horizontal or vertical) If there's room for that paver there, then it's drawn there. Else skip. This is done 3000 times (you can change this number) - At the end the smallest paver fills all the rest at the end command PAVER The script needs some cleanup; I just got it working. I might edit the script to clean it up. TODO. It might be nice to put a factor in the pavers, so that big pavers are randomly selected more or less often than small ones. You can add pavers sizes to the pavers_size list. Make sure the first size is 1,1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; DRAW (defun drawLWPoly (lst cls) (entmakex (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 70 cls)) (mapcar (function (lambda (p) (cons 10 p))) lst))) ) (defun drawLWPoly_color (lst cls col) (entmakex (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 62 col) (cons 70 cls)) (mapcar (function (lambda (p) (cons 10 p))) lst))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ROUNDING ;; http://www.lee-mac.com/round.html ;; Round Multiple - Lee Mac ;; Rounds 'n' to the nearest multiple of 'm' (defun LM:roundm ( n m ) (* m (fix ((if (minusp n) - +) (/ n (float m)) 0.5))) ) ;; Round Up - Lee Mac ;; Rounds 'n' up to the nearest 'm' (defun LM:roundup ( n m ) ((lambda ( r ) (cond ((equal 0.0 r 1e-8) n) ((< n 0) (- n r)) ((+ n (- m r))))) (rem n m)) ) ;; Round Down - Lee Mac ;; Rounds 'n' down to the nearest 'm' (defun LM:rounddown ( n m ) ((lambda ( r ) (cond ((equal 0.0 r 1e-8) n) ((< n 0) (- n r m)) ((- n r)))) (rem n m)) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; RANDOM number generator ;; http://www.lee-mac.com/random.html ;; 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) ) ;; Random in Range - Lee Mac ;; Returns a pseudo-random integral number in a given range (inclusive) (defun LM:randrange ( a b ) (+ (min a b) (fix (* (LM:rand) (1+ (abs (- a b)))))) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Replace item in list (defun replace-element (index newelement lst) (subst newelement (nth index lst) lst) ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; XY coordinates to array index ;; vice versa is just (nth index pavers) (defun yx2index ( x y pavers / res i) ;;(setq x_ (rem x w)) ;;(setq y_ (LM:rounddown (/ ind w) 1.0)) (setq i 0) (foreach cel pavers (if (and (= x (nth 0 cel)) (= y (nth 1 cel)) ) (setq res i) ) (setq i (+ i 1)) ) res ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defun c:pavers ( / bl tr p1 p2 driveway_pl pixels pix w h x y a rnd rot ind ind_ blk paver pixelsfree counter stopcounter) (setq stopcounter 3000) ;; number of times it will try to put a randow paver on a random place (setq pavers_size (list (list 1 1) (list 2 1) (list 2 2) (list 3 2) )) ;;(setq p1 (getpoint "\nPoint bottom left: ")) (setq p1 (list 0.0 0.0)) (setq p2 (getcorner p1 "\nPoint top right: ")) ;; now round down the coordinates to multiples of the size of the smallest pavers (setq bl (list (LM:rounddown (nth 0 p1) 1 ) (LM:rounddown (nth 1 p1) 1 ) )) (setq tr (list (LM:rounddown (nth 0 p2) 1 ) (LM:rounddown (nth 1 p2) 1 ) )) ;; draw driveway (drawLWPoly (list (list (nth 0 bl) (nth 1 bl) ) (list (nth 0 tr) (nth 1 bl) ) (list (nth 0 tr) (nth 1 tr) ) (list (nth 0 bl) (nth 1 tr) ) ) 1) ;; make a list of pixels (setq w (- (nth 0 tr) (nth 0 bl))) (setq h (- (nth 1 tr) (nth 1 bl))) ;; round down and turn into integer (setq w (atoi (rtos w 2 0))) (setq h (atoi (rtos h 2 0))) (setq pixels (list)) (setq x 0) (setq y 0) (repeat h (setq x 0) (repeat w (setq pixels (append pixels (list (list x y nil) ;; the nil means the pixel is empty and can/must be filled by a paver ))) (setq x (+ x 1)) ) (setq y (+ y 1)) ) ;;(princ pixels) ;;(while (/= "a" (getstring "\nPress enter for random pixel") ) (setq counter 0) (while (< counter stopcounter) ;; random pixel (setq rnd (LM:randrange 0 (- (length pixels) 1))) ;; random orientation (0 = 0°, 1 = 90°) ;;(setq rot (/ (* pi (LM:randrange 0 1)) -2) ) (setq rot (LM:randrange 0 1)) ;; 0 means horizontal, 1 means vertical (this doesn't matter for square pavers obviously) ;; random paver block. ind is the index of the paver. ;; Let's skip the smallest paver, as it will fill up any place that doesn't fit any bigger. ;;(setq blk (nth (setq ind (LM:randrange 1 (length pavers_name))) pavers_name )) (setq paver (nth (setq ind (LM:randrange 1 (- (length pavers_size) 1))) pavers_size )) (setq pix (nth rnd pixels)) ;; now put a paver there ;;(drawInsert_rot (list (nth 0 pix) (nth 1 pix)) blk rot) (setq pixels_taken (list)) ;; draw paver (if (= 0 rot) ;; horizontal T ;; vertical (setq paver (list (nth 1 paver) (nth 0 paver))) ;; swap Width / height ) (progn ;; pixels taken: ;; width = (nth 0 paver) ;; height = (nth 1 paver) (setq x (nth 0 pix)) (setq y (nth 1 pix)) (setq pixelsfree T) (repeat (nth 1 paver) (setq x (nth 0 pix)) (repeat (nth 0 paver) (setq ind_ (yx2index x y pixels)) (setq pixels_taken (append pixels_taken (list ind_))) (if (or (= ind_ nil) ;; pixels outside the driveway (nth 2 (nth ind_ pixels)) ;; pixels already taken ) (setq pixelsfree nil) ) (setq x (+ x 1)) ) (setq y (+ y 1)) ) (if pixelsfree (progn (foreach a pixels_taken ;; set (nth 2) to true (setq pixels (replace-element a (list (nth 0 (nth a pixels)) (nth 1 (nth a pixels)) T) pixels)) ) (drawLWPoly_color (list (list (nth 0 pix) (nth 1 pix) ) (list (+ (nth 0 pix) (nth 0 paver) ) (nth 1 pix) ) (list (+ (nth 0 pix) (nth 0 paver) ) (+ (nth 1 pix) (nth 1 paver)) ) (list (nth 0 pix) (+ (nth 1 pix) (nth 1 paver)) ) ) 1 ind ) ) ;;(princ "*") ) ) ;;(setq (nth 1 pix)) (setq counter (+ counter 1)) ) ;;(princ pixels) ;; fill the rest with 1/1 pavers (foreach pix pixels (if (not (nth 2 pix)) (drawLWPoly_color (list (list (nth 0 pix) (nth 1 pix) ) (list (+ (nth 0 pix) 1 ) (nth 1 pix) ) (list (+ (nth 0 pix) 1 ) (+ (nth 1 pix) 1) ) (list (nth 0 pix) (+ (nth 1 pix) 1) ) ) 1 0 ) ) ) ) Edited June 14, 2023 by Emmanuel Delay 2 1 Quote
Steven P Posted June 14, 2023 Posted June 14, 2023 Nice, I was thinking something similar to fill in the drive - mine above only worked for the edges which was easy enough. Random place a rectangle and check it fits. My thought was to start with the largest paver, place a random number of them, then the next sizes down to the smallest size - which might have worked to change the proportions of pavers - repeat a loop place say 1 largest, 2 next size and 3 next to smallest then repeat ? 1 Quote
Emmanuel Delay Posted June 14, 2023 Posted June 14, 2023 The way of randomly selecting a paver can be improved. I should do a weighed randomizer. So the user can select whether they want more or fewer big pavers as opposed to the smaller ones. 1 Quote
marko_ribar Posted June 15, 2023 Posted June 15, 2023 In combination with this : https://www.theswamp.org/index.php?topic=53697.msg583798#msg583798 , you can make associative hatch and make walls or ways - ground paths remarkable perfect... Thanks for your effort Emmanuel... P.S. You have to be member to access the link I provided... 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.