Scaling lengths in an AutoCAD diagram

人走茶凉 提交于 2021-02-11 12:08:36

问题


This is a followup to my previous post here

I've a 2D geometry created using the following code, ref.

(defun graph ( pts sls tls )

    (   (lambda ( l )
            (foreach x l (text (cdr x) (itoa (car x)) 0.0 1))
            (mapcar
               '(lambda ( a b / p q r )
                    (setq p (cdr (assoc a l))
                          q (cdr (assoc b l))
                          r (angle p q)
                    )
                    (entmake (list '(0 . "LINE") (cons 10 p) (cons 11 q) '(62 . 8)))
                    (text
                        (mapcar '(lambda ( x y ) (/ (+ x y) 2.0)) p q)
                        (rtos (distance p q) 2)
                        (if (and (< (* pi 0.5) r) (<= r (* pi 1.5))) (+ r pi) r)
                        2
                    )
                )
                sls tls
            )
        )
        (mapcar 'cons (vl-sort (append sls tls) '<) pts)
    )
)
(defun text ( p s a c )
    (entmake
        (list
           '(0 . "TEXT")
            (cons 10 p)
            (cons 11 p)
            (cons 50 a)
            (cons 01 s)
            (cons 62 c)
           '(40 . 2)
           '(72 . 1)
           '(73 . 2)
        )
    )
)

Input:

(graph
   '((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25))
   '(1 1 1 1 2 2 3 4 4 5 6)
   '(2 3 4 5 3 6 6 5 7 7 7)
)

The resulting image

From the coordinates that are given as inputs, the above 2D diagram is created. I want to scale the lengths in the image i.e The lengths have to be multiple of a scalar x (x can be any value). let's say x =10, the lengths have to be scaled to 20.0, 30.0, 50.0, 70.0 and so on. This will result in a shift in coordinates of points at the junctions.

Any suggestions on how to implement the scaling in AutoLisp will be really helpful.


回答1:


In general, there are simply not enough constraints on this problem: for an arbitrary given set of connected nodes and weights, there could be infinitely many configurations which would satisfy the input, or none at all depending on the weights (distances) supplied.

For example, if you were to reduce the problem to 2 connected nodes with a given weight:

(graph '(1) '(2) '(10.0))

Fixing the position of one of the nodes would mean that the second node could be positioned at one of the infinitely many points on a circle of radius 10.0 centered at the first node.

Assuming that you choose an arbitrary position on this circle for the second note, adding a third node connected to the first two then involves solving the intersection between two circles whose radii are equal to the weights between the nodes (that is, if they even intersect).

For every successive node added, you would need to find a common intersection in a set of circles centered at every node to which the new node is connected, whose radii are equal to the weight between the nodes.


There is of course a cheat's solution:

(defun graph ( pts sls tls )

    (   (lambda ( l )
            (foreach x l (text (cdr x) (itoa (car x)) 0.0 1))
            (mapcar
               '(lambda ( a b / p q r )
                    (setq p (cdr (assoc a l))
                          q (cdr (assoc b l))
                          r (angle p q)
                    )
                    (entmake (list '(0 . "LINE") (cons 10 p) (cons 11 q) '(62 . 8)))
                    (text
                        (mapcar '(lambda ( x y ) (/ (+ x y) 2.0)) p q)
                        (rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)
                        (if (and (< (* pi 0.5) r) (<= r (* pi 1.5))) (+ r pi) r)
                        2
                    )
                )
                sls tls
            )
        )
        (mapcar 'cons (vl-sort (append sls tls) '<) pts)
    )
)
(defun text ( p s a c )
    (entmake
        (list
           '(0 . "TEXT")
            (cons 10 p)
            (cons 11 p)
            (cons 50 a)
            (cons 01 s)
            (cons 62 c)
           '(40 . 2)
           '(72 . 1)
           '(73 . 2)
        )
    )
)

Here, the line:

(rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)

Is rounding the distance to the nearest multiple of 10 and then converting the result to a string with zero decimal place precision.

If you wanted to proceed using this method in general, you might want to define a general rounding function such as the following, which will round to any supplied multiple:

(defun roundto ( x m / d r )
    (setq d (getvar 'dimzin))
    (setvar 'dimzin 8)
    (setq r (rtos (* m (atof (rtos (/ x (float m)) 2 0))) 2 16))
    (setvar 'dimzin d)
    r
)

And you would then replace:

(rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)

With:

(roundto (distance p q) 10.0)

Where 10.0 represents the rounding multiple.


Following your question in the comments, you could use the following function to round up to the next multiple (to a precision of 1e-8):

(defun roundupto ( x m / d r )
    (setq d (getvar 'dimzin))
    (setvar 'dimzin 8)
    (setq r (rtos (* m (fix (+ 1 -1e-8 (/ x (float m))))) 2 8))
    (setvar 'dimzin d)
    r
)

For example:

_$ (roundupto 12.4 12.4)
"12.4"
_$ (roundupto 12.41 12.4)
"24.8"
_$ (roundupto 29.15 12.4)
"37.2"


来源:https://stackoverflow.com/questions/60135396/scaling-lengths-in-an-autocad-diagram

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!