Рассчитать среднюю точку кривой Безье
У меня есть функция рисовать Bezier Curve
через три пункта. У меня уже есть 2 точки (начало и конец) - A и B. Как рассчитать среднюю точку между этими двумя точками, так как средняя точка всегда будет немного выше или ниже линейной функции этих двух точек.
Пример:
Любые формулы, идеи будут великолепны!
3 ответа
Я думаю, это то, что вы ищете:
http://blog.sklambert.com/finding-the-control-points-of-a-bezier-curve/
Здесь подробно рассматриваются расчеты различных точек на кривой Безье.
Вы также можете быть заинтересованы в этом более конкретном примере для вашего приложения:
http://www.codeproject.com/Articles/223159/Midpoint-Algorithm-Divide-and-Conquer-Method-for-D
Если вы действительно хотите войти в это, то я предлагаю этот учебник для начинающих:
http://pomax.github.io/bezierinfo/
Кривые Безье немного сложнее, чем простые дуги. Для дуги, вы можете просто использовать эту формулу:
R = H/2 + W^2/8H
... что определенно не будет работать для кривой Безье. Например, на квадратичной кривой Безье для расчета точки необходимо использовать:
Источники: http://en.wikipedia.org/wiki/B%C3%A9zier_curve, Квадратичная кривая Безье: Расчет точки
Ниже приведено то, что я использую, чтобы получить контрольную точку кривой Безье. Это должно работать для вашей проблемы, когда контрольная точка находится на кривой. Это в Swift, но вы должны быть в состоянии легко конвертировать его на другой язык. По сути, в средней точке линии (точки которой - точка1 и точка2) я вырабатываю перпендикулярную линию заданной длины. Параметр по часовой стрелке определяет, на какую сторону линии должна падать точка.
func getControlPointWithPoint1(point1:CGPoint, point2:CGPoint, length:CGFloat, clockwise:Bool) -> CGPoint {
let angle = getAngleWithPoint1(point1, point2:point2)
let direction = clockwise ? 1 : -1
let perpendicularAngle = angle + (CGFloat(direction) * CGFloat((M_PI / 2)))
let midPoint = getMidPointWithPoint1(point1, point2:point2)
return CGPointMake(midPoint.x + (cos(perpendicularAngle) * length), midPoint.y + (sin(perpendicularAngle) * length))
}
func getAngleWithPoint1(point1:CGPoint, point2:CGPoint) -> CGFloat {
return atan2((point2.y - point1.y), (point2.x - point1.x))
}
func getMidPointWithPoint1(point1:CGPoint, point2:CGPoint) -> CGPoint {
return CGPointMake((point1.x + point2.x) / 2, (point1.y + point2.y) / 2)
}
Ниже показано, как это будет отображаться на диаграмме вашего письма:
c = getControlPointWithPoint1(a, point2:b, length:h, clockwise:true)
После ответа Марка, вот фрагмент в C#
public static Path DrawBezeireUsingTwoPoints(Point startPoint, Point endPoint)
{
Path path = new Path();
PathFigure pathFigure = new PathFigure();
// Set up the Path to insert the segments
PathGeometry pathGeometry = new PathGeometry();
BezierSegment bezeireSeg;
// Draw an ellipse passing by the 2 points and let the path cross it
Point beziereMidPoint = CalculateBezierePoint(startPoint, endPoint, true);
bezeireSeg = new BezierSegment(startPoint, beziereMidPoint, endPoint, true);
pathFigure.StartPoint = startPoint;
pathFigure.IsClosed = false;
pathFigure.Segments.Add(bezeireSeg);
pathGeometry.Figures.Add(pathFigure);
path.Data = pathGeometry;
path.Stroke = Brushes.Brown;
path.StrokeThickness = 2;
return path;
}
Буду рад, если вам поможет.
Это мое решение.
Vector2 posA = sphereA.transform.position;
Vector2 posB = sphereB.transform.position;
Gizmos.color = Color.blue;
Gizmos.DrawLine(posA, posB);
float distance = Vector2.Distance(posA, posB);
Vector2 direction = (posB - posA).normalized;
Vector2 v2 = end - start;
var angle = Mathf.Atan2(v2.y, v2.x) * Mathf.Rad2Deg;
var midStartPos = posA + direction * (distance / 2f);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midStartPos, 0.02f);
var height = 0.3f;
height = Mathf.Clamp(height, 0f, Vector2.Distance(posA, posB) * 0.5f);
angle = 90f + angle;
var goalDirection = new Vector2(Mathf.Cos(angle * Mathf.Deg2Rad), Mathf.Sin(angle * Mathf.Deg2Rad));
if (goalDirection.y < 0f)
{
goalDirection.x = -goalDirection.x;
goalDirection.y = Mathf.Abs(goalDirection.y);
}
var midEndPos = midStartPos + goalDirection * height;
Gizmos.color = Color.blue;
Gizmos.DrawLine(midStartPos, midEndPos);
Gizmos.color = Color.red;
Gizmos.DrawSphere(midEndPos, 0.02f);