0

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

enter image description here

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.

Lee Mac
  • 15,615
  • 6
  • 32
  • 80
Natasha
  • 1,111
  • 5
  • 28
  • 66

1 Answers1

2

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)
        )
    )
)

enter image description here

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"
Lee Mac
  • 15,615
  • 6
  • 32
  • 80
  • Thanks a lot again. Could you please explain how this line works `(rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)` For instance, if I check for values like 10.2, the lengths of the edges aren't multiples of 10.2. The lengths are rounded to a whole number always. – Natasha Feb 13 '20 at 16:11
  • Thank you very much for the update. If you don't mind may I ask one last question, can we modify the way the `roundto` function is implemented ? For instance, if the length of an edge in the original image is `29.15` the final length returned by the `roundto` function is 24.8 (when the rounding multiple is 12.4). I'd like to return a value of 37.2 instead of 24.8. How? I'd like to do it this way -- ceil(29.15/12.4) will return a value of 3. product of 3*12.4 will be 37.2. Can we please have an implementation in this form? – Natasha Feb 18 '20 at 04:07
  • Thank you for the update. Does the cheat solution work only by changing the labels and not the actual lengths in the geometry? I understand the challenge involved , `"there could be infinitely many configurations which would satisfy the input, or none at all depending on the weights"`. But what I intend to create is atleast one configuration that has lengths given by the roundupto function. The focus is on obtaining the correct lengths of the edges. – Natasha Feb 19 '20 at 02:53