Задачки любителям 3Д
Для Z=0 действительно просто. Только немного не так как Вы написали.
У меня получается два подобных прямоугольных треугольника.
Один с гипотенузой "линией" и второй с гипотенузой "перемещения"
С первого находим угол, со второго две стороны: dx,dy
И затем просто перемещаем линию.
Теперь осталось Z добавить.
То, что я написал, легко обобщается и на 3Д:
до момента получения вектора N one doesn't use the explicit coordinates, nor the dimensionality
of the space (so it works in a space of an arbitrary dimension).
So N = (X1 - X2) / |X1 - X2| (vector form!)
Then one takes two arbitrary vectors Y'1 = (x'1, y'1, z'1) and Y2, such that the three vectors N, Y1, Y2 - are linearly independent
(this is almost always the case once one takes random vectors).
Then one starts Gram-Schmidt orthogonalization process taking N as the first vector. One obtains orthonormal vectos N, N1, N2.
Two-parametric surface:
X' (t, alpha) = (X1 - X2) t + X2 +
(a /2) * (N1* cos(alpha) + N2*sin(alpha)) - is a cylinder around your line, with the radius = a/2.
For the fixed parameter alpha - one obtains one of parallel lines, parametrized with t, which is parallel to the initial line, and has the distance = a/2 to it.
Нужен видимо еще какой то вектор указывающий направление, потому как можно целый цилиндр параллельных прямых сделать возле центральной.
Именно. Или соглашение, как расположить басис.
В примере я совмещаю ось х с направлющим вектором заданной линии.
using System.Numerics; float distance = (float)Math.Sqrt(2); Vector3 pnt1 = new Vector3(1, 0, 0); Vector3 pnt2 = new Vector3(4, 3, 0); Vector3 ray = pnt2 - pnt1; Matrix4x4 rotate1 = Matrix4x4.CreateRotationX(0.0f); // В результате поворачивает полученную линию вокруг заданной (опционально). Matrix4x4 rotate2 = getRotateMatrix(Vector3.UnitX, Vector3.Normalize(ray)); // Совмещает ось х с направляющим вектором линии Matrix4x4 rotate = Matrix4x4.Multiply(rotate1, rotate2); // Комбинация Vector3 axis = Vector3.Transform(Vector3.UnitY, rotate); // Получаем вектор, вдоль которого будем перемещать линию Matrix4x4 translate = Matrix4x4.CreateTranslation(distance * axis); // Собственно перемещение pnt1 = Vector3.Transform(pnt1, translate); pnt2 = Vector3.Transform(pnt2, translate); // Матрица поворота одного нормализованного вектора к другому. Стырено отсюда https://gist.github.com/kevinmoran/b45980723e53edeb8a5a43c49f134724 private static Matrix4x4 getRotateMatrix(Vector3 v1, Vector3 v2) { Vector3 axis = Vector3.Normalize(Vector3.Cross(v1, v2)); float dotProduct = Vector3.Dot(v1, v2); dotProduct = Math.Max( -1.0f, Math.Min(1.0f, dotProduct) ); float angleRadians = (float)Math.Acos(dotProduct); return Matrix4x4.CreateFromAxisAngle(axis, angleRadians); }
ну это хоть как то понятно, спасибо. Хотя оказалось, что и мой алгоритм с треугольниками работает в пространстве, за исключением двух случаев dx==0 && dz==0
и dx==0 && dy ==0 (исправил до получения картинки). Теперь уже на простом тесте работает.
Но появились новые вопросы.
- Какой еще тест(ы) можно сделать? Пока буду вершины немного передвигать на 0.01.
- Как рассчитать Епсилон? Ведь не будет работать не только с 0 но и так dx<Epsilon && dy <Epsilon
ну это хоть как то понятно
Странно. А что, #22 было не понятно?
Это как бы реализация аналитики akidervish.
Единственно что я не стал делать это
Then one takes two arbitrary vectors Y'1 = (x'1, y'1, z'1) and Y2, such that the three vectors N, Y1, Y2 - are linearly independent
(this is almost always the case once one takes random vectors).
Then one starts Gram-Schmidt orthogonalization process taking N as the first vector. One obtains orthonormal vectos N, N1, N2.
, так как у меня уже есть ортонормальная тройка - в начале координатной системы.
Как рассчитать Епсилон? Ведь не будет работать не только с 0 но и так dx<Epsilon && dy <Epsilon
https://docs.microsoft.com/en-us/dotnet/api/system.double....
На фига?
Смотрим на картинку кубика
для связей 1-2 и подобных нужны другие вектора перемещений. Связь 2-6 тоже несколько другая, через x, y не посчитать, нужно z еще
что ты там закодировал под dx
Просто абсолютная разница координат начала и конца базовой линии.
dx=Abs(x2-x1)
для связей 1-2 и подобных нужны другие вектора перемещений. Связь 2-6 тоже несколько другая
В обоих случаях две образующие цилиндрической поверхности (см. #22) отстоят друг от друга на 180°.
1-я образующая: Matrix4x4 rotate1 = Matrix4x4.CreateRotationX(0.0f); 2-я образующая: Matrix4x4 rotate1 = Matrix4x4.CreateRotationX((float)Math.PI);
Ты издеваешься?
Во всех случаях, для любых заданных линий:
1-я образующая: Matrix4x4 rotate1 = Matrix4x4.CreateRotationX(0.0f); 2-я образующая: Matrix4x4 rotate1 = Matrix4x4.CreateRotationX((float)Math.PI);
Где здесь ветвления и условия?
float distance = ...; List<Line> lines = new List<Line>{...}; foreach (Line l in lines) { Line _1stGenLine = getGenLine(l, distance, 0.0f); Line _2ndGenLine = getGenLine(l, distance, (float)Math.PI); drawLine(l); drawLine(_1stGenLine); drawLine(_2ndGenLine); } private static Line getGenLine(Line line, float distance, float angle) { Vector3 pnt1 = line.Point1; Vector3 pnt2 = line.Point2; Vector3 ray = pnt2 - pnt1; Matrix4x4 rotate1 = Matrix4x4.CreateRotationX(angle); Matrix4x4 rotate2 = getRotateMatrix(Vector3.UnitX, Vector3.Normalize(ray)); Matrix4x4 rotate = Matrix4x4.Multiply(rotate1, rotate2); Vector3 axis = Vector3.Transform(Vector3.UnitY, rotate); Matrix4x4 translate = Matrix4x4.CreateTranslation(distance * axis); pnt1 = Vector3.Transform(pnt1, translate); pnt2 = Vector3.Transform(pnt2, translate); return new Line { Point1 = pnt1, Point2 = pnt2 }; } private static Matrix4x4 getRotateMatrix(Vector3 v1, Vector3 v2) { Vector3 axis = Vector3.Normalize(Vector3.Cross(v1, v2)); float dotProduct = Vector3.Dot(v1, v2); dotProduct = Math.Max( -1.0f, Math.Min(1.0f, dotProduct) ); float angleRadians = (float)Math.Acos(dotProduct); return Matrix4x4.CreateFromAxisAngle(axis, angleRadians); } private class Line { public Vector3 Point1; public Vector3 Point2; }
ну нифига себе, у меня без условий и дополнительных матриц всего 3 строчки получается.
var tuple1 = Tools.RectangularTriangleSolutionAngle(dxOrig, dyOrig); double connectionAngleRadian = Tools.GradToRadian(90) - tuple1.Angle; tuple2 = Tools.RectangularTriangleSolutions(lineDistance, connectionAngleRadian);
Может на досуге проверю как работает. Что то меня сомнения берут.