В общем, для этой проблемы просто недостаточно ограничений: для произвольного заданного набора связанных узлов и весов может быть бесконечно много конфигураций, которые удовлетворяли бы входным данным, или вообще не было бы, в зависимости от весов (расстояний)
Например, если вы хотите уменьшить проблему до 2 соединенных узлов с заданным весом:
(graph '(1) '(2) '(10.0))
Исправление положения одного из узлов будет означать, что второй узел может быть расположен в одной из бесконечно многих точек на окружности радиуса 10.0
с центром в первом узле.
Предполагается, что вы выбрали произвольную позицию на этом круге для второй ноты, добавив третий связанный узел затем к первым двум относится решение вопроса о пересечении двух окружностей, радиусы которых равны весам между узлами (то есть, если они даже пересекаются).
Для каждого добавленного последующего узла вам нужно будет найти общее пересечение в наборе кругов с центром в каждом нет de, к которому подключен новый узел, радиусы которого равны весу между узлами.
Конечно, есть чит-решение:
(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)
)
)
)
Здесь строка:
(rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)
Округляет расстояние до ближайшего кратного 10
, а затем преобразует результат в строку с точностью до нуля после запятой. .
Если вы хотите продолжить использовать этот метод в целом, вы можете определить общую функцию округления, такую как следующая, которая будет округляться до любого предоставленного кратного:
(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
)
И Затем вы должны заменить:
(rtos (* 10.0 (atof (rtos (/ (distance p q) 10.0) 2 0))) 2 0)
на:
(roundto (distance p q) 10.0)
Где 10.0
представляет кратное округления.
Следуя вашему вопросу в комментариях, Вы можете использовать следующую функцию для округления до до следующего кратного (с точностью до 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
)
Например:
_$ (roundupto 12.4 12.4)
"12.4"
_$ (roundupto 12.41 12.4)
"24.8"
_$ (roundupto 29.15 12.4)
"37.2"