Jump to content

LISP - Automatic dimensions according to set rules


Kyler

Recommended Posts

Hello everyone,

 

I work with a glazing company and am trying to write an AutoLISP command that will automate a large part of our job by dimensioning glass panels with holes and cutout in the format that our supplier prefers.

 

I will attach a photo here to show what I have done so far.

dimensions.jpg

 

The rectangle on the left shows what I would like the dimensions to look like.

The rectangle on the right shows what my LISP routine currently does.

I am having trouble writing the logic to dimension it in the way that I want.

 

Rules it should follow are:

1) dimensions strings should be made to the corner nearest to the hole

2) if two holes are in-line, the dimension should pass through the closer hole

3) if two dimensions go to the same corner, they should stack at 3" intervals (TYP. offset set for DIMBASELINE)

4) Dimension strings should always be 3" behind the larger dimension above them (See the 5" measure at the top left)

 

However, these rules only hold true for the "rectangle" shape option. In the final version of the routine, I am looking to have an easily expandable list of rules that I can modify and tweak per-shape.

 

I have attached a test drawing and the current version of my LISP routine below. The code for dimensioning rules on the rectangle is found on lines 436-494.

 

Any help figuring this out would be much appreciated.

 

Thank you!

 

Drawing File: autodimtest.dwg

Current LISP: autoDim.lsp

Link to comment
Share on other sites

Thats a big chunck of code, without spending hours trying to figure it out. I would look at dimensioning twice on two different layers, maybe even more as you build the shapes. The code size seems excessive for rather simple shapes rectangs etc maybe I am looking at it wrong.

 

Ps like the shape block.

Link to comment
Share on other sites

Thanks for the reply, BIGAL. :)

 

Could you elaborate what you mean by dimensioning on two different layers?

Are you referring to Layers as defined in the Layer Property Manager?

 

I am mostly new to programming, so I am sure there is a lot of simplification that could be done.

 

Currently the program works like this:

• Analyzes the polyline, reforming it if necessary to ensure the start point is the bottom-left-most corner and going clockwise from there

• Saves the coordinates of each vertex to vars A through H (there will only ever be a max of 8 points in all the shapes defined)

• Saves a bounding-box wrapping the outermost vertexes of the polyline. This works to define the dimension locations. I can offset it by 3" and then place the first dim, and again for the next dim, to allow for dim stacking

• Saves coordinates of all holes into a list ((x1 y1) (x2 y2) ...) and then can sort the list by minX, minY, etc.

• Then it just starts placing dimensions based on this information. The basic dim rules for most of the shapes are already in there with the custom function drawDim, following the rules laid out in that shape block I made.

 

The issue I have with the holes is that the stacking has to reset when dimensioning to a different corner on the same side. I think I need the program to recognise what dims came before it and what ones will be coming after it so it can dynamically decide what stacking level to place the dimension, rather than rigidly increasing the bounding box size with every action. You can see that happening with the rectangle on the right in my first post.

 

There is a couple of reasons that the code is so large:

I opted to define rules for dimensioning for each shape individually, of which there are 67 different shapes, because this will help me expand on it in the future.

The other reason it is so long is because the command is also used as a double check to make sure the shape is drawn correctly. 60% of the code is error messages checking that certain corners are square and sides are equal length, etc.

Link to comment
Share on other sites

The final ouput your after is a variation of what your already producing so like the stacked dim 12 15 20 goes on layer DIM1 staright away though you do dim 12 on top of object but on layer Dim2. Yes it means flipping layers all the time (setvar "clayer" "dim2"). Its just me but to write something that has already finished according to rules and then try again to redo it is much harder, it will mean check rule 22 if true do rule 22A. Again you may need a 3rd layer DIM3 which is dims always visible. Using 2 layouts should be able to see result is correct by turning off correct layers in viewports.

Link to comment
Share on other sites

Thank you for the ideas.

 

I wanted to do it without adding any additional layers to the drawing. After some thinking I have come up with a code-only solution that works for me. I will post it here for anyone who is curious or who may like to see it.

 

The code I added:

(if (setq holes	(orgCoords holes "BL"))
(progn
	(foreach j holes
		(cond
			( (= (nearCoor j glassBorderPts) a)
				(if (or  (isInline j holes "y" "top")
					(not (isInline j holes "y" nil)))
					(setq orderedHoles (addHole j orderedHoles "bottom" a)))
				(if (or  (isInline j holes "x" "right")
					(not (isInline j holes "x" nil)))
					(setq orderedHoles (addHole j orderedHoles "left" a)))
			)
			( (= (nearCoor j glassBorderPts) b)
				(cond
					( (isInline j holes "y" "top") (setq orderedHoles (addHole j orderedHoles "bottom" a)) )
					( (not (isInline j holes "y" nil)) (setq orderedHoles (addHole j orderedHoles "top" b)) )
				);cond
				(if (or  (isInline j holes "x" "right")
					(not (isInline j holes "x" nil)))
					(setq orderedHoles (addHole j orderedHoles "left" b)))
			)
			( (= (nearCoor j glassBorderPts) c)
				(cond
					( (isInline j holes "y" "top") (setq orderedHoles (addHole j orderedHoles "bottom" d)) )
					( (not (isInline j holes "y" nil)) (setq orderedHoles (addHole j orderedHoles "top" c)) )
				);cond
				(cond
					( (isInline j holes "x" "right") (setq orderedHoles (addHole j orderedHoles "left" b)) )
					( (not (isInline j holes "x" nil)) (setq orderedHoles (addHole j orderedHoles "right" c)) )
				);cond 
			)
			( (= (nearCoor j glassBorderPts) d)
				(if (or  (isInline j holes "y" "top")
					(not (isInline j holes "y" nil)))
					(setq orderedHoles (addHole j orderedHoles "bottom" d)))
				(cond
					( (isInline j holes "x" "right") (setq orderedHoles (addHole j orderedHoles "left" a)) )
					( (not (isInline j holes "x" nil)) (setq orderedHoles (addHole j orderedHoles "right" d)) )
				);cond 
			)
		);cond
	);foreach
	(setq orderedHoles (orgCoords orderedHoles (list "bottom" a "LB")))
	(setq orderedHoles (orgCoords orderedHoles (list "bottom" d "RB")))
	(setq orderedHoles (orgCoords orderedHoles (list "left" a "BL")))
	(setq orderedHoles (orgCoords orderedHoles (list "left" b "TL")))
	(setq orderedHoles (orgCoords orderedHoles (list "top" b "LT")))
	(setq orderedHoles (orgCoords orderedHoles (list "top" c "RT")))
	(setq orderedHoles (orgCoords orderedHoles (list "right" c "TR")))
	(setq orderedHoles (orgCoords orderedHoles (list "right" d "BR")))
	(setq bounding (drawHoleDims orderedHoles bounding))
);progn
);if

 

isInline function:

(defun isInline (pt pts axis dir / j ans flag)
;Checks if a point is inline with any point in a list of points,
;and if it is the furthest point inline point in a given direction
;pt		:	List - Coordinate pair (x y) for point to check
;pts		:	List - List of coordinate pairs for points to check against
;axis		:	String - Which axis to check for other points ("x" or "y")
;dir		:	String - Direction to check if point is the furthest ("left", "bottom", etc) pass nil to check for inline only
;Returns	:	T if holes are inline AND hole is furthest on specified direction, or if holes exist inline while dir=nil
;				Nil if no holes are inline OR holes are inline but pt is not furthest in specified direction
(foreach j pts
	(cond
		( (= j pt) )
		( (and (= axis "x") (null dir) (equal (cadr pt) (cadr j) fuzz)) (setq ans T) )
		( (and (= axis "y") (null dir) (equal (car pt) (car j) fuzz)) (setq ans T) )
		( (and (= axis "x") (= dir "left")  (equal (cadr pt) (cadr j) fuzz)		 (< (car pt) (car j))) (setq ans T) )
		( (and (= axis "x") (= dir "left")  (equal (cadr pt) (cadr j) fuzz) (not (< (car pt) (car j)))) (setq flag T) )
		( (and (= axis "x") (= dir "right") (equal (cadr pt) (cadr j) fuzz)		 (> (car pt) (car j))) (setq ans T) )
		( (and (= axis "x") (= dir "right") (equal (cadr pt) (cadr j) fuzz) (not (> (car pt) (car j)))) (setq flag T) )
		( (and (= axis "y") (= dir "bottom")  (equal (car pt) (car j) fuzz)	   (< (cadr pt) (cadr j))) (setq ans T) )
		( (and (= axis "y") (= dir "bottom")  (equal (car pt) (car j) fuzz) (not (< (cadr pt) (cadr j)))) (setq flag T) )
		( (and (= axis "y") (= dir "top") (equal (car pt) (car j) fuzz)	   (> (cadr pt) (cadr j))) (setq ans T) )
		( (and (= axis "y") (= dir "top") (equal (car pt) (car j) fuzz) (not (> (cadr pt) (cadr j)))) (setq flag T) )
	);cond
);foreach
(if flag (setq ans nil))
ans
);defun

 

drawHoleDims function:

(defun drawHoleDims (holes ofst / finalBounding i j k l maxi)
;Draws dimensions for all coordinates in the ordered coordinate list passed
;holes		:	List - Ordered list of holes to dimension (list created with addHole command)
;ofst		:	List - Two sets of coordinates ((x1 y1) (x2 y2)) for bounding box to offset dimensions to
;Returns	:	List - New sets of coordinates ((x1 y1) (x2 y2)) for bounding box of final dimensions
(setq finalBounding ofst)
(foreach j holes
	(setq maxi 0)
	(foreach k (cdr j)
		(if (> (1- (vl-list-length k)) maxi) (setq maxi (1- (vl-list-length k))))
	);foreach
	(foreach k (cdr j)
		(setq i maxi)
		(foreach l (reverse (cdr k))
			(setq i (1- i))
			(drawDim l (car k) (if (/= i 0) (growbound ofst (car j) (* i ofstTYP)) ofst) (car j) nil)
		);foreach
	);foreach
	(setq finalBounding (growbound finalBounding (car j) (* maxi ofstTYP)))
);foreach
);defun

 

Entire Code: autoDim.lsp

Test Drawing: autodimtest.dwg

 

To use, run the command and select the entire un-dimensioned border including the shape block and all holes.

 

It currently supports only the RECTANGLE shape but it will be trivial to add logic for the rest with the way I have it set up.

 

If anyone looking at this code notices any optimisations I could make, please let me know!

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...