Converting a graph to a 2D diagram
Asked Answered
O

1

7

I want to create a 2D diagram like the following,

enter image description here The above image has been created using Graph in MATLAB (ref)

s = [1 1 1 1 2 2 3 4 4 5 6];
t = [2 3 4 5 3 6 6 5 7 7 7];
weights = [50 10 20 80 90 90 30 20 100 40 60];
G = graph(s,t,weights)
plot(G,'EdgeLabel',G.Edges.Weight)

The information is stored as nodes, edges, edge weight of a graph. I'd like to create a 2D CAD drawing using this information. The length of lines can be specified using edge weights. However, I am not sure how the angles can be retrieved from the graph. From what I understand, the orientation of the edges vary depending on the layout that is selected for creating a graph object. I want to create a [x,y] coordinate file and import into Autocad.

EDIT: From the answer explained below, I understand it is not straightforward to assign the edge weights as lengths. As an alternative, I want to obtain the coordinates of nodes from the image, compute the distance between nodes and assign the distance as edge weights (ignoring the weights provided above). With the set of coordinates, node-node connection and node-node distance I'd like to generate a 1D CAD digram programmatically.

EDIT2: Since the coordinates of the nodes cannot be directly obtained from the MATLAB output and the edge weights(in the original input) cannot be assigned as edge lengths, I'd like to try an alternate approach. For instance, if these are the coordinates of the nodes ((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25)), I'd like to compute the euclidean distance between the coordinates and assign the distances as edge weights. From what I understand, the dimension tab in AutoCAD computes the euclidean distance. However, I am not sure how to assign this output as edge weights.

Any suggestions on how to proceed will be really appreciated.

Ormazd answered 15/1, 2020 at 13:34 Comment(0)
C
7

Firstly, for your particular example it would not be possible to generate a graph for which the edge weights are the line lengths.

For example, if the distances between nodes 1, 2 and 3 are per your arrays:

  • 1 → 2 = 50
  • 1 → 3 = 10

Then the distance 2 → 3 must be between 40 & 60, else the triangle does not exist. Whereas your array specifies this distance as 90.

To demonstrate this visually, if you were to picture a line of length 50 spanning nodes 1 & 2, if you construct circles at either end of this line with radii equal to the distances between nodes 1 → 3 and 2 → 3, then such circles must intersect for the triangle to exist.

Currently, with the weights you have specified, there is no such intersection:

enter image description here


As such, assuming arbitrary positions for each of the nodes, with node coordinates supplied as an argument to the function, you could construct the desired graph using a function such as the following AutoLISP example:

(defun graph ( pts sls tls wgt )
    (   (lambda ( l )
            (foreach x l (text (cdr x) (itoa (car x)) 0.0 1))
            (mapcar
               '(lambda ( a b c / 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)
                        (itoa c)
                        (if (and (< (* pi 0.5) r) (<= r (* pi 1.5))) (+ r pi) r)
                        2
                    )
                )
                sls tls wgt
            )
        )
        (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)
        )
    )
)

When the above function is evaluated with the following arguments (where the first argument indicates the coordinates for the seven nodes):

(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)
   '(50 10 20 80 90 90 30 20 100 40 60)
)

It will produce the following result in AutoCAD:

enter image description here


If however, you want the weights to be determined by the 2D distance between each of the supplied node coordinates, could might want to consider the following AutoLISP function:

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

Supplied with a list of node coordinates and two lists of connected nodes:

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

This function will produce the following result:

enter image description here

Here, the accuracy of the weights will be determined by the value of the LUPREC system variable in AutoCAD (which was set to 4 in the above example). You can alternatively override this by supplying the precision argument to the rtos function in my code, e.g. for a precision of 3 decimal places, the expression would be:

(rtos (distance p q) 2 3)
Casework answered 17/1, 2020 at 19:32 Comment(9)
Thank you very much for the detailed illustration. Could you please have a look at the edit made in the original post?Ormazd
I have tweaked the code in my post to also label the nodes numbers and have updated the image. On reading your edited question, I don't think it will be possible to obtain the information you require from the matlab output.Casework
Thanks a lot for the response. In that case, ill supply the coordinates as inputs (I've managed to obtain the coordinates from image processing toolboxes). Could you please have a look at the edit in original post? I'd like to compute the Euclidean distances using the coordinates and assign these as edge weights.Ormazd
You're most welcome - following your edit, I have updated my answer above.Casework
I'd like to ask for suggestion on which format must be used to save the CAD file. I dave in DXF format, but when I import it into another software the geometry appears like a surface. I had expected only lines to appear after import. For instance, please check thisOrmazd
DXF is a standard format and would be the format that I would suggest you use. I could only assume that the software into which you are importing the file automatically interprets closed polygons as regions.Casework
Thanks for the response. I could convert the closed polygons to lines after import. I've a question, for the following test case (graph '((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25)) '(1 1 1 1 1 2 2 3 4 4 4 5 6) '(2 3 4 5 5 3 6 6 5 7 7 7 7) ) there are multiple edges between two nodes. In the resulting geometry, if there are two edges of same length between two nodes the lines overlap. I'd like to know if it is possible to add an offset to make both the edges visible ( this would change the length of one edge I suppose).Ormazd
I would like to ask for a suggestion. I would like to scale down all the distances between edges by 10. For instance, the distance between nodes 4 and 5 to 3.53 from 35.35 ( similarly for all the edges) . I am not sure if there is a straightforward way(a command to scale) to do this in AutoCAD. Any hints?Ormazd
Yes, the AutoCAD SCALE command exists, however, it would likely be easier to apply a scaling matrix transformation to the supplied coordinates before any objects are created. The only other element that you may wish to scale is the text height, given by '(40 . 2) in my code (which indicates a text height of 2 units).Casework

© 2022 - 2024 — McMap. All rights reserved.