Преобразование графика в двухмерную диаграмму - PullRequest
7 голосов
/ 15 января 2020

Я хочу создать 2D-диаграмму, как показано ниже:

enter image description here Приведенное выше изображение было создано с использованием Graph в 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)

Информация хранится в виде узлов, ребер, веса ребра a graph. Я хотел бы создать чертеж 2D САПР, используя эту информацию. Длина линий может быть указана с использованием веса ребер. Однако я не уверен, как углы могут быть получены из графика. Из того, что я понимаю, ориентация краев варьируется в зависимости от макета, выбранного для создания графического объекта. Я хочу создать файл координат [x, y] и импортировать его в Autocad.

РЕДАКТИРОВАТЬ: Исходя из ответа, объясненного ниже, я понимаю, что не просто назначить веса ребер длинами. В качестве альтернативы я хочу получить координаты узлов из изображения, вычислить расстояние между узлами и назначить расстояние в качестве веса ребер (игнорируя веса, указанные выше). С набором координат, соединением узла-узла и расстоянием между узлом я хотел бы программно создать 1D CAD-диаграмму.

EDIT2: Поскольку координаты узлов не могут быть напрямую получены из вывода MATLAB, а веса ребер (в исходном вводе) не могут быть назначены как длины ребер, я хотел бы попробовать альтернативный подход. Например, если это координаты узлов ((75 25) (115 45) (90 60) (10 5) (45 0) (45 55) (0 25)), я бы хотел вычислить евклидово расстояние между координатами и назначить расстояния как веса ребер. Насколько я понимаю, вкладка dimension в AutoCAD вычисляет евклидово расстояние. Однако я не уверен, как назначить этот вывод в качестве граничных весов.

Любые предложения о том, как поступить, будут по-настоящему оценены.

1 Ответ

7 голосов
/ 17 января 2020

Во-первых, для вашего конкретного примера было бы невозможно создать график, для которого веса ребер являются длинами линий.

Например, если расстояния между узлами 1, 2 и 3 для ваших массивов:

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

Тогда расстояние 2 → 3 должно быть между 40 & 60, иначе треугольника не существует. Принимая во внимание, что ваш массив определяет это расстояние как 90.

Чтобы продемонстрировать это визуально, если бы вы изобразили линию длиной 50 охватывающих узлов 1 & 2, если вы строите круги в конец этой линии с радиусами, равными расстояниям между узлами 1 → 3 и 2 → 3, тогда такие круги должны пересекаться для существования треугольника.

В настоящее время с указанными вами весами таких нет пересечение:

enter image description here


Таким образом, предполагая произвольные позиции для каждого из узлов с координатами узла, предоставленными в качестве аргумента функции, вы мог бы построить желаемый граф, используя функцию, такую ​​как следующий пример AutoLISP:

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

Когда вышеупомянутая функция оценивается следующими аргументами (где первый аргумент указывает координаты для семи узлов):

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

В AutoCAD будет получен следующий результат:

enter image description here


Если однако r, вы хотите, чтобы веса определялись по двухмерному расстоянию между каждой из предоставленных координат узла, может потребоваться рассмотреть следующую функцию AutoLISP:

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

Поставляется со списком координат узла и двумя списками подключенных узлов:

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

Эта функция даст следующий результат:

enter image description here

Здесь точность весов будет быть определено значением системной переменной LUPREC в AutoCAD (которая была установлена ​​на 4 в приведенном выше примере). В качестве альтернативы вы можете переопределить это, предоставив аргумент точности для функции rtos в моем коде, например, для точности 3 десятичных знаков выражение будет:

(rtos (distance p q) 2 3)
...